2 * MB_IN_BYTES ) { return $html; } foreach ( headers_list() as $header ) { if ( 0 === stripos( $header, 'content-type:' ) && false === stripos( $header, 'html' ) ) { return $html; } } if ( false === stripos( $html, ' get_bloginfo( 'language' ), 'document_title' => static function () use ( $title ) { return '' !== $title ? $title : wp_get_document_title(); }, 'attachment_alt' => array( __CLASS__, 'attachment_alts' ), 'post_title' => array( __CLASS__, 'post_title_for_url' ), 'home_url' => static function () { return home_url( '/' ); }, 'site_name' => static function () { // Stored HTML-escaped; the HTML API escapes attribute values itself. return wp_specialchars_decode( get_bloginfo( 'name' ), ENT_QUOTES ); }, ); } /** * Alt text of attachments, false for images marked decorative. * * @param int[] $ids Attachment ids. * @return array */ public static function attachment_alts( array $ids ) { $ids = array_slice( array_filter( array_map( 'absint', $ids ) ), 0, 200 ); if ( ! $ids ) { return array(); } update_meta_cache( 'post', $ids ); $alts = array(); foreach ( $ids as $id ) { if ( get_post_meta( $id, '_fixlight_decorative', true ) ) { $alts[ $id ] = false; continue; } $alt = get_post_meta( $id, '_wp_attachment_image_alt', true ); if ( is_string( $alt ) && '' !== trim( $alt ) ) { $alts[ $id ] = $alt; } } return $alts; } /** * Title of the post a URL points to, '' when it is not a post. * * @param string $url Link URL. * @return string */ public static function post_title_for_url( $url ) { static $cache = array(); if ( isset( $cache[ $url ] ) ) { return $cache[ $url ]; } $post_id = 0; if ( preg_match( '/#more-(\d+)$/', $url, $matches ) ) { $post_id = (int) $matches[1]; } else { $host = wp_parse_url( $url, PHP_URL_HOST ); if ( ! $host || wp_parse_url( home_url(), PHP_URL_HOST ) === $host ) { $post_id = url_to_postid( $url ); } } $title = ''; if ( $post_id && 'publish' === get_post_status( $post_id ) ) { $title = trim( wp_strip_all_tags( html_entity_decode( get_the_title( $post_id ), ENT_QUOTES, get_bloginfo( 'charset' ) ) ) ); } $cache[ $url ] = $title; return $title; } /** * Fix stylesheet, and the scanner scripts on scan requests. */ public static function enqueue() { if ( self::is_scan_request() && ! empty( $_GET['fixlight_frame'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Token checked in is_scan_request(). wp_enqueue_script( 'fixlight-axe', FIXLIGHT_URL . 'assets/vendor/axe-core/axe.min.js', array(), '4.14.0', true ); wp_enqueue_script( 'fixlight-scan-runner', FIXLIGHT_URL . 'assets/js/scan-runner.js', array( 'fixlight-axe' ), Plugin::asset_version( 'assets/js/scan-runner.js' ), true ); wp_localize_script( 'fixlight-scan-runner', 'fixlightScan', array( 'id' => isset( $_GET['fixlight_id'] ) ? sanitize_key( wp_unslash( $_GET['fixlight_id'] ) ) : '', // phpcs:ignore WordPress.Security.NonceVerification.Recommended 'adminOrigin' => self::origin( admin_url() ), 'sendHtml' => self::fixes_off(), ) ); } if ( self::excluded() || self::fixes_off() ) { return; } $css = self::css( Settings::fixes() ); if ( '' === $css ) { return; } wp_register_style( 'fixlight-fixes', false, array(), FIXLIGHT_VERSION ); wp_enqueue_style( 'fixlight-fixes' ); wp_add_inline_style( 'fixlight-fixes', $css ); } /** * CSS for the enabled fixes. * * @param array $fixes Fix id => bool. * @return string */ public static function css( array $fixes ) { $css = ''; if ( ! empty( $fixes['skip_link'] ) ) { // Above sticky headers (Divi's top bar uses 100000). $css .= '.fixlight-skip-link{position:absolute;left:-10000px;top:auto;width:1px;height:1px;overflow:hidden;z-index:2147483647}' . '.fixlight-skip-link:focus{left:8px;top:8px;width:auto;height:auto;overflow:visible;padding:12px 18px;background:#fff;color:#1d2327;border:2px solid #1d2327;border-radius:4px;font:600 16px/1.2 system-ui,-apple-system,"Segoe UI",sans-serif;text-decoration:underline}'; } if ( ! empty( $fixes['focus_visible'] ) ) { // Dark outline with a light inner ring: visible on light and dark backgrounds. // Only the outline is forced (themes often remove it); a theme's own box-shadow wins over the ring. $css .= ':where(a,button,input,select,textarea,summary,[tabindex],[contenteditable],[role=button]):focus-visible{outline:3px solid #1d2327!important;outline-offset:2px!important;box-shadow:0 0 0 2px #fff}'; } if ( ! empty( $fixes['underline_links'] ) ) { $css .= ':where(p,li,dd,td,blockquote,figcaption) a:where(:not([class*=button]):not([role=button]):not(.wp-element-button)){text-decoration:underline!important;text-underline-offset:.15em}'; } if ( ! empty( $fixes['icon_labels'] ) || ! empty( $fixes['theme_compat'] ) ) { // Label text added inside links and buttons: read by screen readers, not shown. $css .= '.fixlight-sr{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}'; } if ( ! empty( $fixes['theme_compat'] ) ) { $css .= Compat::css(); } if ( ! empty( $fixes['reduced_motion'] ) ) { $css .= '@media (prefers-reduced-motion:reduce){*,*::before,*::after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}'; } return $css; } /** * Hides the admin bar on scan requests so it is not part of the results. * * @param bool $show Whether to show the admin bar. * @return bool */ public static function admin_bar( $show ) { return self::is_scan_request() ? false : $show; } /** * Scheme, host and port of a URL. * * @param string $url URL. * @return string */ public static function origin( $url ) { $parts = wp_parse_url( $url ); if ( empty( $parts['host'] ) ) { return ''; } return ( isset( $parts['scheme'] ) ? $parts['scheme'] : 'https' ) . '://' . $parts['host'] . ( isset( $parts['port'] ) ? ':' . $parts['port'] : '' ); } }