array( 'post', 'page' ), 'post_status' => 'publish', 'posts_per_page' => (int) $limit, 'orderby' => 'modified', 'order' => 'DESC', ) ); $findings = array(); foreach ( $posts as $p ) { $findings[] = $this->analyse_post( $p ); } return $findings; } /** * Analyse a single post's content for accessibility issues. */ public function analyse_post( $post ) { $content = $post->post_content; $issues = array(); // Missing alt $img_count = preg_match_all( '/]*\salt=)/i', $content ); if ( $missing_alt > 0 ) { $issues[] = array( 'severity' => 'critical', 'rule' => 'WCAG 1.1.1', 'count' => (int) $missing_alt, 'label' => sprintf( __( '%d image(s) missing alt text', 'sitefix' ), $missing_alt ), ); } // No H1 if ( $img_count > 0 && ! preg_match( '/ 'warning', 'rule' => 'WCAG 1.3.1', 'count' => 1, 'label' => __( 'Post missing H1 heading', 'sitefix' ), ); } // Heading skip detection if ( preg_match_all( '/ 0 && $l > $prev + 1 ) { $issues[] = array( 'severity' => 'warning', 'rule' => 'WCAG 1.3.1', 'count' => 1, 'label' => sprintf( __( 'Heading skip: H%d → H%d', 'sitefix' ), $prev, $l ), ); break; } $prev = $l; } } // Tables without TH if ( preg_match_all( '/ 0 && ! preg_match( '/ 'warning', 'rule' => 'WCAG 1.3.1', 'count' => 1, 'label' => __( 'Table without header cells (TH)', 'sitefix' ), ); } // "Click here" / "Read more" link text if ( preg_match_all( '/]*>(?:click here|read more|here|more)<\/a>/i', $content ) > 0 ) { $issues[] = array( 'severity' => 'notice', 'rule' => 'WCAG 2.4.4', 'count' => 1, 'label' => __( 'Generic link text ("click here", "read more")', 'sitefix' ), ); } $score = $this->score_post( $issues, $img_count ); return array( 'id' => $post->ID, 'url' => get_permalink( $post ), 'title' => get_the_title( $post ), 'images' => $img_count, 'issues' => $issues, 'score' => $score, ); } private function score_post( $issues, $img_count ) { $base = 100; foreach ( $issues as $i ) { switch ( $i['severity'] ) { case 'critical': $base -= 15 * min( 3, $i['count'] ); break; case 'warning': $base -= 5 * min( 5, $i['count'] ); break; case 'notice': $base -= 2; break; } } return max( 30, $base ); } /** * Aggregate score across pages. */ public function calculate_score( $findings ) { if ( empty( $findings ) ) return 100; $sum = 0; foreach ( $findings as $f ) $sum += (int) ( $f['score'] ?? 0 ); return (int) round( $sum / count( $findings ) ); } }