@@ -300,6 +300,145 @@ public static function maybe_enqueue_email_opt_in_script() {
300300 }
301301
302302
303+ /**
304+ * Enqueue the screen reader only format script and styles for the block editor.
305+ *
306+ * Loads on post edit screens for scannable post types, and also on the
307+ * Full Site Editor (site-editor.php) where there is no post type context.
308+ *
309+ * @return void
310+ */
311+ public static function maybe_enqueue_sr_only_format (): void {
312+ if ( ! self ::should_load_sr_only_format () ) {
313+ return ;
314+ }
315+
316+ global $ pagenow ;
317+ $ is_fse = 'site-editor.php ' === $ pagenow ;
318+
319+ wp_enqueue_script (
320+ 'edac-sr-only-format ' ,
321+ plugin_dir_url ( EDAC_PLUGIN_FILE ) . 'build/srOnlyFormat.bundle.js ' ,
322+ [ 'wp-rich-text ' , 'wp-block-editor ' , 'wp-element ' , 'wp-i18n ' , 'wp-plugins ' , 'wp-editor ' , 'wp-api-fetch ' ],
323+ EDAC_VERSION ,
324+ false
325+ );
326+
327+ wp_set_script_translations ( 'edac-sr-only-format ' , 'accessibility-checker ' , plugin_dir_path ( EDAC_PLUGIN_FILE ) . 'languages ' );
328+
329+ wp_localize_script (
330+ 'edac-sr-only-format ' ,
331+ 'edacSrOnlyFormat ' ,
332+ [
333+ 'showSrTextInEditor ' => (bool ) get_user_meta ( get_current_user_id (), 'show_sr_text_in_editor ' , true ),
334+ 'isFSE ' => $ is_fse ,
335+ ]
336+ );
337+ }
338+
339+ /**
340+ * Inject screen reader only format styles into the block editor iframe.
341+ *
342+ * @param array $editor_settings Default editor settings.
343+ * @return array
344+ */
345+ public static function maybe_inject_sr_only_editor_styles ( array $ editor_settings ): array {
346+ if ( ! self ::should_load_sr_only_format () ) {
347+ return $ editor_settings ;
348+ }
349+
350+ $ css = self ::get_sr_only_editor_styles ();
351+ if ( '' === $ css ) {
352+ return $ editor_settings ;
353+ }
354+
355+ if ( ! isset ( $ editor_settings ['styles ' ] ) || ! is_array ( $ editor_settings ['styles ' ] ) ) {
356+ $ editor_settings ['styles ' ] = [];
357+ }
358+
359+ if ( get_user_meta ( get_current_user_id (), 'show_sr_text_in_editor ' , true ) ) {
360+ $ body_classes = trim ( (string ) ( $ editor_settings ['bodyClassName ' ] ?? '' ) );
361+ if ( false === strpos ( " {$ body_classes } " , ' sr-only-show-always ' ) ) {
362+ $ editor_settings ['bodyClassName ' ] = trim ( $ body_classes . ' sr-only-show-always ' );
363+ }
364+ }
365+
366+ $ editor_settings ['styles ' ][] = [
367+ 'css ' => $ css ,
368+ ];
369+
370+ return $ editor_settings ;
371+ }
372+
373+ /**
374+ * Determine whether the screen reader only format assets should load.
375+ *
376+ * Returns true for the post editor on scannable post types, and also
377+ * for the Full Site Editor where there is no post type context.
378+ *
379+ * @return bool
380+ */
381+ private static function should_load_sr_only_format (): bool {
382+ global $ pagenow ;
383+
384+ $ is_post_editor = 'post.php ' === $ pagenow || 'post-new.php ' === $ pagenow ;
385+ $ is_fse = 'site-editor.php ' === $ pagenow ;
386+
387+ if ( ! $ is_post_editor && ! $ is_fse ) {
388+ return false ;
389+ }
390+
391+ if ( ! Helpers::is_block_editor () ) {
392+ return false ;
393+ }
394+
395+ // The FSE has no post type context, so always load there.
396+ if ( $ is_fse ) {
397+ return true ;
398+ }
399+
400+ $ post_types = Settings::get_scannable_post_types ();
401+
402+ return Helpers::is_current_post_type_scannable ( $ post_types );
403+ }
404+
405+ /**
406+ * Build the CSS that should be injected into the block editor iframe.
407+ *
408+ * @return string
409+ */
410+ private static function get_sr_only_editor_styles (): string {
411+ static $ cached_css = null ;
412+
413+ if ( null !== $ cached_css ) {
414+ return $ cached_css ;
415+ }
416+
417+ $ css_file = plugin_dir_path ( EDAC_PLUGIN_FILE ) . 'build/css/srOnlyFormat.css ' ;
418+ if ( ! file_exists ( $ css_file ) || ! is_readable ( $ css_file ) ) {
419+ $ cached_css = '' ;
420+ return $ cached_css ;
421+ }
422+
423+ $ css = file_get_contents ( $ css_file ); // phpcs:ignore WordPressVIPMinimum.Performance.FetchingRemoteData.FileGetContentsUnknown -- Reads a local built CSS asset from the plugin directory.
424+ if ( false === $ css ) {
425+ $ cached_css = '' ;
426+ return $ cached_css ;
427+ }
428+
429+ $ css .= sprintf (
430+ '
431+ .is-selected .text-format-sr-only:hover:after,
432+ .is-selected .text-format-sr-only:focus:after {
433+ content: %s;
434+ } ' ,
435+ wp_json_encode ( __ ( '* Screen Reader Text ' , 'accessibility-checker ' ) )
436+ );
437+
438+ $ cached_css = $ css ;
439+ return $ cached_css ;
440+ }
441+
303442 /**
304443 * Gets the current admin page slug.
305444 *
0 commit comments