settings = AccessIQ_Settings::instance(); add_action( 'wp_head', [ $this, 'inject_fixes' ], 1 ); // Skip link must be the first focusable element: wp_body_open (WP 5.2+), footer as fallback. add_action( 'wp_body_open', [ $this, 'inject_skip_link' ], 1 ); add_action( 'wp_footer', [ $this, 'inject_skip_link_fallback' ], 1 ); add_action( 'wp_footer', [ $this, 'inject_skip_target' ], 2 ); add_filter( 'language_attributes', [ $this, 'fix_lang_attribute' ] ); add_filter( 'the_content', [ $this, 'fix_decorative_images' ] ); } /* ── 1. Skip Link ──────────────────────────────────────────── */ /** * Output skip-to-content link as first element in footer (priority 1). * Visually hidden until focused via CSS; accessible via keyboard tab. */ public function inject_skip_link() { if ( ! $this->is_enabled( 'skip_link' ) || $this->skip_link_done ) { return; } $this->skip_link_done = true; echo '' . esc_html__( 'Skip to content', 'accessiq' ) . ''; } /** * Themes without wp_body_open(): print in footer so the link still exists. */ public function inject_skip_link_fallback() { $this->inject_skip_link(); } /** * Ensure #content exists. If the theme has no element with that id, point the link at *
/[role=main] (giving it id=content) instead of leaving a dead anchor. */ public function inject_skip_target() { if ( ! $this->is_enabled( 'skip_link' ) ) { return; } wp_print_inline_script_tag( "(function(){var l=document.getElementById('accessiq-skip-link');if(!l||document.getElementById('content')){return;}" . "var m=document.querySelector('main,[role=\"main\"],#primary,#main');if(!m){return;}" . "if(!m.id){m.id='content';}l.setAttribute('href','#'+m.id);" . "if(!m.hasAttribute('tabindex')){m.setAttribute('tabindex','-1');}})();" ); } /* ── 2 & 5. CSS injection ──────────────────────────────────── */ /** * Inject CSS fixes via wp_add_inline_style (WP.org compliant, no raw