0 ); } /** * Import Elementor JSON (template export) and create/update a Home page. * This works by writing Elementor data/meta directly to a WP page. * * Requirements: * - Elementor plugin active * - Premium active (purchase code verified) */ function bongoto_woo_is_elementor_active() : bool { return class_exists( '\\Elementor\\Plugin' ); } /** * Check if WooCommerce is active. */ function bongoto_woo_is_woocommerce_active() : bool { return class_exists( 'WooCommerce' ) || function_exists( 'WC' ); } /** * Derive a friendly Home page title from a demo JSON file name. * Examples: * - elementor/bongoto-wc-home-electronics.json => Home Electronics * - elementor/home-books.json => Home Books */ function bongoto_woo_home_title_from_file( string $file, string $fallback = 'Home' ) : string { $base = basename( $file ); $base = preg_replace( '/\.[a-zA-Z0-9]+$/', '', $base ); // Remove common prefixes. $base = preg_replace( '/^(bongoto|bongoto-wc|bongoto-woocommerce)[-_]?/i', '', $base ); // Normalize separators. $base = str_replace( array( '_', '-' ), ' ', $base ); $base = trim( preg_replace( '/\s+/', ' ', $base ) ); if ( $base === '' ) { return $fallback; } // Ensure it starts with Home. if ( stripos( $base, 'home ' ) !== 0 ) { $base = 'Home ' . $base; } // Title Case. $base = ucwords( strtolower( $base ) ); return $base; } /** * Local demo folder inside theme. * We sync remote demo assets here when user runs Demo Import. */ function bongoto_woo_local_demo_root( string $demo_slug = 'bongoto-woocommerce' ) : string { // Back-compat: store demos in uploads (never in theme dir). return bongoto_woo_demo_storage_root() . trailingslashit( $demo_slug ); } function bongoto_woo_local_demo_file( string $relative, string $demo_slug = 'bongoto-woocommerce' ) : string { $relative = ltrim( $relative, '/' ); return bongoto_woo_local_demo_root( $demo_slug ) . $relative; } function bongoto_woo_import_home_01_from_manifest() { if ( ! bongoto_woo_is_elementor_active() ) { return new WP_Error( 'bongoto_no_elementor', 'Elementor is not active.' ); } if ( ! bongoto_woo_is_woocommerce_active() ) { return new WP_Error( 'bongoto_no_woocommerce', 'WooCommerce is not active.' ); } $manifest = bongoto_woo_fetch_manifest(); if ( is_wp_error( $manifest ) ) { return $manifest; } if ( empty( $manifest['elementor']['home_pages'][0]['file'] ) ) { return new WP_Error( 'bongoto_no_home_json', 'Home JSON not found in manifest.' ); } $home = $manifest['elementor']['home_pages'][0]; $file = (string) $home['file']; $name = ! empty( $home['name'] ) ? (string) $home['name'] : ''; if ( '' === trim( $name ) ) { $name = bongoto_woo_home_title_from_file( $file, 'Home 01' ); } $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); $url = $base_url . ltrim( $file, '/' ); $resp = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( is_wp_error( $resp ) ) { return $resp; } $code = (int) wp_remote_retrieve_response_code( $resp ); $body = (string) wp_remote_retrieve_body( $resp ); if ( 200 !== $code || '' === $body ) { // Retry once on transient failures. $resp2 = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( ! is_wp_error( $resp2 ) ) { $code = (int) wp_remote_retrieve_response_code( $resp2 ); $body = (string) wp_remote_retrieve_body( $resp2 ); } return new WP_Error( 'bongoto_home_download_failed', 'Failed to download home JSON. (HTTP ' . $code . ') ' . $url, [ 'http' => $code, 'url' => $url ] ); } $body = preg_replace('/^\xEF\xBB\xBF/', '', (string) $body ); $data = json_decode( $body, true ); if ( ! is_array( $data ) ) { return new WP_Error( 'bongoto_home_json_invalid', 'Home JSON is not valid JSON.' ); } // Elementor exports usually contain: content, page_settings/settings, version/title/type $content = null; if ( isset( $data['content'] ) && is_array( $data['content'] ) ) { $content = $data['content']; } elseif ( isset( $data[0] ) && is_array( $data[0] ) ) { // Some exports are raw array $content = $data; } if ( ! is_array( $content ) ) { return new WP_Error( 'bongoto_home_json_no_content', 'Elementor content not found in JSON.' ); } $page_settings = []; if ( isset( $data['page_settings'] ) && is_array( $data['page_settings'] ) ) { $page_settings = $data['page_settings']; } elseif ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) { $page_settings = $data['settings']; } $page_id = bongoto_woo_upsert_home_page( $name, $content, $page_settings, $data ); if ( is_wp_error( $page_id ) ) { return $page_id; } // Set as Front Page update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', (int) $page_id ); // Clear Elementor cache if available try { if ( class_exists( '\\Elementor\\Plugin' ) && isset( \Elementor\Plugin::$instance->files_manager ) ) { \Elementor\Plugin::$instance->files_manager->clear_cache(); } } catch ( \Throwable $e ) { /* ignore */ } return [ 'page_id' => (int) $page_id, 'page_url' => get_permalink( (int) $page_id ), 'title' => get_the_title( (int) $page_id ), ]; } function bongoto_woo_upsert_home_page( string $title, array $elementor_content, array $page_settings, array $raw ) { // Defensive: ensure settings stay as array even if upstream JSON is malformed. if ( ! is_array( $page_settings ) ) { $page_settings = []; } $existing = get_page_by_title( $title, OBJECT, 'page' ); $page_id = $existing ? (int) $existing->ID : 0; $postarr = [ 'post_title' => $title, 'post_type' => 'page', 'post_status' => 'publish', 'post_name' => sanitize_title( $title ), ]; // Keep slug stable and friendly. $postarr['post_name'] = sanitize_title( $title ); if ( $page_id ) { $postarr['ID'] = $page_id; $page_id = wp_update_post( $postarr, true ); } else { $page_id = wp_insert_post( $postarr, true ); } if ( is_wp_error( $page_id ) ) { return $page_id; } // Elementor meta update_post_meta( $page_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $page_id, '_elementor_template_type', 'wp-page' ); // Version if present, else keep current if ( defined( 'ELEMENTOR_VERSION' ) ) { update_post_meta( $page_id, '_elementor_version', ELEMENTOR_VERSION ); } // Write Elementor data $encoded = wp_json_encode( $elementor_content ); update_post_meta( $page_id, '_elementor_data', wp_slash( $encoded ) ); if ( ! empty( $page_settings ) ) { update_post_meta( $page_id, '_elementor_page_settings', $page_settings ); } // Mark as demo home so Customizer can list it for selection. update_post_meta( $page_id, '_bongoto_demo_home', '1' ); if ( isset( $raw['file'] ) && is_string( $raw['file'] ) ) { update_post_meta( $page_id, '_bongoto_demo_source', sanitize_text_field( $raw['file'] ) ); } return (int) $page_id; } /** * Import a home by index from manifest (elementor.home_pages[index]). */ function bongoto_woo_import_home_by_index_from_manifest( int $index, bool $set_front = true ) { if ( ! bongoto_woo_is_elementor_active() ) { return new WP_Error( 'bongoto_no_elementor', 'Elementor is not active.' ); } if ( ! bongoto_woo_is_woocommerce_active() ) { return new WP_Error( 'bongoto_no_woocommerce', 'WooCommerce is not active.' ); } $manifest = bongoto_woo_fetch_manifest(); if ( is_wp_error( $manifest ) ) { return $manifest; } $homes = $manifest['elementor']['home_pages'] ?? []; if ( ! is_array( $homes ) || empty( $homes ) || ! isset( $homes[ $index ] ) ) { return new WP_Error( 'bongoto_home_not_found', 'Selected home not found in manifest.' ); } $home = $homes[ $index ]; $file = isset( $home['file'] ) ? (string) $home['file'] : ''; $name = isset( $home['name'] ) ? (string) $home['name'] : ''; $file = ltrim( $file, '/' ); if ( '' === $file ) { return new WP_Error( 'bongoto_no_home_json', 'Home JSON file is missing in manifest.' ); } // If manifest doesn't provide a friendly name, derive it from JSON file name. if ( trim( $name ) === '' ) { $name = bongoto_woo_home_title_from_file( $file, 'Home' ); } // Prefer local synced JSON inside theme. $body = ''; $local = bongoto_woo_local_demo_file( $file ); if ( file_exists( $local ) ) { $body = (string) file_get_contents( $local ); } else { $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); $url = $base_url . $file; $resp = wp_remote_get( $url, [ 'timeout' => 25, 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ), ] ); if ( is_wp_error( $resp ) ) { return new WP_Error( 'bongoto_home_download_failed', 'Failed to download home JSON. ' . $resp->get_error_message() ); } $code = (int) wp_remote_retrieve_response_code( $resp ); $body = (string) wp_remote_retrieve_body( $resp ); if ( 200 !== $code || '' === $body ) { return new WP_Error( 'bongoto_home_download_failed', sprintf( 'Failed to download home JSON. (HTTP %d) %s', $code, esc_url_raw( $url ) ) ); } } // Strip UTF-8 BOM if present. if ( 0 === strpos( $body, "\xEF\xBB\xBF" ) ) { $body = substr( $body, 3 ); } $body = preg_replace('/^\xEF\xBB\xBF/', '', (string) $body ); $data = json_decode( $body, true ); if ( ! is_array( $data ) ) { return new WP_Error( 'bongoto_home_json_invalid', 'Home JSON is not valid JSON.' ); } // Elementor exports usually contain: content, page_settings/settings, version/title/type $content = null; if ( isset( $data['content'] ) && is_array( $data['content'] ) ) { $content = $data['content']; } elseif ( isset( $data[0] ) && is_array( $data[0] ) ) { $content = $data; } if ( ! is_array( $content ) || empty( $content ) ) { return new WP_Error( 'bongoto_home_no_content', 'Home JSON does not contain content.' ); } $page_settings = []; if ( isset( $data['page_settings'] ) && is_array( $data['page_settings'] ) ) { $page_settings = $data['page_settings']; } elseif ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) { $page_settings = $data['settings']; } // Trace the source file for support. $data['file'] = $file; $page_id = bongoto_woo_upsert_home_page( $name, $content, $page_settings, $data ); if ( is_wp_error( $page_id ) ) { return $page_id; } if ( $set_front ) { update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', (int) $page_id ); } return (int) $page_id; } function bongoto_woo_download_headers_selected( array $files ) { $manifest = bongoto_woo_fetch_manifest(); if ( is_wp_error( $manifest ) ) return $manifest; $demo_slug = 'bongoto-woocommerce'; $render_dir = bongoto_woo_local_demo_root( $demo_slug ) . 'headers/'; wp_mkdir_p( $render_dir ); $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); foreach ( $files as $file ) { // Only allow safe assets. if ( ! bongoto_woo_demo_is_allowed_file( (string) $file ) ) { continue; } $file = ltrim( (string) $file, '/' ); if ( '' === $file ) continue; $url = $base_url . $file; $r = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( is_wp_error( $r ) ) continue; $code = (int) wp_remote_retrieve_response_code( $r ); $body = (string) wp_remote_retrieve_body( $r ); if ( 200 !== $code || '' === $body ) continue; $name = basename( $file ); bongoto_woo_fs_put_contents( $render_dir . $name, $body ); } // Always try to fetch shared partials used by headers (Topbar), even if not selected. // NOTE: We do not download PHP or .htaccess from remote servers. foreach ( array( 'headers/topbar.css' ) as $extra ) { $url = $base_url . ltrim( $extra, '/' ); $r = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( is_wp_error( $r ) ) { continue; } $code = (int) wp_remote_retrieve_response_code( $r ); $body = (string) wp_remote_retrieve_body( $r ); if ( 200 !== $code || '' === $body ) { continue; } bongoto_woo_fs_put_contents( $render_dir . basename( $extra ), $body ); } return true; } /** * Apply color preset by index from manifest.colors[] * Preset JSON should be: * { "theme_mods": { "bongoto_color_site_bg":"#ffffff", ... } } */ function bongoto_woo_apply_color_preset_by_index_from_manifest( int $index ) { $manifest = bongoto_woo_fetch_manifest(); if ( is_wp_error( $manifest ) ) return $manifest; $colors = $manifest['colors'] ?? []; if ( ! is_array( $colors ) || empty( $colors ) || ! isset( $colors[ $index ] ) ) { return new WP_Error( 'bongoto_color_not_found', 'Color preset not found in manifest.' ); } $preset = $colors[ $index ]; $file = isset( $preset['file'] ) ? (string) $preset['file'] : ''; if ( '' === $file ) return new WP_Error( 'bongoto_color_file_missing', 'Color preset file missing.' ); $local = bongoto_woo_local_demo_file( ltrim( $file, '/' ) ); if ( file_exists( $local ) ) { $body = (string) file_get_contents( $local ); } else { $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); $url = $base_url . ltrim( $file, '/' ); $resp = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( is_wp_error( $resp ) ) return $resp; $code = (int) wp_remote_retrieve_response_code( $resp ); $body = (string) wp_remote_retrieve_body( $resp ); if ( 200 !== $code || '' === $body ) { return new WP_Error( 'bongoto_color_download', 'Could not download color preset.' ); } } $body = preg_replace('/^\xEF\xBB\xBF/', '', (string) $body ); $data = json_decode( $body, true ); if ( ! is_array( $data ) || empty( $data['theme_mods'] ) || ! is_array( $data['theme_mods'] ) ) { return new WP_Error( 'bongoto_color_invalid', 'Invalid color preset JSON.' ); } // Save preset into the theme demo folder (as requested) so Customizer can read from template-parts/demos/... $save_dir = bongoto_woo_local_demo_root() . 'presets/'; wp_mkdir_p( $save_dir ); bongoto_woo_fs_put_contents( $save_dir . basename( $file ), $body ); // Apply theme_mods (overwrite) foreach ( $data['theme_mods'] as $k => $v ) { if ( ! is_string( $k ) ) continue; if ( ! is_string( $v ) ) continue; set_theme_mod( $k, $v ); } // Ensure Customizer's minimal 3 color controls reflect imported presets, // even if the preset uses a different key schema. $mods = $data['theme_mods']; if ( empty( $mods['bongoto_color_site_bg'] ) && ! empty( $mods['bongoto_woocommerce_color_bg'] ) ) { set_theme_mod( 'bongoto_color_site_bg', (string) $mods['bongoto_woocommerce_color_bg'] ); } if ( empty( $mods['bongoto_color_header_bg'] ) ) { if ( ! empty( $mods['bongoto_woocommerce_color_primary'] ) ) { set_theme_mod( 'bongoto_color_header_bg', (string) $mods['bongoto_woocommerce_color_primary'] ); } elseif ( ! empty( $mods['bongoto_woocommerce_color_accent'] ) ) { set_theme_mod( 'bongoto_color_header_bg', (string) $mods['bongoto_woocommerce_color_accent'] ); } } if ( empty( $mods['bongoto_color_footer_bg'] ) ) { // Prefer a dark footer if not provided. set_theme_mod( 'bongoto_color_footer_bg', '#111111' ); } return true; } /** * Import a selected Home JSON file from manifest (Elementor home_pages[*].file). * @param string $file Relative file path from manifest, e.g. "elementor/bongoto-wc-home-01.json" */ function bongoto_woo_import_home_from_manifest_file( string $file ) { if ( ! bongoto_woo_is_elementor_active() ) { return new WP_Error( 'bongoto_no_elementor', 'Elementor is not active.' ); } if ( ! bongoto_woo_is_woocommerce_active() ) { return new WP_Error( 'bongoto_no_woocommerce', 'WooCommerce is not active.' ); } $manifest = bongoto_woo_fetch_manifest(); if ( is_wp_error( $manifest ) ) { return $manifest; } $file = ltrim( (string) $file, '/' ); if ( '' === $file ) { return new WP_Error( 'bongoto_no_home_json', 'Home JSON not selected.' ); } // Resolve title from manifest item name, fallback to filename. $title = basename( $file, '.json' ); $homes = $manifest['elementor']['home_pages'] ?? []; if ( is_array( $homes ) ) { foreach ( $homes as $item ) { $ifile = isset( $item['file'] ) ? ltrim( (string) $item['file'], '/' ) : ''; if ( $ifile === $file ) { $iname = isset( $item['name'] ) ? (string) $item['name'] : ''; if ( '' !== $iname ) { $title = $iname; } break; } } } // Prefer local synced JSON inside theme (avoid remote fetch flakiness). $body = ''; $local = bongoto_woo_local_demo_file( $file ); if ( file_exists( $local ) ) { $body = (string) file_get_contents( $local ); } else { $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); $url = $base_url . $file; $resp = wp_remote_get( $url, [ 'timeout' => 25, 'user-agent' => 'WordPress/' . get_bloginfo( 'version' ) . '; ' . home_url( '/' ), ] ); if ( is_wp_error( $resp ) ) { return new WP_Error( 'bongoto_home_download_failed', 'Failed to download home JSON. ' . $resp->get_error_message() ); } $code = (int) wp_remote_retrieve_response_code( $resp ); $body = (string) wp_remote_retrieve_body( $resp ); if ( 200 !== $code || '' === $body ) { return new WP_Error( 'bongoto_home_download_failed', sprintf( 'Failed to download home JSON. (HTTP %d) %s', $code, esc_url_raw( $url ) ) ); } } if ( 0 === strpos( $body, "\xEF\xBB\xBF" ) ) { $body = substr( $body, 3 ); } $body = preg_replace('/^\xEF\xBB\xBF/', '', (string) $body ); $data = json_decode( $body, true ); if ( ! is_array( $data ) ) { return new WP_Error( 'bongoto_home_json_invalid', 'Home JSON is not valid JSON.' ); } $content = null; if ( isset( $data['content'] ) && is_array( $data['content'] ) ) { $content = $data['content']; } elseif ( isset( $data[0] ) && is_array( $data[0] ) ) { $content = $data; } if ( ! is_array( $content ) || empty( $content ) ) { return new WP_Error( 'bongoto_home_no_content', 'Home JSON does not contain content.' ); } $page_settings = []; if ( isset( $data['page_settings'] ) && is_array( $data['page_settings'] ) ) { $page_settings = $data['page_settings']; } elseif ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) { $page_settings = $data['settings']; } // Trace the source file for support. $data['file'] = $file; $page_id = bongoto_woo_upsert_home_page( $title, $content, $page_settings, $data ); if ( is_wp_error( $page_id ) ) { return $page_id; } // This method is used for the selected front page home. update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', (int) $page_id ); return (int) $page_id; } function bongoto_woo_sync_demo_folder_to_theme( array $manifest, string $demo_slug = 'bongoto-woocommerce' ) { $base_url = trailingslashit( dirname( BONGOTO_DEMO_MANIFEST_URL ) ); $root = bongoto_woo_local_demo_root( $demo_slug ); // Ensure base dirs. wp_mkdir_p( $root ); $files = []; // Save manifest for debugging/preview. $files[] = 'manifest.json'; // Elementor home pages $homes = $manifest['elementor']['home_pages'] ?? []; if ( is_array( $homes ) ) { foreach ( $homes as $h ) { if ( ! empty( $h['file'] ) ) $files[] = (string) $h['file']; } } // Headers $headers = $manifest['headers'] ?? []; if ( is_array( $headers ) ) { foreach ( $headers as $h ) { if ( ! empty( $h['file'] ) ) $files[] = (string) $h['file']; } } // Shared header partials (Topbar) - these may not be listed in manifest.headers // but are required by header-2..5 templates. // NOTE: We do not download PHP or .htaccess from remote servers. foreach ( array( 'headers/topbar.css' ) as $extra ) { $files[] = $extra; } // Presets/customizer (optional) $presets = $manifest['presets']['customizer'] ?? []; if ( is_array( $presets ) ) { foreach ( $presets as $p ) { if ( ! empty( $p['file'] ) ) $files[] = (string) $p['file']; } } // Colors (maps to presets/*.json usually) $colors = $manifest['colors'] ?? []; if ( is_array( $colors ) ) { foreach ( $colors as $c ) { if ( ! empty( $c['file'] ) ) $files[] = (string) $c['file']; } } // Keep only safe file types. $files = array_values( array_filter( $files, function( $f ) { $f = (string) $f; if ( 'manifest.json' === $f ) return true; return bongoto_woo_demo_is_allowed_file( $f ); } ) ); $files = array_values( array_unique( array_filter( array_map( function( $f ) { $f = ltrim( (string) $f, '/' ); return $f; }, $files ) ) ) ); // Write manifest.json locally $manifest_local = $root . 'manifest.json'; bongoto_woo_fs_put_contents( $manifest_local, wp_json_encode( $manifest, JSON_PRETTY_PRINT ) ); foreach ( $files as $rel ) { // Safety: never download executable/config files. if ( 'manifest.json' !== $rel && ! bongoto_woo_demo_is_allowed_file( (string) $rel ) ) { continue; } if ( 'manifest.json' === $rel ) continue; $dest = bongoto_woo_local_demo_file( $rel, $demo_slug ); $dir = trailingslashit( dirname( $dest ) ); wp_mkdir_p( $dir ); // If already exists, keep it (avoid overwriting manual edits). if ( file_exists( $dest ) ) { continue; } $url = $base_url . $rel; $resp = wp_remote_get( $url, [ 'timeout' => 25 ] ); if ( is_wp_error( $resp ) ) { continue; } $code = (int) wp_remote_retrieve_response_code( $resp ); $body = (string) wp_remote_retrieve_body( $resp ); if ( 200 !== $code || '' === $body ) { continue; } bongoto_woo_fs_put_contents( $dest, $body ); } return true; } /** * Import an Elementor JSON export from a local file path (Theme-shipped or already downloaded). */ function bongoto_woo_import_home_from_local_json_file( string $json_path, string $title = 'Home 01', bool $set_front = false ) { if ( ! bongoto_woo_is_elementor_active() ) { return new WP_Error( 'bongoto_no_elementor', 'Elementor is not active.' ); } if ( ! file_exists( $json_path ) ) { return new WP_Error( 'bongoto_home_missing', 'Home JSON file not found.' ); } $body = (string) file_get_contents( $json_path ); if ( 0 === strpos( $body, "\xEF\xBB\xBF" ) ) { $body = substr( $body, 3 ); } $body = preg_replace('/^\xEF\xBB\xBF/', '', (string) $body ); $data = json_decode( $body, true ); if ( ! is_array( $data ) ) { return new WP_Error( 'bongoto_home_json_invalid', 'Home JSON is not valid JSON.' ); } $content = null; if ( isset( $data['content'] ) && is_array( $data['content'] ) ) { $content = $data['content']; } elseif ( isset( $data[0] ) && is_array( $data[0] ) ) { $content = $data; } if ( ! is_array( $content ) || empty( $content ) ) { return new WP_Error( 'bongoto_home_no_content', 'Home JSON does not contain content.' ); } $page_settings = []; if ( isset( $data['page_settings'] ) && is_array( $data['page_settings'] ) ) { $page_settings = $data['page_settings']; } elseif ( isset( $data['settings'] ) && is_array( $data['settings'] ) ) { $page_settings = $data['settings']; } // Trace source for support. $data['file'] = basename( $json_path ); $page_id = bongoto_woo_upsert_home_page( $title, $content, $page_settings, $data ); if ( is_wp_error( $page_id ) ) { return $page_id; } if ( $set_front ) { update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', (int) $page_id ); } return (int) $page_id; }