' . esc_html__( 'Missing', 'ariaccess' ) . ''; } else { echo esc_html( mb_strlen( $alt ) > 60 ? mb_substr( $alt, 0, 59 ) . '…' : $alt ); } } /** * Image MIME types query value. * * @return string */ private static function image_mimes() { return 'image'; } /** * Count images without alt text. * * @return int */ public static function missing_count() { $q = new WP_Query( self::missing_args( array( 'posts_per_page' => 1, 'fields' => 'ids' ) ) ); return (int) $q->found_posts; } /** * Query args for images missing alt text. * * @param array $extra Extra args. * @return array */ public static function missing_args( $extra = array() ) { return array_merge( array( 'post_type' => 'attachment', 'post_status' => 'inherit', 'post_mime_type' => self::image_mimes(), 'meta_query' => self::missing_meta_query(), // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query 'orderby' => 'date', 'order' => 'DESC', ), $extra ); } /** * Meta query for "no alt text". * * @return array */ private static function missing_meta_query() { return array( 'relation' => 'OR', array( 'key' => '_wp_attachment_image_alt', 'compare' => 'NOT EXISTS', ), array( 'key' => '_wp_attachment_image_alt', 'value' => '', ), ); } /** * "Missing alt text" view link in the Media Library list. * * @param array $views Views. * @return array */ public static function views( $views ) { $count = self::missing_count(); $url = add_query_arg( array( 'mode' => 'list', 'ariaccess_alt' => 'missing', ), admin_url( 'upload.php' ) ); $current = isset( $_GET['ariaccess_alt'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended /* translators: %s: number of images. */ $views['ariaccess_alt'] = sprintf( '%s', esc_url( $url ), $current ? ' class="current" aria-current="page"' : '', sprintf( esc_html__( 'Missing alt text %s', 'ariaccess' ), '(' . number_format_i18n( $count ) . ')' ) ); return $views; } /** * Apply the filter in the Media Library list. * * @param WP_Query $q Query. */ public static function filter_query( $q ) { if ( ! $q->is_main_query() || ! isset( $_GET['ariaccess_alt'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended return; } global $pagenow; if ( 'upload.php' !== $pagenow ) { return; } $q->set( 'post_mime_type', self::image_mimes() ); $q->set( 'meta_query', self::missing_meta_query() ); // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query } /** * Save alt text for several images. * * @param array $alts id => alt text. * @return int Number saved. */ public static function save_alts( $alts ) { $saved = 0; foreach ( (array) $alts as $id => $alt ) { $id = (int) $id; $alt = sanitize_text_field( (string) $alt ); if ( ! $id || '' === $alt || ! wp_attachment_is_image( $id ) || ! current_user_can( 'edit_post', $id ) ) { continue; } update_post_meta( $id, '_wp_attachment_image_alt', $alt ); $saved++; } return $saved; } }