• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

equalizedigital / accessibility-checker / 22024231170

14 Feb 2026 09:04PM UTC coverage: 57.263%. First build
22024231170

Pull #1413

github

web-flow
Merge c07f857fb into 1cbcfbf9b
Pull Request #1413: Fix loopback helper warning on DNS AAAA failures

27 of 81 new or added lines in 24 files covered. (33.33%)

4147 of 7242 relevant lines covered (57.26%)

3.47 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/admin/class-frontend-highlight.php
1
<?php
2
/**
3
 * Accessibility Checker plugin file.
4
 *
5
 * @package Accessibility_Checker
6
 */
7

8
namespace EDAC\Admin;
9

10
use EqualizeDigital\AccessibilityChecker\Admin\AdminPage\FixesPage;
11
use EqualizeDigital\AccessibilityChecker\Fixes\FixesManager;
12

NEW
13
if ( ! defined( 'ABSPATH' ) ) {
×
NEW
14
        exit;
×
15
}
16

17
/**
18
 * Class Frontend_Highlight
19
 *
20
 * A class that handles AJAX requests for frontend highlighting of accessibility issues.
21
 */
22
class Frontend_Highlight {
23

24
        /**
25
         * Constructor function for the class.
26
         */
27
        public function __construct() {
28
        }
×
29

30
        /**
31
         * Initialize hooks.
32
         *
33
         * @return void
34
         */
35
        public function init_hooks() {
36
                add_action( 'wp_ajax_edac_frontend_highlight_ajax', [ $this, 'ajax' ] );
×
37

38
                /**
39
                 * Filter the visibility of the frontend highlighter.
40
                 *
41
                 * 'edac_filter_frontend_highlighter_visibility' is a filter that can be used
42
                 * to allow users without edit permissions on the post to see the frontend
43
                 * highlighter. You can use the filter to perform additional permission checks
44
                 * on who can see it.
45
                 *
46
                 * @since 1.14.0
47
                 *
48
                 * @param bool $visibility The visibility of the frontend highlighter. Default is false, return true to show the frontend highlighter.
49
                 */
50
                if ( apply_filters( 'edac_filter_frontend_highlighter_visibility', false ) ) {
×
51
                        // A nopriv endpoint allows logged-out users to access the endpoint.
52
                        add_action( 'wp_ajax_nopriv_edac_frontend_highlight_ajax', [ $this, 'ajax' ] );
×
53
                }
54
        }
55

56
        /**
57
         * Retrieves accessibility issues for a specific post.
58
         *
59
         * @param int $post_id The ID of the post.
60
         *
61
         * @return array|null The array of issues or null if no issues found.
62
         */
63
        public function get_issues( $post_id ) {
64
                global $wpdb;
×
65
                $table_name = $wpdb->prefix . 'accessibility_checker';
×
66
                $post_id    = (int) $post_id;
×
67
                $siteid     = get_current_blog_id();
×
68
                $results    = $wpdb->get_results( $wpdb->prepare( 'SELECT id, rule, ignre, object, ruletype, selector, ancestry, xpath FROM %i where postid = %d and siteid = %d', $table_name, $post_id, $siteid ), ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- Safe variable used for table name.
×
69
                if ( ! $results ) {
×
70
                        return null;
×
71
                }
72

73
                return Helpers::filter_results_to_only_active_rules( $results );
×
74
        }
75

76
        /**
77
         * AJAX handler function for frontend highlighting requests.
78
         */
79
        public function ajax() {
80

81
                if ( ! check_ajax_referer( 'frontend-highlighter', 'nonce', false ) ) {
×
82
                        wp_send_json_error( new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) ) );
×
83
                }
84

85
                if ( ! isset( $_REQUEST['post_id'] ) ) {
×
86
                        $error = new \WP_Error( '-2', __( 'The id value was not set', 'accessibility-checker' ) );
×
87
                        wp_send_json_error( $error );
×
88
                }
89

90
                $post_id = isset( $_REQUEST['post_id'] ) ? (int) $_REQUEST['post_id'] : 0;
×
91
                $post    = get_post( $post_id );
×
92
                if ( ! $post ) {
×
93
                        wp_send_json_error( new \WP_Error( '-4', __( 'Post not found', 'accessibility-checker' ) ) );
×
94
                }
95

96
                // Check if the user has permission to view this post.
97
                if ( is_user_logged_in() ) {
×
98
                        // For authenticated users, use read_post capability.
99
                        if ( ! current_user_can( 'read_post', $post_id ) ) {
×
100
                                wp_send_json_error( new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) ) );
×
101
                        }
102
                } elseif ( apply_filters( 'edac_filter_frontend_highlighter_visibility', false ) ) {
×
103
                        // For unauthenticated users, only allow access to publicly viewable posts.
104
                        if ( ! is_post_publicly_viewable( $post ) ) {
×
105
                                wp_send_json_error( new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) ) );
×
106
                        }
107
                } else {
108
                        // Shouldn't ever reach this point but error just in case.
109
                        wp_send_json_error( new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) ) );
×
110
                }
111

112
                $results = $this->get_issues( $post_id );
×
113

114
                if ( ! $results ) {
×
115
                        wp_send_json_error( new \WP_Error( '-3', __( 'Issue query returned no results', 'accessibility-checker' ) ) );
×
116
                }
117

118
                $rules = edac_register_rules();
×
119

120
                $issues = [];
×
121
                $fixes  = [];
×
122
                foreach ( $results as $result ) {
×
123
                        $array = [];
×
124
                        $rule  = edac_filter_by_value( $rules, 'slug', $result['rule'] );
×
125

126
                        // When rules are filtered out, they are not in the rules array and this can be empty. Skip when the rule
127
                        // is empty to avoid php warnings and passing null values to the frontend highlighter.
128
                        if ( ! $rule ) {
×
129
                                continue;
×
130
                        }
131

132
                        $rule_type = ( true === (bool) $result['ignre'] ) ? 'ignored' : $rule[0]['rule_type'];
×
133

134
                        $array['rule_type']  = $rule_type;
×
135
                        $array['slug']       = $rule[0]['slug'];
×
136
                        $array['rule_title'] = $rule[0]['title'];
×
137
                        $array['summary']    = $rule[0]['summary'];
×
138
                        $array['how_to_fix'] = wp_kses_post( $rule[0]['how_to_fix'] ?? '' );
×
139
                        $array['link']       = edac_link_wrapper( $rule[0]['info_url'], 'frontend-highlighter', $rule[0]['slug'], false );
×
140
                        $array['object']     = html_entity_decode( $result['object'], ENT_QUOTES | ENT_HTML5 );
×
141
                        $array['id']         = $result['id'];
×
142
                        $array['ignored']    = $result['ignre'];
×
143
                        $array['selector']   = $result['selector'] ?? '';
×
144
                        $array['ancestry']   = $result['ancestry'] ?? '';
×
145
                        $array['xpath']      = $result['xpath'] ?? '';
×
146

147
                        $issues[] = $array;
×
148

149
                        if ( ! isset( $fixes[ $rule[0]['slug'] ] ) ) {
×
150
                                $fixes_for_rule = $rule[0]['fixes'] ?? [];
×
151

152
                                foreach ( $fixes_for_rule as $fix_for_rule ) {
×
153
                                        $fix = FixesManager::get_instance()->get_fix( $fix_for_rule );
×
154
                                        if ( $fix && method_exists( $fix, 'get_fields_array' ) ) {
×
155
                                                $fixes[ $rule[0]['slug'] ] = isset( $fixes[ $rule[0]['slug'] ] ) ? array_merge( $fixes[ $rule[0]['slug'] ], $fix->get_fields_array() ) : $fix->get_fields_array();
×
156
                                        }
157
                                }
158
                        }
159
                }
160

161
                if ( ! $issues ) {
×
162
                        wp_send_json_error( new \WP_Error( '-5', __( 'Object query returned no results', 'accessibility-checker' ) ) );
×
163
                }
164

165
                // if we have fixes then create fields for each of the groups.
166
                if ( ! empty( $fixes ) ) {
×
167
                        foreach ( $fixes as $key => $fix ) {
×
168
                                // count the number of fields in the fix.
169
                                $fields_count      = count( $fix );
×
170
                                $itteration        = 0;
×
171
                                $fix_fields_markup = '';
×
172
                                foreach ( $fix as $index => $field ) {
×
173
                                        ++$itteration;
×
174
                                        $field_type = $field['type'] ?? 'checkbox';
×
175
                                        ob_start();
×
176
                                        if ( isset( $field['group_name'] ) ) {
×
177
                                                // if this is anything other than the first field in the group then close the fieldset.
178
                                                if ( 1 !== $itteration ) {
×
179
                                                        ?>
180
                                                        </fieldset>
×
181
                                                        <?php
×
182
                                                }
183
                                                ?>
184
                                                <fieldset>
×
185
                                                <legend><h3 class="title"><?php echo esc_html( $field['group_name'] ); ?></h3></legend>
×
186
                                                <?php
187
                                        }
188
                                        FixesPage::{$field_type}(
×
189
                                                array_merge(
×
190
                                                        [
×
191
                                                                'name'     => $index,
×
192
                                                                'location' => 'frontend-highlighter',
×
193
                                                        ],
×
194
                                                        $field
×
195
                                                )
×
196
                                        );
×
197
                                        if ( $fields_count === $itteration ) {
×
198
                                                ?>
199
                                                </fieldset>
×
200
                                                <?php
×
201
                                        }
202
                                        $fix_fields_markup .= ob_get_clean();
×
203
                                }
204
                                $fixes[ $key ]['fields'] = $fix_fields_markup . PHP_EOL . '</fieldset>';
×
205
                        }
206
                }
207

208
                wp_send_json_success(
×
209
                        wp_json_encode(
×
210
                                [
×
211
                                        'issues' => $issues,
×
212
                                        'fixes'  => $fixes,
×
213
                                ]
×
214
                        )
×
215
                );
×
216
        }
217
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc