'Header','footer'=>'Footer','single-post'=>'Single post','single-page'=>'Single page','single-product'=>'WooCommerce product','archive'=>'Blog and archives','search'=>'Search results','404'=>'404 page']; public function __construct(){ add_action('init',[$this,'register'],5); add_filter('digibl_public_dynamic_meta_keys',static function($keys,$type){return array_values(array_unique(array_merge((array)$keys,self::options()['publicMeta'][$type]??[])));},10,2); add_action('admin_menu',[$this,'menu']); add_action('admin_post_digibl_theme_save',[$this,'save']); add_action('admin_post_digibl_theme_create',[$this,'create']); add_action('template_redirect',[$this,'protect_template'],1); add_filter('template_include',[$this,'template'],100); add_action('wp_enqueue_scripts',[$this,'assets']); add_action('wp',[$this,'select']); add_filter('render_block_core/template-part',[$this,'block_part'],20,2); add_filter('wp_sitemaps_post_types',static function($types){unset($types['digibl_template']);return $types;}); } public function register(): void { $caps=array_fill_keys(['edit_post','read_post','delete_post','edit_posts','edit_others_posts','publish_posts','read_private_posts','delete_posts','delete_private_posts','delete_published_posts','delete_others_posts','edit_private_posts','edit_published_posts','create_posts'],'manage_options'); register_post_type('digibl_template',['label'=>'Digiter site templates','public'=>false,'publicly_queryable'=>true,'show_ui'=>false,'show_in_rest'=>false,'exclude_from_search'=>true,'rewrite'=>false,'query_var'=>false,'supports'=>['title','editor','revisions'],'capabilities'=>$caps,'map_meta_cap'=>false]); } public function menu(): void {add_submenu_page('digiter-builder',Language::text('Site templates'),Language::text('Site templates'),'manage_options','digibl-site-templates',[$this,'screen']);} public static function default_colors(): array {return ['accent'=>'#2667b8','ink'=>'#19324c','surface'=>'#ffffff','soft'=>'#edf5ff','border'=>'#d5e5f6','highlight'=>'#f4c95d'];} public static function view_areas(): array { return ['archive'=>'Blog / home','search'=>'Search results','404'=>'404 page']; } public static function area_label(string $area): string { return self::AREAS[$area]??ucwords(str_replace('-',' ',$area)); } public static function assigned_source(string $area): int { if(!array_key_exists($area,self::AREAS)){return 0;}$settings=self::options();$id=absint($settings['areas'][$area]['source']??0); return !empty($settings['enabled'])&&$id&&get_post_type($id)==='digibl_template'&&get_post_status($id)==='publish'&&get_post_meta($id,'_digibl_published',true)?$id:0; } /** True only for a published template configured as a live site region. */ public static function is_assigned_source(int $id): bool { if($id<1){return false;}$settings=self::options();if(empty($settings['enabled'])){return false;} foreach(array_keys(self::AREAS) as $area){if(absint($settings['areas'][$area]['source']??0)===$id){return true;}} return false; } public static function template_document(string $kind,string $name): array { $kind=Document::choice($kind,array_merge(array_keys(self::AREAS),['loop','section']),'section');$doc=Document::blank();$doc['title']=$name;$doc['settings']['canvas']=true; $node=static fn($id,$type,$props=[])=>['id'=>$id,'type'=>$type,'props'=>$props,'children'=>[]]; if(in_array($kind,['single-post','single-page','single-product'],true)){$doc['nodes']=[$node('templateTitle','dynamic-field',['source'=>'post-title']),$node('templateContent','post-content')];} elseif(in_array($kind,['archive','search'],true)){$doc['nodes']=[$node('archiveTitle','archive-info'),$node('archivePosts','posts',['source'=>'current-query']),$node('archivePages','pagination')];} elseif($kind==='header'){$doc['nodes']=[$node('siteName','dynamic-field',['source'=>'site-title']),$node('siteMenu','nav-menu')];} elseif($kind==='footer'){$doc['nodes']=[$node('siteName','dynamic-field',['source'=>'site-title']),$node('footerText','text',['content'=>'
© '.gmdate('Y').' '.esc_html(get_bloginfo('name')).'
'])];} elseif($kind==='loop'){$doc['nodes']=[$node('postImage','featured-image'),$node('postTitle','dynamic-field',['source'=>'post-title']),$node('postExcerpt','dynamic-field',['source'=>'post-excerpt'])];} else{$doc['nodes']=[$node('templateHeading','heading',['text'=>$kind==='404'?'Page not found':$name]),$node('templateText','text')];} return Document::clean($doc); } public static function prepare_view_template(string $area,string $name) { if(!isset(self::view_areas()[$area])){return new \WP_Error('digibl_view_area','This site view cannot be edited as a layout.',['status'=>400]);} $assigned=self::assigned_source($area);if($assigned){return $assigned;} $existing=get_posts(['post_type'=>'digibl_template','post_status'=>['draft','pending'],'author'=>get_current_user_id(),'numberposts'=>1,'orderby'=>'modified','order'=>'DESC','meta_query'=>[['key'=>'_digibl_pending_view_area','value'=>$area]]]); if($existing){return (int)$existing[0]->ID;} $doc=self::template_document($area,$name);if(is_wp_error($doc)){return $doc;} $id=wp_insert_post(wp_slash(['post_type'=>'digibl_template','post_status'=>'draft','post_title'=>$name,'post_author'=>get_current_user_id()]),true);if(is_wp_error($id)){return $id;} if(!add_post_meta($id,'_digibl_draft',wp_slash(wp_json_encode(['revision'=>wp_generate_uuid4(),'doc'=>$doc])),true)){wp_delete_post($id,true);return new \WP_Error('digibl_view_storage','The site-view draft could not be created.',['status'=>500]);} update_post_meta($id,'_digibl_saved_at',gmdate('Y-m-d H:i:s'));update_post_meta($id,'_digibl_template_kind',$area);update_post_meta($id,'_digibl_pending_view_area',$area);return $id; } public static function assign_view_template(string $area,int $id) { if(!isset(self::view_areas()[$area])){return new \WP_Error('digibl_view_area','This site view cannot be assigned.',['status'=>400]);} if(get_post_type($id)!=='digibl_template'||get_post_status($id)!=='publish'||!get_post_meta($id,'_digibl_published',true)){return new \WP_Error('digibl_view_template','Publish the Digiter site template before assigning it.',['status'=>409]);} $current=self::options();$next=$current;$next['enabled']=true;$next['areas'][$area]=['source'=>$id,'include'=>[],'exclude'=>[]]; $result=self::commit($next,(string)$current['revision']);if(!is_wp_error($result)){delete_post_meta($id,'_digibl_pending_view_area');}return $result; } public static function options(): array { $raw=get_option('digibl_site_templates',[]); $settings=wp_parse_args(is_array($raw)?$raw:[],['enabled'=>false,'areas'=>[],'accent'=>'','bodySize'=>0,'headingFont'=>'inherit','revision'=>'','publicMeta'=>[],'colors'=>self::default_colors(),'typography'=>Typography::defaults()]); $settings['colors']=wp_parse_args(is_array($settings['colors']??null)?$settings['colors']:[],self::default_colors()); foreach(self::default_colors() as $key=>$fallback){$settings['colors'][$key]=Document::color($settings['colors'][$key]??'')?:$fallback;} try{$settings['typography']=Typography::clean($settings['typography']);}catch(\InvalidArgumentException $e){$settings['typography']=Typography::defaults();} return $settings; } public static function colors(): array {return self::options()['colors'];} public function screen(): void { if(!current_user_can('manage_options')){return;}$settings=self::options();$templates=get_posts(['post_type'=>'digibl_template','post_status'=>['publish','draft'],'numberposts'=>100,'orderby'=>'title','order'=>'ASC']); echo ('' . esc_html(Language::text('Create a template in Studio, publish it, then assign it below. Enabling site templates replaces the selected theme regions. Keep all areas at “Theme default” to retain the active theme.')) . '
'); if(isset($_GET['saved'])){echo ('' . esc_html(Language::text('Site template settings saved.')) . '
' . esc_html(Language::text('The active theme has no dedicated header/footer adapter. Its original header and footer are retained. Page content editing remains available.')) . '