456 lines
17 KiB
PHP
456 lines
17 KiB
PHP
<?php
|
|
namespace WooNooW\Frontend;
|
|
|
|
/**
|
|
* Frontend Assets Manager
|
|
* Handles loading of customer-spa assets
|
|
*/
|
|
class Assets {
|
|
|
|
/**
|
|
* Initialize
|
|
*/
|
|
public static function init() {
|
|
add_action('wp_enqueue_scripts', [self::class, 'enqueue_assets'], 20);
|
|
add_action('wp_head', [self::class, 'add_inline_config'], 5);
|
|
add_action('wp_enqueue_scripts', [self::class, 'dequeue_conflicting_scripts'], 100);
|
|
add_filter('script_loader_tag', [self::class, 'add_module_type'], 10, 3);
|
|
add_action('woocommerce_before_main_content', [self::class, 'inject_spa_mount_point'], 5);
|
|
}
|
|
|
|
/**
|
|
* Add type="module" to customer-spa scripts
|
|
*/
|
|
public static function add_module_type($tag, $handle, $src) {
|
|
// Add type="module" to our Vite scripts
|
|
if (strpos($handle, 'woonoow-customer') !== false) {
|
|
$tag = str_replace('<script ', '<script type="module" ', $tag);
|
|
}
|
|
return $tag;
|
|
}
|
|
|
|
/**
|
|
* Enqueue customer-spa assets
|
|
*/
|
|
public static function enqueue_assets() {
|
|
// Only load on pages with WooNooW shortcodes or in full SPA mode
|
|
if (!self::should_load_assets()) {
|
|
return;
|
|
}
|
|
|
|
// Check if dev mode is enabled
|
|
$is_dev = defined('WOONOOW_CUSTOMER_DEV') && WOONOOW_CUSTOMER_DEV;
|
|
|
|
if ($is_dev) {
|
|
// Dev mode: Load from Vite dev server
|
|
$dev_server = 'https://woonoow.local:5174';
|
|
|
|
// Vite client for HMR
|
|
wp_enqueue_script(
|
|
'woonoow-customer-vite',
|
|
$dev_server . '/@vite/client',
|
|
[],
|
|
null,
|
|
false // Load in header
|
|
);
|
|
|
|
// Main entry point
|
|
wp_enqueue_script(
|
|
'woonoow-customer-spa',
|
|
$dev_server . '/src/main.tsx',
|
|
['woonoow-customer-vite'],
|
|
null,
|
|
false // Load in header
|
|
);
|
|
} else {
|
|
// Production mode: Load from build
|
|
$plugin_url = plugin_dir_url(dirname(dirname(__FILE__)));
|
|
$dist_path = plugin_dir_path(dirname(dirname(__FILE__))) . 'customer-spa/dist/';
|
|
|
|
// Check if build exists
|
|
if (!file_exists($dist_path)) {
|
|
return;
|
|
}
|
|
|
|
// Production build - load app.js and app.css directly
|
|
$js_url = $plugin_url . 'customer-spa/dist/app.js';
|
|
$css_url = $plugin_url . 'customer-spa/dist/app.css';
|
|
|
|
wp_enqueue_script(
|
|
'woonoow-customer-spa',
|
|
$js_url,
|
|
[],
|
|
null,
|
|
true
|
|
);
|
|
|
|
// Add type="module" for Vite build
|
|
add_filter('script_loader_tag', function($tag, $handle, $src) {
|
|
if ($handle === 'woonoow-customer-spa') {
|
|
$tag = str_replace('<script ', '<script type="module" ', $tag);
|
|
}
|
|
return $tag;
|
|
}, 10, 3);
|
|
|
|
wp_enqueue_style(
|
|
'woonoow-customer-spa',
|
|
$css_url,
|
|
[],
|
|
null
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Inject SPA mounting point for full mode
|
|
*/
|
|
public static function inject_spa_mount_point() {
|
|
if (!self::should_load_assets()) {
|
|
return;
|
|
}
|
|
|
|
// Check if we're in full mode and not on a page with shortcode
|
|
$spa_settings = get_option('woonoow_customer_spa_settings', []);
|
|
$mode = isset($spa_settings['mode']) ? $spa_settings['mode'] : 'disabled';
|
|
|
|
if ($mode === 'full') {
|
|
// Only inject if the mount point doesn't already exist (from shortcode)
|
|
echo '<div id="woonoow-customer-app" data-page="shop"><div class="woonoow-loading"><p>Loading...</p></div></div>';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Add inline config and scripts to page head
|
|
*/
|
|
public static function add_inline_config() {
|
|
if (!self::should_load_assets()) {
|
|
return;
|
|
}
|
|
|
|
// Get Customer SPA settings
|
|
$spa_settings = get_option('woonoow_customer_spa_settings', []);
|
|
$default_settings = [
|
|
'mode' => 'disabled',
|
|
'layout' => 'modern',
|
|
'colors' => [
|
|
'primary' => get_option('woonoow_primary_color', '#111827'), // Gray-900 from Store Details
|
|
'secondary' => '#6B7280', // Gray-500
|
|
'accent' => '#10B981',
|
|
],
|
|
'typography' => [
|
|
'preset' => 'professional',
|
|
],
|
|
];
|
|
$theme_settings = array_replace_recursive($default_settings, $spa_settings);
|
|
|
|
// Get appearance settings and preload them
|
|
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
|
if (empty($appearance_settings)) {
|
|
// Use defaults from AppearanceController
|
|
$appearance_settings = \WooNooW\Admin\AppearanceController::get_default_settings();
|
|
}
|
|
|
|
// Get WooCommerce currency settings
|
|
$currency_settings = [
|
|
'code' => get_woocommerce_currency(),
|
|
'symbol' => get_woocommerce_currency_symbol(),
|
|
'position' => get_option('woocommerce_currency_pos', 'left'),
|
|
'thousandSeparator' => wc_get_price_thousand_separator(),
|
|
'decimalSeparator' => wc_get_price_decimal_separator(),
|
|
'decimals' => wc_get_price_decimals(),
|
|
];
|
|
|
|
// Get store logo from WooNooW Store Details (Settings > Store Details)
|
|
$logo_url = get_option('woonoow_store_logo', '');
|
|
|
|
// Get user billing/shipping data if logged in
|
|
$user_data = [
|
|
'isLoggedIn' => is_user_logged_in(),
|
|
'id' => get_current_user_id(),
|
|
];
|
|
|
|
if (is_user_logged_in()) {
|
|
$customer = new \WC_Customer(get_current_user_id());
|
|
$user_data['email'] = $customer->get_email();
|
|
$user_data['billing'] = [
|
|
'first_name' => $customer->get_billing_first_name(),
|
|
'last_name' => $customer->get_billing_last_name(),
|
|
'email' => $customer->get_billing_email(),
|
|
'phone' => $customer->get_billing_phone(),
|
|
'address_1' => $customer->get_billing_address_1(),
|
|
'city' => $customer->get_billing_city(),
|
|
'state' => $customer->get_billing_state(),
|
|
'postcode' => $customer->get_billing_postcode(),
|
|
'country' => $customer->get_billing_country(),
|
|
];
|
|
$user_data['shipping'] = [
|
|
'first_name' => $customer->get_shipping_first_name(),
|
|
'last_name' => $customer->get_shipping_last_name(),
|
|
'address_1' => $customer->get_shipping_address_1(),
|
|
'city' => $customer->get_shipping_city(),
|
|
'state' => $customer->get_shipping_state(),
|
|
'postcode' => $customer->get_shipping_postcode(),
|
|
'country' => $customer->get_shipping_country(),
|
|
];
|
|
}
|
|
|
|
// Determine SPA base path for BrowserRouter
|
|
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
|
$spa_page = $spa_page_id ? get_post($spa_page_id) : null;
|
|
|
|
// Check if SPA page is set as WordPress frontpage
|
|
$frontpage_id = (int) get_option('page_on_front');
|
|
$is_spa_frontpage = $frontpage_id && $spa_page_id && $frontpage_id === (int) $spa_page_id;
|
|
|
|
// If SPA is frontpage, base path is /, otherwise use page slug
|
|
$base_path = $is_spa_frontpage ? '' : ($spa_page ? '/' . $spa_page->post_name : '/store');
|
|
|
|
// Check if BrowserRouter is enabled (default: true for SEO)
|
|
$use_browser_router = $appearance_settings['general']['use_browser_router'] ?? true;
|
|
|
|
$config = [
|
|
'apiUrl' => rest_url('woonoow/v1'),
|
|
'apiRoot' => rest_url('woonoow/v1'),
|
|
'nonce' => wp_create_nonce('wp_rest'),
|
|
'siteUrl' => get_site_url(),
|
|
'siteTitle' => get_bloginfo('name'),
|
|
'siteName' => get_bloginfo('name'),
|
|
'storeName' => get_bloginfo('name'),
|
|
'storeLogo' => $logo_url,
|
|
'user' => $user_data,
|
|
'theme' => $theme_settings,
|
|
'currency' => $currency_settings,
|
|
'appearanceSettings' => $appearance_settings,
|
|
'basePath' => $base_path,
|
|
'useBrowserRouter' => $use_browser_router,
|
|
];
|
|
|
|
?>
|
|
<script type="text/javascript">
|
|
window.woonoowCustomer = <?php echo wp_json_encode($config); ?>;
|
|
</script>
|
|
<?php
|
|
|
|
// If dev mode, output scripts directly
|
|
$is_dev = defined('WOONOOW_CUSTOMER_DEV') && WOONOOW_CUSTOMER_DEV;
|
|
if ($is_dev) {
|
|
$dev_server = 'https://woonoow.local:5174';
|
|
?>
|
|
<script type="module">
|
|
import RefreshRuntime from '<?php echo $dev_server; ?>/@react-refresh'
|
|
RefreshRuntime.injectIntoGlobalHook(window)
|
|
window.$RefreshReg$ = () => {}
|
|
window.$RefreshSig$ = () => (type) => type
|
|
window.__vite_plugin_react_preamble_installed__ = true
|
|
</script>
|
|
<script type="module" crossorigin src="<?php echo $dev_server; ?>/@vite/client"></script>
|
|
<script type="module" crossorigin src="<?php echo $dev_server; ?>/src/main.tsx"></script>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Check if we should load customer-spa assets
|
|
*/
|
|
private static function should_load_assets() {
|
|
global $post;
|
|
|
|
// Check if we're serving SPA directly (set by serve_spa_for_frontpage_routes)
|
|
if (defined('WOONOOW_SERVE_SPA') && WOONOOW_SERVE_SPA) {
|
|
return true;
|
|
}
|
|
|
|
// Check if we're on a frontpage SPA route (by URL detection)
|
|
if (self::is_frontpage_spa_route()) {
|
|
return true;
|
|
}
|
|
|
|
// First check: Is this a designated SPA page?
|
|
if (self::is_spa_page()) {
|
|
return true;
|
|
}
|
|
|
|
// Get Customer SPA settings
|
|
$spa_settings = get_option('woonoow_customer_spa_settings', []);
|
|
$mode = isset($spa_settings['mode']) ? $spa_settings['mode'] : 'disabled';
|
|
|
|
// If disabled, don't load
|
|
if ($mode === 'disabled') {
|
|
// Special handling for WooCommerce Shop page (it's an archive, not a regular post)
|
|
if (function_exists('is_shop') && is_shop()) {
|
|
$shop_page_id = get_option('woocommerce_shop_page_id');
|
|
if ($shop_page_id) {
|
|
$shop_page = get_post($shop_page_id);
|
|
if ($shop_page && has_shortcode($shop_page->post_content, 'woonoow_shop')) {
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check for shortcodes on regular pages
|
|
if ($post) {
|
|
if (has_shortcode($post->post_content, 'woonoow_shop')) {
|
|
return true;
|
|
}
|
|
if (has_shortcode($post->post_content, 'woonoow_cart')) {
|
|
return true;
|
|
}
|
|
if (has_shortcode($post->post_content, 'woonoow_checkout')) {
|
|
return true;
|
|
}
|
|
if (has_shortcode($post->post_content, 'woonoow_account')) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Full SPA mode - load on all WooCommerce pages
|
|
if ($mode === 'full') {
|
|
if (function_exists('is_shop') && is_shop()) {
|
|
return true;
|
|
}
|
|
if (function_exists('is_product') && is_product()) {
|
|
return true;
|
|
}
|
|
if (function_exists('is_cart') && is_cart()) {
|
|
return true;
|
|
}
|
|
if (function_exists('is_checkout') && is_checkout()) {
|
|
return true;
|
|
}
|
|
if (function_exists('is_account_page') && is_account_page()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Checkout-Only mode - load only on specific pages
|
|
if ($mode === 'checkout_only') {
|
|
$checkout_pages = isset($spa_settings['checkoutPages']) ? $spa_settings['checkoutPages'] : [];
|
|
|
|
if (!empty($checkout_pages['checkout']) && function_exists('is_checkout') && is_checkout() && !is_order_received_page()) {
|
|
return true;
|
|
}
|
|
if (!empty($checkout_pages['thankyou']) && function_exists('is_order_received_page') && is_order_received_page()) {
|
|
return true;
|
|
}
|
|
if (!empty($checkout_pages['account']) && function_exists('is_account_page') && is_account_page()) {
|
|
return true;
|
|
}
|
|
if (!empty($checkout_pages['cart']) && function_exists('is_cart') && is_cart()) {
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// Check if current page has WooNooW shortcodes
|
|
if ($post && has_shortcode($post->post_content, 'woonoow_shop')) {
|
|
return true;
|
|
}
|
|
if ($post && has_shortcode($post->post_content, 'woonoow_cart')) {
|
|
return true;
|
|
}
|
|
if ($post && has_shortcode($post->post_content, 'woonoow_checkout')) {
|
|
return true;
|
|
}
|
|
if ($post && has_shortcode($post->post_content, 'woonoow_account')) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if current page is the designated SPA page
|
|
*/
|
|
private static function is_spa_page() {
|
|
global $post;
|
|
if (!$post) {
|
|
return false;
|
|
}
|
|
|
|
// Get SPA page ID from appearance settings
|
|
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
|
$spa_page_id = isset($appearance_settings['general']['spa_page']) ? $appearance_settings['general']['spa_page'] : 0;
|
|
|
|
// Check if current page matches the SPA page
|
|
if ($spa_page_id && $post->ID == $spa_page_id) {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Check if current request is a frontpage SPA route
|
|
* Used to detect SPA routes by URL when SPA page is set as frontpage
|
|
*/
|
|
private static function is_frontpage_spa_route() {
|
|
// Get SPA settings
|
|
$appearance_settings = get_option('woonoow_appearance_settings', []);
|
|
$spa_page_id = $appearance_settings['general']['spa_page'] ?? 0;
|
|
$spa_mode = $appearance_settings['general']['spa_mode'] ?? 'full';
|
|
|
|
// Only run in full SPA mode
|
|
if ($spa_mode !== 'full' || !$spa_page_id) {
|
|
return false;
|
|
}
|
|
|
|
// Check if SPA page is set as WordPress frontpage
|
|
$frontpage_id = (int) get_option('page_on_front');
|
|
if (!$frontpage_id || $frontpage_id !== (int) $spa_page_id) {
|
|
return false;
|
|
}
|
|
|
|
// Get the current request path
|
|
$request_uri = $_SERVER['REQUEST_URI'] ?? '/';
|
|
$path = parse_url($request_uri, PHP_URL_PATH);
|
|
$path = '/' . trim($path, '/');
|
|
|
|
// Define SPA routes
|
|
$spa_routes = ['/', '/shop', '/cart', '/checkout', '/my-account', '/login', '/register', '/reset-password'];
|
|
|
|
// Check exact matches
|
|
if (in_array($path, $spa_routes)) {
|
|
return true;
|
|
}
|
|
|
|
// Check path prefixes
|
|
$prefix_routes = ['/shop/', '/my-account/', '/product/'];
|
|
foreach ($prefix_routes as $prefix) {
|
|
if (strpos($path, $prefix) === 0) {
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Dequeue conflicting scripts when SPA is active
|
|
*/
|
|
public static function dequeue_conflicting_scripts() {
|
|
if (!self::should_load_assets()) {
|
|
return;
|
|
}
|
|
|
|
// Dequeue WooCommerce scripts that conflict with SPA
|
|
wp_dequeue_script('wc-cart-fragments');
|
|
wp_dequeue_script('woocommerce');
|
|
wp_dequeue_script('wc-add-to-cart');
|
|
wp_dequeue_script('wc-add-to-cart-variation');
|
|
|
|
// Dequeue WordPress block scripts that cause errors in SPA
|
|
wp_dequeue_script('wp-block-library');
|
|
wp_dequeue_script('wp-block-navigation');
|
|
wp_dequeue_script('wp-interactivity');
|
|
wp_dequeue_script('wp-interactivity-router');
|
|
|
|
// Keep only essential WooCommerce styles, dequeue others if needed
|
|
// wp_dequeue_style('woocommerce-general');
|
|
// wp_dequeue_style('woocommerce-layout');
|
|
// wp_dequeue_style('woocommerce-smallscreen');
|
|
}
|
|
}
|