__( 'Theme Templates', 'admore-widgets-suite' ), 'labels' => [ 'name' => __( 'Theme Templates', 'admore-widgets-suite' ), 'singular_name' => __( 'Theme Template', 'admore-widgets-suite' ), 'add_new_item' => __( 'Add New Template', 'admore-widgets-suite' ), 'edit_item' => __( 'Edit Template', 'admore-widgets-suite' ), ], 'public' => false, 'publicly_queryable' => true, 'exclude_from_search' => true, 'show_ui' => true, 'show_in_menu' => false, // Templates are rendered on the frontend by the plugin only; they // are not listed through the REST API. 'show_in_rest' => false, 'has_archive' => false, 'rewrite' => false, 'supports' => [ 'title', 'editor', 'elementor', 'thumbnail' ], 'capability_type' => 'post', // Headers, footers and page templates apply site-wide, so only // administrators may manage them (same as the Theme Builder page). 'capabilities' => self::capabilities(), 'map_meta_cap' => true, ] ); } /** Primitive capabilities for the template post type, all mapped to manage_options. */ public static function capabilities(): array { $cap = 'manage_options'; return [ 'edit_posts' => $cap, 'edit_others_posts' => $cap, 'edit_private_posts' => $cap, 'edit_published_posts' => $cap, 'publish_posts' => $cap, 'read_private_posts' => $cap, 'delete_posts' => $cap, 'delete_private_posts' => $cap, 'delete_published_posts' => $cap, 'delete_others_posts' => $cap, 'create_posts' => $cap, ]; } public static function filter_elementor_cpt_support( $supported ): array { if ( ! is_array( $supported ) ) { $supported = [ 'page', 'post' ]; } if ( ! in_array( self::POST_TYPE, $supported, true ) ) { $supported[] = self::POST_TYPE; } return $supported; } public static function maybe_flush(): void { if ( get_option( 'eppro_hf_cpt_flushed' ) ) return; flush_rewrite_rules(); update_option( 'eppro_hf_cpt_flushed', '1' ); } /** * Block direct frontend access — only Elementor preview and editors allowed. */ public static function block_direct_access(): void { if ( ! is_singular( self::POST_TYPE ) ) return; // Covers the Elementor preview iframe too (it loads as the logged-in editor); // a bare "?elementor-preview" query arg is not trusted on its own. if ( current_user_can( 'edit_post', get_queried_object_id() ) ) return; global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); include get_query_template( '404' ); exit; } /** * Get all published templates of a specific type. * * @param string $type 'header'|'footer'|'section' * @return \WP_Post[] */ public static function get_templates_by_type( string $type ): array { // Few templates exist, so filter the (meta-cached) posts in PHP instead // of a meta_query. $type = sanitize_key( $type ); return array_values( array_filter( get_posts( [ 'post_type' => self::POST_TYPE, 'post_status' => 'publish', 'posts_per_page' => 200, 'orderby' => 'title', 'order' => 'ASC', ] ), static fn( $post ) => get_post_meta( $post->ID, '_eppro_hf_type', true ) === $type ) ); } }