label. */ public static function categories(): array { return [ 'popup' => __( 'Popups', 'admore-widgets-suite' ), 'section' => __( 'Sections', 'admore-widgets-suite' ), 'page' => __( 'Pages', 'admore-widgets-suite' ), 'theme' => __( 'Header & Footer', 'admore-widgets-suite' ), ]; } /** * All templates: slug => [ title, desc, type, category, widgets, preview, content, popup? ]. * Built on demand (they are translated and only needed on two screens). */ public static function all(): array { static $templates = null; if ( null === $templates ) { $templates = require EPPRO_PATH . 'templates/library.php'; $templates = is_array( $templates ) ? $templates : []; } return $templates; } // ========================================================================= // Builders (used by templates/library.php) // ========================================================================= /** A full-width section. $columns: list of self::col(). */ public static function section( array $columns, array $settings = [] ): array { $settings += [ 'gap' => 'extended', 'padding' => self::box( 80, 20 ), ]; return [ 'elType' => 'section', 'settings' => $settings, 'elements' => $columns ]; } /** A column of $size percent holding $widgets. */ public static function col( int $size, array $widgets, array $settings = [] ): array { $settings += [ '_column_size' => $size, '_inline_size' => null ]; return [ 'elType' => 'column', 'settings' => $settings, 'elements' => $widgets ]; } public static function widget( string $type, array $settings = [] ): array { return [ 'elType' => 'widget', 'widgetType' => $type, 'settings' => $settings, 'elements' => [] ]; } /** Elementor core Heading. */ public static function heading( string $text, string $tag = 'h2', string $align = 'center', array $extra = [] ): array { return self::widget( 'heading', $extra + [ 'title' => $text, 'header_size' => $tag, 'align' => $align, 'title_color' => '#0f172a' ] ); } /** Elementor core Text Editor. */ public static function text( string $html, string $align = 'center', array $extra = [] ): array { return self::widget( 'text-editor', $extra + [ 'editor' => $html, 'align' => $align, 'text_color' => '#475569' ] ); } public static function spacer( int $px ): array { return self::widget( 'spacer', [ 'space' => [ 'unit' => 'px', 'size' => $px ] ] ); } /** One Advanced Form field row. */ public static function field( string $id, string $type, string $label, array $extra = [] ): array { return $extra + [ '_id' => $id, 'field_id' => $id, 'field_type' => $type, 'field_label' => $label, ]; } /** Padding / margin value (top+bottom, left+right). */ public static function box( int $vertical, int $horizontal = 0, string $unit = 'px' ): array { return [ 'unit' => $unit, 'top' => (string) $vertical, 'right' => (string) $horizontal, 'bottom' => (string) $vertical, 'left' => (string) $horizontal, 'isLinked' => false, ]; } public static function icon( string $fa, string $library = 'fa-solid' ): array { return [ 'value' => $fa, 'library' => $library ]; } // ========================================================================= // Import // ========================================================================= public static function handle_import(): void { if ( ! current_user_can( 'manage_options' ) ) { wp_die( esc_html__( 'Insufficient permissions.', 'admore-widgets-suite' ) ); } check_admin_referer( self::NONCE ); $slug = sanitize_key( wp_unslash( $_POST['template'] ?? '' ) ); $result = self::import( $slug ); if ( is_wp_error( $result ) ) { wp_safe_redirect( add_query_arg( [ 'page' => self::PAGE_SLUG, 'eppro_error' => rawurlencode( $result->get_error_message() ) ], admin_url( 'admin.php' ) ) ); exit; } // Straight into Elementor to customise the new copy. wp_safe_redirect( admin_url( 'post.php?post=' . (int) $result . '&action=elementor' ) ); exit; } /** * Create a post from template $slug. Returns the new post ID. * * @return int|WP_Error */ public static function import( string $slug ) { $all = self::all(); if ( ! isset( $all[ $slug ] ) ) { return new WP_Error( 'eppro_template', __( 'Unknown template.', 'admore-widgets-suite' ) ); } if ( ! class_exists( '\Elementor\Plugin' ) ) { return new WP_Error( 'eppro_template', __( 'Elementor is not active.', 'admore-widgets-suite' ) ); } $tpl = $all[ $slug ]; if ( ! self::requirements_met( $tpl ) ) { return new WP_Error( 'eppro_template', __( 'This template needs WooCommerce. Install and activate WooCommerce first.', 'admore-widgets-suite' ) ); } $type = $tpl['type']; $elements = self::with_ids( $tpl['content'] ); switch ( $type ) { case 'popup': $post_id = wp_insert_post( [ 'post_type' => class_exists( 'EPPRO_Popup_CPT' ) ? EPPRO_Popup_CPT::POST_TYPE : 'eppro_popup', 'post_title' => $tpl['title'], 'post_status' => 'draft', ], true ); if ( is_wp_error( $post_id ) ) return $post_id; // Inactive until the site owner switches it on in Popup Builder. update_post_meta( $post_id, '_eppro_popup', ( $tpl['popup'] ?? [] ) + self::popup_defaults() ); break; case 'header': case 'footer': $post_id = wp_insert_post( [ 'post_type' => class_exists( 'EPPRO_Theme_Builder_CPT' ) ? EPPRO_Theme_Builder_CPT::POST_TYPE : 'eppro_hf_template', 'post_title' => $tpl['title'], // Draft: it must not replace the live header / footer before it is reviewed. 'post_status' => 'draft', ], true ); if ( is_wp_error( $post_id ) ) return $post_id; update_post_meta( $post_id, '_eppro_hf_type', $type ); update_post_meta( $post_id, '_eppro_hf_conditions', [ [ 'type' => 'entire_site', 'value' => '' ] ] ); update_post_meta( $post_id, '_elementor_template_type', 'wp-post' ); break; default: // section, page → Elementor template library $doc = \Elementor\Plugin::$instance->documents->create( 'page' === $type ? 'page' : 'section', [ 'post_title' => $tpl['title'], 'post_status' => 'publish', 'post_type' => 'elementor_library' ] ); if ( ! $doc || is_wp_error( $doc ) ) { return new WP_Error( 'eppro_template', __( 'The template could not be created.', 'admore-widgets-suite' ) ); } $post_id = (int) $doc->get_main_id(); break; } update_post_meta( $post_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $post_id, '_eppro_library_template', $slug ); $document = \Elementor\Plugin::$instance->documents->get( $post_id, false ); if ( ! $document ) { return new WP_Error( 'eppro_template', __( 'The template could not be created.', 'admore-widgets-suite' ) ); } $document->save( [ 'elements' => $elements ] ); return (int) $post_id; } /** False when the template needs a plugin that is not active (e.g. WooCommerce). */ public static function requirements_met( array $tpl ): bool { if ( 'woocommerce' === ( $tpl['requires'] ?? '' ) ) { return class_exists( 'WooCommerce' ); } return true; } /** Popup Builder settings for an imported popup (see EPPRO_Popup_Settings::save). */ private static function popup_defaults(): array { return [ 'active' => false, 'triggers' => [ 'page_load' ], 'page_load_delay' => 3000, 'condition_scope' => 'entire_site', 'user_condition' => 'all', 'visitor_type' => 'all', 'devices' => [ 'desktop', 'tablet', 'mobile' ], 'show_once_session' => true, 'cookie_days' => 30, 'close_overlay' => true, 'close_esc' => true, 'show_close_btn' => true, 'position' => 'center', 'animation' => 'zoom', 'popup_width' => 600, 'max_width' => 600, 'popup_width_unit' => 'px', 'overlay_color' => '#0f172a', 'overlay_opacity' => 60, 'container_bg' => '#ffffff', 'border_radius' => 16, 'content_padding' => 32, 'body_scroll_lock' => true, ]; } /** Give every element (and repeater row without one) a fresh Elementor ID. */ private static function with_ids( array $elements ): array { foreach ( $elements as &$el ) { $el['id'] = self::new_id(); foreach ( (array) ( $el['settings'] ?? [] ) as $key => $value ) { if ( is_array( $value ) && isset( $value[0] ) && is_array( $value[0] ) ) { foreach ( $el['settings'][ $key ] as &$row ) { // Repeater rows: a fresh ID per import (used by {{CURRENT_ITEM}} CSS). if ( is_array( $row ) && is_string( array_key_first( $row ) ) ) { $row['_id'] = self::new_id(); } } unset( $row ); } } if ( ! empty( $el['elements'] ) ) { $el['elements'] = self::with_ids( $el['elements'] ); } } unset( $el ); return $elements; } private static function new_id(): string { return substr( bin2hex( random_bytes( 4 ) ), 0, 7 ); } // ========================================================================= // Admin page // ========================================================================= public static function add_menu(): void { add_submenu_page( 'eppro-settings', __( 'Template Library', 'admore-widgets-suite' ), __( 'Template Library', 'admore-widgets-suite' ), 'manage_options', self::PAGE_SLUG, [ __CLASS__, 'render_page' ] ); } public static function render_page(): void { if ( ! current_user_can( 'manage_options' ) ) return; $templates = self::all(); $categories = self::categories(); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Message after a redirect. $error = isset( $_GET['eppro_error'] ) ? sanitize_text_field( wp_unslash( $_GET['eppro_error'] ) ) : ''; ?>

$label ) : ?>
$tpl ) : ?>

'; break; case 'title': echo '
'; break; case 'text': echo '
'; break; case 'button': echo '
'; break; case 'fields2': echo '
'; break; case 'field': echo '
'; break; case 'steps': echo '
'; break; case 'check': echo '
'; break; case 'timer': echo '
'; break; case 'cols3': echo '
'; break; case 'cards3': echo '
'; break; case 'stats': echo '
'; break; case 'faq': echo '
'; break; case 'quote': echo '
'; break; case 'split': echo '
'; break; case 'footer': echo '
'; break; case 'hero': echo '
'; break; case 'cols4': echo '
'; break; case 'cards4': echo '
'; break; case 'steps4': echo '
1234
'; break; case 'logos': echo '
'; break; case 'gallery': echo ''; break; case 'map': echo '
'; break; case 'product': echo '
'; break; case 'tabs': echo '
'; break; default: echo '
'; } } }