'page', 'post_status' => 'any', 'posts_per_page' => 1, 'meta_key' => '_bongoto_minimal_home', 'meta_value' => '1', ] ); if ( ! empty( $existing ) && ! empty( $existing[0]->ID ) ) { $home_id = (int) $existing[0]->ID; } $setup_url = admin_url( 'admin.php?page=bongoto-shop-setup' ); $content = ''; $content .= '

' . esc_html__( 'Welcome to Bongoto Shop', 'bongoto-shop' ) . '

'; $content .= '

' . esc_html__( 'Your site is ready. To use a demo design, run the Quick Setup import.', 'bongoto-shop' ) . '

'; $content .= '

' . esc_html__( 'Run Quick Setup', 'bongoto-shop' ) . '

'; if ( $home_id > 0 ) { wp_update_post( [ 'ID' => $home_id, 'post_title' => 'Welcome Home Page', 'post_name' => 'welcome-home-page', 'post_content' => $content, ] ); update_post_meta( $home_id, '_bongoto_minimal_home', '1' ); } else { $home_id = (int) wp_insert_post( [ 'post_type' => 'page', 'post_status' => 'publish', 'post_title' => 'Welcome Home Page', 'post_name' => 'welcome-home-page', 'post_content' => $content, ] ); if ( $home_id > 0 ) { update_post_meta( $home_id, '_bongoto_minimal_home', '1' ); } } if ( $home_id > 0 ) { update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', $home_id ); // Keep posts page unset for a clean default. update_option( 'page_for_posts', 0 ); } } ); /** * Dismiss handler for the setup notice. */ add_action( 'admin_init', function () { // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( isset( $_GET['bongoto-shop-dismiss'] ) && check_admin_referer( 'bongoto_shop_dismiss' ) ) { delete_transient( 'bongoto_shop_show_setup' ); } } ); /* ------------------------------------------------------------------------- * 4) Helpers * ------------------------------------------------------------------------- */ /** * Check if the Bongoto WC Add-On plugin is active. * * This checks the plugin folder/file: * bongoto-wc-premium/bongoto-wc-premium.php * * License gating is handled entirely inside the plugin; * the theme only cares if the premium plugin itself is active. */ if ( ! function_exists( 'bongoto_shop_is_pro_active' ) ) { function bongoto_shop_is_pro_active() { include_once ABSPATH . 'wp-admin/includes/plugin.php'; $active = false; if ( function_exists( 'is_plugin_active' ) ) { if ( is_plugin_active( 'bongoto-wc-premium/bongoto-wc-premium.php' ) ) { $active = true; } } /** * Filter whether the Bongoto Shop Addon is active. * * @param bool $active Whether the premium is active. */ return (bool) apply_filters( 'bongoto_shop/is_pro_active', $active ); } } /** * Check if Elementor is available. * * @return bool */ function bongoto_shop_is_elementor() { return class_exists( '\Elementor\Plugin' ); } /** * Check if WooCommerce is available. * * @return bool */ function bongoto_shop_is_woo() { return function_exists( 'WC' ); } /* ------------------------------------------------------------------------- * 5) Feature Locks (Footer credit, Header variants) * ------------------------------------------------------------------------- */ /** * Filter footer credit. * Free users see a locked credit, premium users can override via filters. */ add_filter( 'bongoto_shop_footer_credit', function ( $credit ) { if ( ! bongoto_shop_is_pro_active() ) { $credit = sprintf( /* translators: %s: site name */ esc_html__( '© %s — Powered by Bongoto Shop', 'bongoto-shop' ), get_bloginfo( 'name' ) ); } return $credit; } ); /** * Header variant whitelist for Customizer/UI. * Free: 1; Add-On active: 1–5. */ add_filter( 'bongoto_shop/header/allowed_variants', function ( $allowed ) { return bongoto_shop_is_pro_active() ? array( 1, 2, 3, 4, 5 ) : array( 1 ); } ); /* ------------------------------------------------------------------------- * 6) Utility: version for static files * ------------------------------------------------------------------------- */ /** * Return a version string for static files based on filemtime. * * @param string $relative_path Relative path from the theme directory. * @return string */ if ( ! function_exists( 'bongoto_shop_file_version' ) ) { function bongoto_shop_file_version( $relative_path ) { $path = BONGOTO_SHOP_DIR . ltrim( $relative_path, '/' ); return file_exists( $path ) ? (string) filemtime( $path ) : BONGOTO_SHOP_VERSION; } } /* ------------------------------------------------------------------------- * 7) Full theme setup * ------------------------------------------------------------------------- */ /** * Theme setup: supports, image sizes, menus, etc. */ if ( ! function_exists( 'bongoto_shop_setup' ) ) { function bongoto_shop_setup() { load_theme_textdomain( 'bongoto-shop', BONGOTO_SHOP_DIR . 'languages' ); add_theme_support( 'title-tag' ); add_theme_support( 'post-thumbnails' ); add_image_size( 'bongoto-thumb', 540, 360, true ); add_image_size( 'bongoto-card', 720, 480, true ); add_theme_support( 'custom-logo', array( 'height' => 80, 'width' => 240, 'flex-height' => true, 'flex-width' => true, ) ); add_theme_support( 'html5', array( 'search-form', 'comment-form', 'comment-list', 'gallery', 'caption', 'script', 'style', 'navigation-widgets', ) ); add_theme_support( 'wp-block-styles' ); add_theme_support( 'editor-styles' ); add_editor_style( 'assets/css/main.css' ); add_theme_support( 'align-wide' ); add_theme_support( 'responsive-embeds' ); add_theme_support( 'woocommerce' ); add_theme_support( 'automatic-feed-links' ); add_theme_support( 'custom-background' ); add_theme_support( 'custom-header' ); register_nav_menus( array( 'primary' => __( 'Primary Menu', 'bongoto-shop' ), 'footer' => __( 'Footer Menu', 'bongoto-shop' ), 'topbar' => __( 'Top Bar Menu', 'bongoto-shop' ), ) ); } } add_action( 'after_setup_theme', 'bongoto_shop_setup' ); /** * Global content width. */ if ( ! isset( $content_width ) ) { // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound $content_width = 720; } /* ------------------------------------------------------------------------- * 8) Widgets * ------------------------------------------------------------------------- */ /** * Register widget areas. */ function bongoto_shop_widgets_init() { for ( $i = 1; $i <= 4; $i++ ) { register_sidebar( array( /* translators: %d: footer column number */ 'name' => sprintf( __( 'Footer Column %d', 'bongoto-shop' ), $i ), 'id' => "footer-$i", 'description' => __( 'Add widgets here to appear in the footer.', 'bongoto-shop' ), 'before_widget' => '
', 'after_widget' => '
', 'before_title' => '

', 'after_title' => '

', ) ); } register_sidebar( array( 'name' => __( 'Sidebar', 'bongoto-shop' ), 'id' => 'sidebar-1', 'description' => __( 'Add widgets here for posts and pages.', 'bongoto-shop' ), 'before_widget' => '
', 'after_widget' => '
', 'before_title' => '

', 'after_title' => '

', ) ); register_sidebar( array( 'name' => __( 'Shop Sidebar', 'bongoto-shop' ), 'id' => 'shop-sidebar', 'description' => __( 'Widgets shown on WooCommerce shop and product archive pages.', 'bongoto-shop' ), 'before_widget' => '
', 'after_widget' => '
', 'before_title' => '

', 'after_title' => '

', ) ); } add_action( 'widgets_init', 'bongoto_shop_widgets_init' ); /* ------------------------------------------------------------------------- * 9) Body Classes * ------------------------------------------------------------------------- */ /** * Add theme-specific classes to the tag. * * @param string[] $classes Existing body classes. * @return string[] */ function bongoto_shop_body_class( $classes ) { $classes[] = bongoto_shop_is_pro_active() ? 'bongoto-shop-pro-active' : 'bongoto-shop-free'; if ( class_exists( 'WooCommerce' ) ) { $classes[] = 'has-woocommerce'; } return $classes; } add_filter( 'body_class', 'bongoto_shop_body_class' ); /* ------------------------------------------------------------------------- * 10) Includes * ------------------------------------------------------------------------- */ /** * Core includes for the theme. */ $includes = array( 'inc/setup.php', 'inc/assets.php', 'inc/template-functions.php', 'inc/hooks.php', 'inc/security.php', 'inc/demo-setup.php', 'inc/admin/welcome.php', 'inc/customizer/customizer.php', 'inc/customizer/sanitize.php', 'inc/customizer/options-header.php', 'inc/customizer/options-footer.php', 'inc/customizer/options-containers.php', 'inc/customizer/options-homepage.php', 'inc/customizer/controls/class-sortable-control.php', 'inc/class-bongoto-shop-header-manager.php', 'inc/class-bongoto-shop-footer-manager.php', 'inc/compatibility/elementor.php', 'inc/compatibility/woocommerce.php', // Standalone modules previously embedded in functions.php. 'inc/orientation-images.php', 'inc/image-origin-marker.php', 'inc/preloader.php', ); foreach ( $includes as $rel ) { $path = BONGOTO_SHOP_DIR . ltrim( $rel, '/' ); if ( file_exists( $path ) ) { require_once $path; } } /* ------------------------------------------------------------------------- * 11) Search Form Fallback Helper * ------------------------------------------------------------------------- */ /** * Wrapper around get_template_part( 'searchform' ). * * @param bool $echo Whether to echo or return the form. * @return string|null */ function bongoto_shop_get_search_form( $echo = true ) { ob_start(); get_template_part( 'searchform' ); $form = ob_get_clean(); if ( $echo ) { // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped echo $form; return null; } return $form; } /* ------------------------------------------------------------------------- * 12) Simple Ajax placeholder * ------------------------------------------------------------------------- */ /** * Simple AJAX endpoint for basic connectivity tests. */ function bongoto_shop_ajax_placeholder() { wp_send_json_success( array( 'message' => __( 'OK', 'bongoto-shop' ), ) ); } add_action( 'wp_ajax_bongoto_ping', 'bongoto_shop_ajax_placeholder' ); add_action( 'wp_ajax_nopriv_bongoto_ping', 'bongoto_shop_ajax_placeholder' ); /* ------------------------------------------------------------------------- * 13) WooCommerce tweaks * ------------------------------------------------------------------------- */ /** * Products per row in the shop loop. */ add_filter( 'loop_shop_columns', function () { return 4; } ); /** * Products per page in the shop loop. */ add_filter( 'loop_shop_per_page', function ( $cols ) { // phpcs:ignore VariableAnalysis.CodeAnalysis.VariableAnalysis.UnusedVariable return 16; }, 20 ); /** * Default catalog order: latest products first. */ add_filter( 'woocommerce_default_catalog_orderby', function () { return 'date'; } ); /** * Force front-end search to only search products. */ add_action( 'pre_get_posts', function ( $query ) { if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) { $query->set( 'post_type', 'product' ); } } ); /** * Mark free products (price 0) as always purchasable. */ add_filter( 'woocommerce_is_purchasable', function ( $purchasable, $product ) { if ( (float) $product->get_price() === 0.0 ) { return true; } return $purchasable; }, 999, 2 ); /** * Replace "Read more" button with "Free Download" for free products in loops. */ add_filter( 'woocommerce_loop_add_to_cart_link', function ( $button, $product ) { if ( (float) $product->get_price() === 0.0 ) { $url = get_permalink( $product->get_id() ); $button = '' . esc_html__( 'Free Download', 'bongoto-shop' ) . ''; } return $button; }, 999, 2 ); /* ------------------------------------------------------------------------- * 14) Elementor Home auto-import (JSON under assets/elementor/) * ------------------------------------------------------------------------- */ /** * Get the absolute path to the default demo JSON (Elementor layout). * * @return string */ function bongoto_shop_home_json_path() { $file = BONGOTO_SHOP_DIR . 'assets/elementor/bongoto-shop-home.json'; return file_exists( $file ) ? $file : ''; } /** * Normalize Elementor JSON data: * - Convert /assets/... paths to absolute URLs. * - Fallback search widget to a shortcode if Elementor Pro is missing. * * @param string $json Raw JSON string. * @return string Normalized JSON string. */ function bongoto_shop_normalize_elementor_json( $json ) { $data = json_decode( $json, true ); if ( JSON_ERROR_NONE !== json_last_error() || ! is_array( $data ) ) { return $json; } $theme_uri = BONGOTO_SHOP_URI; $walk = static function ( &$node ) use ( &$walk, $theme_uri ) { // Single image URL. if ( isset( $node['settings']['image']['url'] ) && is_string( $node['settings']['image']['url'] ) ) { $u = $node['settings']['image']['url']; if ( 0 === strpos( $u, '/assets/' ) ) { $node['settings']['image']['url'] = $theme_uri . ltrim( $u, '/' ); } } // Slides images. if ( isset( $node['settings']['slides'] ) && is_array( $node['settings']['slides'] ) ) { foreach ( $node['settings']['slides'] as &$slide ) { if ( isset( $slide['image']['url'] ) && is_string( $slide['image']['url'] ) ) { $u = $slide['image']['url']; if ( 0 === strpos( $u, '/assets/' ) ) { $slide['image']['url'] = $theme_uri . ltrim( $u, '/' ); } } } unset( $slide ); } // Elementor Pro search-form → shortcode fallback. if ( isset( $node['widgetType'] ) && 'search-form' === $node['widgetType'] && ! class_exists( '\ElementorPro\Plugin' ) ) { $node['widgetType'] = 'shortcode'; $node['settings'] = array( 'shortcode' => function_exists( 'WC' ) ? '[woocommerce_product_search]' : '[bongoto_search]', 'align' => $node['settings']['align'] ?? 'center', ); } // Recurse into children. if ( isset( $node['elements'] ) && is_array( $node['elements'] ) ) { foreach ( $node['elements'] as &$child ) { $walk( $child ); } unset( $child ); } }; foreach ( $data as &$root ) { $walk( $root ); } unset( $root ); return wp_json_encode( $data ); } /** * Import the demo JSON into a "Home" page and set it as the front page. * * @return int|\WP_Error Page ID or error. */ function bongoto_shop_import_home_from_json() { $path = bongoto_shop_home_json_path(); if ( ! $path ) { return new WP_Error( 'missing_json', __( 'Home JSON file not found.', 'bongoto-shop' ) ); } $json = file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents if ( '' === trim( (string) $json ) ) { return new WP_Error( 'empty_json', __( 'Home JSON file is empty.', 'bongoto-shop' ) ); } $json = bongoto_shop_normalize_elementor_json( $json ); $page = get_page_by_title( 'Welcome Home Page' ); $page_id = ( $page && $page->ID ) ? (int) $page->ID : 0; if ( ! $page_id ) { $page_id = wp_insert_post( array( 'post_title' => 'Welcome Home Page', 'post_name' => 'welcome-home-page', 'post_type' => 'page', 'post_status' => 'publish', ) ); if ( is_wp_error( $page_id ) ) { return $page_id; } } if ( bongoto_shop_is_elementor() ) { update_post_meta( $page_id, '_elementor_edit_mode', 'builder' ); update_post_meta( $page_id, '_elementor_template_type', 'wp-page' ); update_post_meta( $page_id, '_elementor_data', wp_slash( $json ) ); wp_update_post( array( 'ID' => $page_id, 'post_content' => '', ) ); } else { $placeholder = '
' . esc_html__( 'Please install or activate Elementor to render the Bongoto Shop home layout.', 'bongoto-shop' ) . '
'; wp_update_post( array( 'ID' => $page_id, 'post_content' => $placeholder, ) ); } update_option( 'show_on_front', 'page' ); update_option( 'page_on_front', $page_id ); // Mark this as the minimal welcome page. update_post_meta( $page_id, '_bongoto_minimal_home', '1' ); // Optional lock meta for free users (used by the premium if needed). if ( ! bongoto_shop_is_pro_active() ) { update_post_meta( $page_id, '_bongoto_locked', '1' ); } else { delete_post_meta( $page_id, '_bongoto_locked' ); } return $page_id; } /** * On first activation only (if no front page is set), import the home layout. */ add_action( 'after_switch_theme', function () { if ( 'page' === get_option( 'show_on_front' ) && get_option( 'page_on_front' ) ) { return; } bongoto_shop_import_home_from_json(); } ); /* ------------------------------------------------------------------------- * 16) Admin menu (Theme screen submenu; Theme-Review safe) * ------------------------------------------------------------------------- */ /** * Add a Theme page for Bongoto Shop Setup. */ /* ------------------------------------------------------------------------- * 17) Comments helpers * ------------------------------------------------------------------------- */ /** * Enqueue comment reply script when needed. */ add_action( 'wp_enqueue_scripts', function () { if ( is_singular() && comments_open() && get_option( 'thread_comments' ) ) { wp_enqueue_script( 'comment-reply' ); } } ); /** * Simple comments callback. */ if ( ! function_exists( 'bongoto_shop_list_comments' ) ) { function bongoto_shop_list_comments( $comment, $args, $depth ) { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.Found $GLOBALS['comment'] = $comment; // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited ?>
  • id="li-comment-">
  • 'bongoto-shop-buttons-rounded', 'label' => __( 'Rounded', 'bongoto-shop' ), ) ); } /*=========================================================================*/ // Checkout Page CSS /*=========================================================================*/ add_action('wp_enqueue_scripts', function () { if ( is_checkout() && ! is_order_received_page() ) { wp_enqueue_style( 'bongoto-checkout', get_stylesheet_directory_uri() . '/assets/css/checkout.css', array(), '1.0.0' ); } }, 20); /*===========================================*/ // Bongoto integrated license + demo tools (no separate plugin) require_once __DIR__ . '/inc/core/license-client.php'; if ( is_admin() ) { // Keep license status fresh in wp-admin. add_action( 'admin_init', 'bongoto_shop_maybe_refresh_license_status' ); require_once __DIR__ . '/inc/admin/shims.php'; require_once __DIR__ . '/inc/admin/menu.php'; require_once __DIR__ . '/inc/admin/license-page.php'; require_once __DIR__ . '/inc/admin/actions.php'; require_once __DIR__ . '/inc/admin/assets.php'; } require_once __DIR__ . '/inc/core/extra-headers-loader.php'; // Demo importer contains helper functions (e.g. topbar CSS gate) that are used on frontend too. require_once __DIR__ . '/inc/core/demo-importer.php'; // Bongoto Colors (single menu) require_once __DIR__ . '/inc/customizer/colors.php'; require_once __DIR__ . '/inc/core/colors-css.php'; require_once __DIR__ . '/inc/core/copyright-gate.php'; /*==========================================================================================*/ /** * Quick Setup notice (Themes screen only). Shows after activation until setup is complete. */ add_action( 'admin_notices', function () { if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) { return; } // Show ONLY on Appearance → Themes (themes.php) if ( function_exists( 'get_current_screen' ) ) { $screen = get_current_screen(); if ( ! $screen || 'themes' !== $screen->id ) { return; } } // ---- Setup complete rules (all must be true to stop showing) ---- $license_active = (bool) get_option( 'bongoto_premium_active', false ); $import_done = (bool) get_option( 'bongoto_shop_import_completed', false ) || (bool) get_option( 'bongoto_demo_import_completed', false ); $front_is_page = ( 'page' === get_option( 'show_on_front' ) ); $front_page_id = (int) get_option( 'page_on_front', 0 ); $home_ready = ( $front_is_page && $front_page_id > 0 ); // If setup complete, stop and clear transient. if ( $license_active && $import_done && $home_ready ) { delete_transient( 'bongoto_shop_show_setup_notice' ); return; } // ---- Dismiss handler ---- // phpcs:ignore WordPress.Security.NonceVerification.Recommended $dismiss = isset( $_GET['bongoto_shop_dismiss_setup_notice'] ) ? absint( $_GET['bongoto_shop_dismiss_setup_notice'] ) : 0; if ( $dismiss ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended $nonce = isset( $_GET['_bongoto_nonce'] ) ? sanitize_text_field( wp_unslash( $_GET['_bongoto_nonce'] ) ) : ''; if ( $nonce && wp_verify_nonce( $nonce, 'bongoto_shop_dismiss_setup_notice' ) ) { delete_transient( 'bongoto_shop_show_setup_notice' ); wp_safe_redirect( remove_query_arg( array( 'bongoto_shop_dismiss_setup_notice', '_bongoto_nonce' ) ) ); exit; } } // ---- When to show ---- // Show if activation transient exists OR immediately after activation redirect. $should_show = (bool) get_transient( 'bongoto_shop_show_setup_notice' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended if ( ! $should_show && empty( $_GET['activated'] ) ) { return; } $setup_url = admin_url( 'admin.php?page=bongoto-shop-setup' ); $dismiss_url = wp_nonce_url( add_query_arg( 'bongoto_shop_dismiss_setup_notice', 1 ), 'bongoto_shop_dismiss_setup_notice', '_bongoto_nonce' ); echo '
    '; echo '

    ' . esc_html__( 'Bongoto Shop — Quick Setup', 'bongoto-shop' ) . '

    '; echo '

    ' . esc_html__( 'Complete setup: activate license, import the demo, and ensure the Home page is set as the front page.', 'bongoto-shop' ) . '

    '; echo '

    ' . esc_html__( 'Open Setup', 'bongoto-shop' ) . ' '; echo '' . esc_html__( 'Dismiss', 'bongoto-shop' ) . '

    '; echo '
    '; }, 5 ); /*=================================================================*/