'Astra','generatepress'=>'GeneratePress','kadence'=>'Kadence','blocksy'=>'Blocksy','oceanwp'=>'OceanWP','neve'=>'Neve','hello-elementor'=>'Hello Elementor']; public function __construct(){add_action('template_redirect',[$this,'attach'],90);} public static function supported(): bool {return wp_is_block_theme()||current_theme_supports('digiter-builder-regions')||isset(self::THEMES[get_template()]);} public static function region(string $area): string { if(!in_array($area,['header','footer'],true)){return '';} $source=ThemeBuilder::$active[$area]??0; if(!$source){return '';} return '<'.$area.' class="dbs-site-'.$area.'" data-dbs-theme-region="'.$area.'">'.ThemeBuilder::render($source,is_singular()?get_queried_object_id():0,$area).''; } /** Remove only the named renderer, keeping unrelated widgets and mobile portals. */ private function remove_renderers(string $hook,array $names): void { global $wp_filter; foreach(($wp_filter[$hook]->callbacks??[]) as $priority=>$callbacks){ foreach($callbacks as $entry){$callback=$entry['function'];$name=is_string($callback)?$callback:(is_array($callback)?(is_object($callback[0])?get_class($callback[0]):$callback[0]).'::'.$callback[1]:'');if(in_array($name,$names,true)){remove_action($hook,$callback,$priority);}} } } private function replace_action(string $hook,string $area,array $renderers): void { // Keep third-party callbacks (analytics, accessibility, widgets and portals). $this->remove_renderers($hook,$renderers); add_action($hook,static function()use($area){echo self::region($area);},10); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Region uses the Builder renderer which validates documents and escapes every module field; preserve forms, styles and script assets. } public function attach(): void { if(wp_is_block_theme()||!ThemeBuilder::$active){return;} $theme=get_template(); // Parent slug also supports child themes using parent hooks. foreach(['header','footer'] as $area){ if(empty(ThemeBuilder::$active[$area])){continue;} switch($theme){ case 'astra': if($area==='footer'){ $this->remove_renderers('astra_footer',['astra_footer_markup','Astra_Builder_Footer::footer_markup']); add_action('astra_footer',static function(){echo self::region('footer');},10); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Region uses the Builder renderer which validates documents and escapes every module field; preserve forms, styles and script assets. }else{$this->replace_action('astra_header','header',['astra_header_markup','Astra_Builder_Header::global_astra_header','Astra_Mobile_Header::mobile_header_markup']);} break; case 'generatepress': $this->replace_action('generate_'.$area,$area,$area==='header'?['generate_construct_header']:['generate_construct_footer','generate_construct_footer_widgets']); if($area==='header'){ remove_action('generate_before_header','generate_top_bar',5); remove_action('generate_before_header','generate_add_navigation_before_header',5); remove_action('generate_after_header','generate_add_navigation_after_header',5); } break; case 'kadence': $this->replace_action('kadence_'.$area,$area,['Kadence\\'.$area.'_markup']);break; case 'oceanwp': $this->replace_action('ocean_'.$area,$area,['oceanwp_'.$area.'_template']); if($area==='header'){add_filter('ocean_display_top_bar','__return_false');} break; case 'neve': $this->replace_action('hfg_'.$area.'_render',$area,['HFG\\Core\\Builder\\'.ucfirst($area).'::load_template']); add_filter('neve_filter_toggle_content_parts',static fn($show,$part)=>$part===$area?true:$show,99,2); break; case 'blocksy': add_filter('blocksy:builder:'.$area.':enabled','__return_false',99); add_action('blocksy:'.$area.':before',static function()use($area){echo self::region($area);}); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Region uses the Builder renderer which validates documents and escapes every module field; preserve forms, styles and script assets. break; } } if($theme==='hello-elementor'){ add_action('get_header',function(){$this->hello_region='header';},0); add_action('get_footer',function(){$this->hello_region='footer';if(isset(ThemeBuilder::$active['footer'])){echo self::region('footer');}},0); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Region uses the Builder renderer which validates documents and escapes every module field; preserve forms, styles and script assets. add_filter('hello_elementor_header_footer',fn($show)=>isset(ThemeBuilder::$active[$this->hello_region])?false:$show,99); add_action('wp_body_open',static function(){echo self::region('header');},20); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Region uses the Builder renderer which validates documents and escapes every module field; preserve forms, styles and script assets. } } }