admin_url( 'admin-ajax.php' ), 'nonce' => wp_create_nonce( 'eppro_theme_builder' ), 'i18n' => [ 'creating' => __( 'Creating…', 'admore-widgets-suite' ), 'confirmDuplicate' => __( 'Duplicate this template? A draft copy will be created.', 'admore-widgets-suite' ), 'duplicated' => __( 'Template duplicated.', 'admore-widgets-suite' ), 'duplicateFailed' => __( 'Failed to duplicate template.', 'admore-widgets-suite' ), /* translators: %s: template name */ 'confirmDelete' => __( 'Delete "%s"? This action cannot be undone.', 'admore-widgets-suite' ), 'deleted' => __( 'Template deleted.', 'admore-widgets-suite' ), 'deleteFailed' => __( 'Failed to delete template.', 'admore-widgets-suite' ), 'requestFailed' => __( 'An error occurred. Please try again.', 'admore-widgets-suite' ), ], ] ); } // ========================================================================= // Meta Box (on eppro_hf_template edit screen) // ========================================================================= public static function register_meta_box(): void { if ( ! class_exists( 'EPPRO_Theme_Builder_CPT' ) ) return; add_meta_box( 'eppro_hf_settings', __( 'Template Settings', 'admore-widgets-suite' ), [ __CLASS__, 'render_meta_box' ], EPPRO_Theme_Builder_CPT::POST_TYPE, 'side', 'high' ); } public static function render_meta_box( \WP_Post $post ): void { $type = get_post_meta( $post->ID, '_eppro_hf_type', true ) ?: 'header'; $conditions = get_post_meta( $post->ID, '_eppro_hf_conditions', true ) ?: []; $priority = get_post_meta( $post->ID, '_eppro_hf_priority', true ) ?: 10; $sticky = get_post_meta( $post->ID, '_eppro_hf_sticky', true ); $transparent = get_post_meta( $post->ID, '_eppro_hf_transparent', true ); $shrink = get_post_meta( $post->ID, '_eppro_hf_shrink_scroll', true ); $shrink_height = get_post_meta( $post->ID, '_eppro_hf_shrink_height', true ) ?: 60; wp_nonce_field( self::NONCE, self::NONCE ); $types = [ 'header' => __( 'Header', 'admore-widgets-suite' ), 'footer' => __( 'Footer', 'admore-widgets-suite' ), 'single_post' => __( 'Single Post', 'admore-widgets-suite' ), 'single_page' => __( 'Single Page', 'admore-widgets-suite' ), 'archive' => __( 'Archive', 'admore-widgets-suite' ), 'search' => __( 'Search Results', 'admore-widgets-suite' ), 'blog' => __( 'Blog (Posts Page)', 'admore-widgets-suite' ), '404' => __( '404 Error Page', 'admore-widgets-suite' ), 'product' => __( 'WooCommerce Product', 'admore-widgets-suite' ), 'shop' => __( 'WooCommerce Shop', 'admore-widgets-suite' ), 'cart' => __( 'WooCommerce Cart', 'admore-widgets-suite' ), 'checkout' => __( 'WooCommerce Checkout', 'admore-widgets-suite' ), 'my_account' => __( 'WooCommerce My Account', 'admore-widgets-suite' ), 'section' => __( 'Reusable Section', 'admore-widgets-suite' ), 'landing_page' => __( 'Landing Page (No Header/Footer)', 'admore-widgets-suite' ), ]; $cond_types = EPPRO_Theme_Builder_Conditions::get_condition_types(); ?>

'entire_site', 'value' => '' ] ]; } foreach ( $conditions as $i => $cond ) : ?>

tags. $handle = 'eppro-hf-meta-box'; wp_register_script( $handle, false, [ 'jquery' ], EPPRO_VERSION, true ); wp_enqueue_script( $handle ); wp_localize_script( $handle, 'epproHfMeta', [ 'condIdx' => count( $conditions ), 'types' => $cond_types, ] ); wp_add_inline_script( $handle, ' (function($){ var condIdx = parseInt(epproHfMeta.condIdx, 10); var types = epproHfMeta.types; $(".eppro-hf-add-cond").on("click", function(){ var opts = ""; $.each(types, function(k,v){ opts += ""; }); var row = "
" + "" + "" + "" + "
"; $("#eppro-hf-conditions").append(row); condIdx++; }); $(document).on("click", ".eppro-hf-remove-cond", function(){ $(this).closest(".eppro-hf-cond-row").remove(); }); $("#eppro_shrink_scroll").on("change", function(){ $("#eppro_shrink_height_wrap").toggle(this.checked); }); })(jQuery); ' ); } // ========================================================================= // Save Meta // ========================================================================= public static function save_meta( int $post_id, \WP_Post $post ): void { if ( ! class_exists( 'EPPRO_Theme_Builder_CPT' ) ) return; if ( EPPRO_Theme_Builder_CPT::POST_TYPE !== $post->post_type ) return; if ( ! isset( $_POST[ self::NONCE ] ) || ! wp_verify_nonce( sanitize_key( wp_unslash( $_POST[ self::NONCE ] ) ), self::NONCE ) ) return; if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) return; if ( ! current_user_can( 'edit_post', $post_id ) ) return; // Type $type = sanitize_key( wp_unslash( $_POST['_eppro_hf_type'] ?? 'header' ) ); if ( ! in_array( $type, self::TEMPLATE_TYPES, true ) ) $type = 'header'; update_post_meta( $post_id, '_eppro_hf_type', $type ); // Priority $priority = absint( $_POST['_eppro_hf_priority'] ?? 10 ); $priority = max( 1, min( 100, $priority ) ); update_post_meta( $post_id, '_eppro_hf_priority', $priority ); // Conditions $raw_conds = isset( $_POST['_eppro_hf_conditions'] ) && is_array( $_POST['_eppro_hf_conditions'] ) ? map_deep( wp_unslash( $_POST['_eppro_hf_conditions'] ), 'sanitize_text_field' ) : []; $conditions = []; foreach ( (array) $raw_conds as $cond ) { $ct = sanitize_key( $cond['type'] ?? '' ); $cv = sanitize_text_field( $cond['value'] ?? '' ); if ( $ct ) { $conditions[] = [ 'type' => $ct, 'value' => $cv ]; } } update_post_meta( $post_id, '_eppro_hf_conditions', $conditions ); // Header Options update_post_meta( $post_id, '_eppro_hf_sticky', ! empty( $_POST['_eppro_hf_sticky'] ) ? '1' : '' ); update_post_meta( $post_id, '_eppro_hf_transparent', ! empty( $_POST['_eppro_hf_transparent'] ) ? '1' : '' ); update_post_meta( $post_id, '_eppro_hf_shrink_scroll', ! empty( $_POST['_eppro_hf_shrink_scroll'] ) ? '1' : '' ); $shrink_height = absint( $_POST['_eppro_hf_shrink_height'] ?? 60 ); $shrink_height = max( 40, min( 200, $shrink_height ) ); update_post_meta( $post_id, '_eppro_hf_shrink_height', $shrink_height ); // Ensure Elementor edit mode is set if ( ! get_post_meta( $post_id, '_elementor_edit_mode', true ) ) { update_post_meta( $post_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $post_id, '_elementor_template_type', 'wp-post' ); } } // ========================================================================= // Create Template Handler // ========================================================================= public static function handle_create(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'admore-widgets-suite' ) ); } check_admin_referer( 'eppro_create_hf_template' ); $title = sanitize_text_field( wp_unslash( $_POST['template_title'] ?? '' ) ); $type = sanitize_key( wp_unslash( $_POST['template_type'] ?? 'header' ) ); if ( ! in_array( $type, self::TEMPLATE_TYPES, true ) ) { $type = 'header'; } if ( ! $title ) $title = ucwords( str_replace( '_', ' ', $type ) ) . ' Template'; // Created as a draft: an empty template must not replace the live // site's header, footer or pages before it has been designed. // Publishing it from Elementor makes it active. $post_id = wp_insert_post( [ 'post_title' => $title, 'post_type' => EPPRO_Theme_Builder_CPT::POST_TYPE, 'post_status' => 'draft', ] ); if ( is_wp_error( $post_id ) || ! $post_id ) { wp_safe_redirect( admin_url( 'admin.php?page=' . self::PAGE_SLUG . '&error=create_failed' ) ); exit; } // A landing page replaces the whole page, so it starts with no // conditions — the admin picks the pages it applies to. $conditions = 'landing_page' === $type ? [] : [ [ 'type' => 'entire_site', 'value' => '' ] ]; update_post_meta( $post_id, '_eppro_hf_type', $type ); update_post_meta( $post_id, '_eppro_hf_conditions', $conditions ); update_post_meta( $post_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $post_id, '_elementor_template_type', 'wp-post' ); // Redirect to Elementor editor if ( class_exists( 'Elementor\Plugin' ) ) { $doc = \Elementor\Plugin::instance()->documents->get( $post_id ); if ( $doc ) { wp_safe_redirect( $doc->get_edit_url() ); exit; } } wp_safe_redirect( get_edit_post_link( $post_id, 'raw' ) ); exit; } // ========================================================================= // Admin Page Render // ========================================================================= public static function render_page(): void { if ( ! class_exists( 'EPPRO_Theme_Builder_CPT' ) || ! class_exists( 'EPPRO_Theme_Builder_Conditions' ) ) { echo '

' . esc_html__( 'Theme Builder', 'admore-widgets-suite' ) . '

'; echo '

' . esc_html__( 'Essential Pro Pack core is still loading. Please ensure Elementor is active, then reload this page.', 'admore-widgets-suite' ) . '

'; return; } $templates = get_posts( [ 'post_type' => EPPRO_Theme_Builder_CPT::POST_TYPE, 'post_status' => [ 'publish', 'draft', 'private' ], 'posts_per_page' => -1, 'orderby' => 'date', 'order' => 'DESC', ] ); $type_labels = [ 'header' => __( 'Header', 'admore-widgets-suite' ), 'footer' => __( 'Footer', 'admore-widgets-suite' ), 'single_post' => __( 'Single Post', 'admore-widgets-suite' ), 'single_page' => __( 'Single Page', 'admore-widgets-suite' ), 'archive' => __( 'Archive', 'admore-widgets-suite' ), 'search' => __( 'Search Results', 'admore-widgets-suite' ), 'blog' => __( 'Blog Page', 'admore-widgets-suite' ), '404' => __( '404 Page', 'admore-widgets-suite' ), 'product' => __( 'Product', 'admore-widgets-suite' ), 'shop' => __( 'Shop', 'admore-widgets-suite' ), 'cart' => __( 'Cart', 'admore-widgets-suite' ), 'checkout' => __( 'Checkout', 'admore-widgets-suite' ), 'my_account' => __( 'My Account', 'admore-widgets-suite' ), 'section' => __( 'Section', 'admore-widgets-suite' ), 'landing_page' => __( 'Landing Page', 'admore-widgets-suite' ), ]; $allowed_svg = [ 'svg' => [ 'width' => [], 'height' => [], 'viewbox' => [], 'fill' => [], 'stroke' => [], 'stroke-width' => [], 'stroke-linecap' => [], 'stroke-linejoin' => [] ], 'path' => [ 'd' => [], 'fill' => [], 'stroke' => [] ], 'rect' => [ 'x' => [], 'y' => [], 'width' => [], 'height' => [], 'rx' => [], 'ry' => [] ], 'line' => [ 'x1' => [], 'y1' => [], 'x2' => [], 'y2' => [] ], 'circle' => [ 'cx' => [], 'cy' => [], 'r' => [] ], 'polyline' => [ 'points' => [] ], ]; $type_icons = [ 'header' => '', 'footer' => '', 'single_post' => '', 'single_page' => '', 'archive' => '', 'search' => '', 'blog' => '', '404' => '', 'product' => '', 'shop' => '', 'cart' => '', 'checkout' => '', 'my_account' => '', 'section' => '', 'landing_page' => '', ]; $type_descriptions = [ 'header' => __( 'Site-wide navigation bar', 'admore-widgets-suite' ), 'footer' => __( 'Bottom section for copyright & links', 'admore-widgets-suite' ), 'single_post' => __( 'Template for individual blog posts', 'admore-widgets-suite' ), 'single_page' => __( 'Template for individual pages', 'admore-widgets-suite' ), 'archive' => __( 'Category, tag & date archives', 'admore-widgets-suite' ), 'search' => __( 'Search results listing page', 'admore-widgets-suite' ), 'blog' => __( 'Main posts listing page', 'admore-widgets-suite' ), '404' => __( 'Page not found error screen', 'admore-widgets-suite' ), 'product' => __( 'WooCommerce single product', 'admore-widgets-suite' ), 'shop' => __( 'WooCommerce products listing', 'admore-widgets-suite' ), 'cart' => __( 'WooCommerce shopping cart', 'admore-widgets-suite' ), 'checkout' => __( 'WooCommerce checkout page', 'admore-widgets-suite' ), 'my_account' => __( 'WooCommerce account dashboard', 'admore-widgets-suite' ), 'section' => __( 'Reusable content blocks', 'admore-widgets-suite' ), 'landing_page' => __( 'Full page without header & footer', 'admore-widgets-suite' ), ]; $cond_labels = EPPRO_Theme_Builder_Conditions::get_condition_types(); // Group templates by type $templates_by_type = array_fill_keys( array_keys( $type_labels ), [] ); foreach ( $templates as $tpl ) { $type = get_post_meta( $tpl->ID, '_eppro_hf_type', true ) ?: 'header'; if ( isset( $templates_by_type[ $type ] ) ) { $templates_by_type[ $type ][] = $tpl; } } ?>

v

$tlabel ) : ?>
$section_templates ) : ?>

()

ID, '_eppro_hf_type', true ) ?: 'header'; $tpl_conds = get_post_meta( $tpl->ID, '_eppro_hf_conditions', true ) ?: []; $is_sticky = get_post_meta( $tpl->ID, '_eppro_hf_sticky', true ); $is_transparent = get_post_meta( $tpl->ID, '_eppro_hf_transparent', true ); $edit_url = get_edit_post_link( $tpl->ID, 'raw' ); $elementor_url = ''; if ( class_exists( 'Elementor\Plugin' ) ) { $doc = \Elementor\Plugin::instance()->documents->get( $tpl->ID ); if ( $doc ) $elementor_url = $doc->get_edit_url(); } $cond_parts = []; foreach ( $tpl_conds as $c ) { $ct = $c['type'] ?? ''; $cv = $c['value'] ?? ''; $clabel = $cond_labels[ $ct ] ?? $ct; if ( $cv ) $clabel .= ': ' . $cv; $cond_parts[] = $clabel; } ?>

post_title ); ?>

post_status ) : ?> post_status ? __( 'Active', 'admore-widgets-suite' ) : __( 'Draft', 'admore-widgets-suite' ) ); ?>
__( 'Insufficient permissions.', 'admore-widgets-suite' ) ] ); } $template_id = absint( $_POST['template_id'] ?? 0 ); if ( ! $template_id || EPPRO_Theme_Builder_CPT::POST_TYPE !== get_post_type( $template_id ) ) { wp_send_json_error( [ 'message' => __( 'Template not found.', 'admore-widgets-suite' ) ] ); } // Shared duplicator: copies all settings and Elementor data safely; the copy is a draft. $new_id = EPPRO_Template_Duplicator::do_duplicate( $template_id ); if ( is_wp_error( $new_id ) ) { wp_send_json_error( [ 'message' => __( 'Failed to duplicate template.', 'admore-widgets-suite' ) ] ); } wp_send_json_success( [ 'message' => __( 'Template duplicated successfully.', 'admore-widgets-suite' ), 'new_id' => $new_id ] ); } public static function ajax_delete_template(): void { check_ajax_referer( 'eppro_theme_builder', 'nonce' ); if ( ! current_user_can( 'manage_options' ) ) { wp_send_json_error( [ 'message' => __( 'Insufficient permissions.', 'admore-widgets-suite' ) ] ); } $template_id = absint( $_POST['template_id'] ?? 0 ); if ( ! $template_id ) { wp_send_json_error( [ 'message' => __( 'Invalid template ID.', 'admore-widgets-suite' ) ] ); } $result = wp_delete_post( $template_id, true ); if ( ! $result ) { wp_send_json_error( [ 'message' => __( 'Failed to delete template.', 'admore-widgets-suite' ) ] ); } wp_send_json_success( [ 'message' => __( 'Template deleted successfully.', 'admore-widgets-suite' ) ] ); } }