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

equalizedigital / accessibility-checker / 21415005664

27 Jan 2026 09:32PM UTC coverage: 57.922%. First build
21415005664

Pull #1345

github

web-flow
Merge 01aef6288 into 0a04f4ab2
Pull Request #1345: Release v1.37.0

15 of 22 new or added lines in 4 files covered. (68.18%)

4226 of 7296 relevant lines covered (57.92%)

3.49 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

13
/**
14
 * Class Frontend_Highlight
15
 *
16
 * A class that handles AJAX requests for frontend highlighting of accessibility issues.
17
 */
18
class Frontend_Highlight {
19

20
        /**
21
         * Constructor function for the class.
22
         */
23
        public function __construct() {
24
        }
×
25

26
        /**
27
         * Initialize hooks.
28
         *
29
         * @return void
30
         */
31
        public function init_hooks() {
32
                add_action( 'wp_ajax_edac_frontend_highlight_ajax', [ $this, 'ajax' ] );
×
33

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

52
        /**
53
         * Retrieves accessibility issues for a specific post.
54
         *
55
         * @param int $post_id The ID of the post.
56
         *
57
         * @return array|null The array of issues or null if no issues found.
58
         */
59
        public function get_issues( $post_id ) {
60
                global $wpdb;
×
61
                $table_name = $wpdb->prefix . 'accessibility_checker';
×
62
                $post_id    = (int) $post_id;
×
63
                $siteid     = get_current_blog_id();
×
NEW
64
                $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.
×
65
                if ( ! $results ) {
×
66
                        return null;
×
67
                }
68

69
                return Helpers::filter_results_to_only_active_rules( $results );
×
70
        }
71

72
        /**
73
         * AJAX handler function for frontend highlighting requests.
74
         */
75
        public function ajax() {
76

77
                if ( ! check_ajax_referer( 'frontend-highlighter', 'nonce', false ) ) {
×
78
                        wp_send_json_error( new \WP_Error( '-1', __( 'Permission Denied', 'accessibility-checker' ) ) );
×
79
                }
80

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

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

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

108
                $results = $this->get_issues( $post_id );
×
109

110
                if ( ! $results ) {
×
111
                        wp_send_json_error( new \WP_Error( '-3', __( 'Issue query returned no results', 'accessibility-checker' ) ) );
×
112
                }
113

114
                $rules = edac_register_rules();
×
115

116
                $issues = [];
×
117
                $fixes  = [];
×
118
                foreach ( $results as $result ) {
×
119
                        $array = [];
×
120
                        $rule  = edac_filter_by_value( $rules, 'slug', $result['rule'] );
×
121

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

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

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

143
                        $issues[] = $array;
×
144

145
                        if ( ! isset( $fixes[ $rule[0]['slug'] ] ) ) {
×
146
                                $fixes_for_rule = $rule[0]['fixes'] ?? [];
×
147

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

157
                if ( ! $issues ) {
×
158
                        wp_send_json_error( new \WP_Error( '-5', __( 'Object query returned no results', 'accessibility-checker' ) ) );
×
159
                }
160

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

204
                wp_send_json_success(
×
205
                        wp_json_encode(
×
206
                                [
×
207
                                        'issues' => $issues,
×
208
                                        'fixes'  => $fixes,
×
209
                                ]
×
210
                        )
×
211
                );
×
212
        }
213
}
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