🐛 CRITICAL FIX - Asset Path Issue: 1. WP-Admin Assets Not Loading: ❌ Old path: includes/Admin/../admin-spa/dist/ ✅ New path: /plugin-root/admin-spa/dist/ Problem: Relative path from includes/Admin/ was wrong Solution: Use dirname(__DIR__) to get plugin root, then build absolute path Before: - CSS exists: no - JS exists: no After: - CSS exists: yes (2.4MB) - JS exists: yes (70KB) 2. Standalone Media Library Styling: ❌ Missing WordPress core styles (buttons, dashicons) ✅ Added wp_print_styles for buttons and dashicons Problem: Media modal had unstyled text/buttons Solution: Enqueue all required WordPress media styles Styles now loaded: - media-views (modal structure) - imgareaselect (image selection) - buttons (WordPress buttons) - dashicons (icons) 📝 Debug logs now show: [WooNooW Assets] Dist dir: /home/.../woonoow/admin-spa/dist/ [WooNooW Assets] CSS exists: yes [WooNooW Assets] JS exists: yes 🎯 Result: - WP-Admin SPA now loads correctly - Standalone media library properly styled - Both modes fully functional
199 lines
6.4 KiB
PHP
199 lines
6.4 KiB
PHP
<?php
|
|
namespace WooNooW\Admin;
|
|
|
|
/**
|
|
* Standalone Admin Handler
|
|
*
|
|
* Handles /admin requests without requiring .htaccess modifications.
|
|
* Uses WordPress template_redirect hook to catch requests early.
|
|
*
|
|
* @package WooNooW\Admin
|
|
*/
|
|
class StandaloneAdmin {
|
|
|
|
/**
|
|
* Initialize standalone admin handler
|
|
*/
|
|
public static function init() {
|
|
// Catch /admin requests very early (before WordPress routing)
|
|
add_action( 'parse_request', [ __CLASS__, 'handle_admin_request' ], 1 );
|
|
}
|
|
|
|
/**
|
|
* Handle /admin requests
|
|
*/
|
|
public static function handle_admin_request() {
|
|
// Check if this is an /admin request
|
|
$request_uri = $_SERVER['REQUEST_URI'] ?? '';
|
|
|
|
// Remove query string
|
|
$path = strtok( $request_uri, '?' );
|
|
|
|
// Only handle exact /admin or /admin/ paths (not asset files)
|
|
if ( $path !== '/admin' && $path !== '/admin/' ) {
|
|
return;
|
|
}
|
|
|
|
// This is a standalone admin request
|
|
self::render_standalone_admin();
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Render standalone admin interface
|
|
*/
|
|
private static function render_standalone_admin() {
|
|
// Enqueue WordPress media library (needed for image uploads)
|
|
wp_enqueue_media();
|
|
|
|
// Check if user is logged in and has permissions
|
|
$is_logged_in = is_user_logged_in();
|
|
$has_permission = $is_logged_in && current_user_can( 'manage_woocommerce' );
|
|
$is_authenticated = $is_logged_in && $has_permission;
|
|
|
|
// Debug logging (only in WP_DEBUG mode)
|
|
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
|
|
error_log( '[StandaloneAdmin] is_user_logged_in: ' . ( $is_logged_in ? 'true' : 'false' ) );
|
|
error_log( '[StandaloneAdmin] has manage_woocommerce: ' . ( $has_permission ? 'true' : 'false' ) );
|
|
error_log( '[StandaloneAdmin] is_authenticated: ' . ( $is_authenticated ? 'true' : 'false' ) );
|
|
}
|
|
|
|
// Get nonce for REST API
|
|
$nonce = wp_create_nonce( 'wp_rest' );
|
|
$rest_url = untrailingslashit( rest_url( 'woonoow/v1' ) );
|
|
$wp_admin_url = admin_url( 'admin.php?page=woonoow' );
|
|
|
|
// Get current user data if authenticated
|
|
$current_user = null;
|
|
if ( $is_authenticated ) {
|
|
$user = wp_get_current_user();
|
|
$current_user = [
|
|
'id' => $user->ID,
|
|
'name' => $user->display_name,
|
|
'email' => $user->user_email,
|
|
'avatar' => get_avatar_url( $user->ID ),
|
|
];
|
|
}
|
|
|
|
// Get WooCommerce store settings
|
|
$store_settings = self::get_store_settings();
|
|
|
|
// Get asset URLs
|
|
$plugin_url = plugins_url( '', dirname( dirname( __FILE__ ) ) );
|
|
$asset_url = $plugin_url . '/admin-spa/dist';
|
|
|
|
// Cache busting
|
|
$version = defined( 'WP_DEBUG' ) && WP_DEBUG ? time() : '1.0.0';
|
|
$css_url = $asset_url . '/app.css?ver=' . $version;
|
|
$js_url = $asset_url . '/app.js?ver=' . $version;
|
|
|
|
// Render HTML
|
|
?>
|
|
<!DOCTYPE html>
|
|
<html lang="<?php echo esc_attr( get_locale() ); ?>">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<meta name="robots" content="noindex, nofollow">
|
|
<title><?php echo esc_html( get_option( 'blogname', 'WooNooW' ) ); ?> Admin</title>
|
|
|
|
<?php
|
|
// Favicon
|
|
$icon = get_option( 'woonoow_store_icon', '' );
|
|
if ( ! empty( $icon ) ) {
|
|
?>
|
|
<link rel="icon" type="image/png" href="<?php echo esc_url( $icon ); ?>" />
|
|
<link rel="apple-touch-icon" href="<?php echo esc_url( $icon ); ?>" />
|
|
<?php
|
|
}
|
|
?>
|
|
|
|
<!-- WooNooW Assets -->
|
|
<link rel="stylesheet" href="<?php echo esc_url( $css_url ); ?>">
|
|
|
|
<?php
|
|
// Print WordPress media library styles (all required styles)
|
|
wp_print_styles( 'media-views' );
|
|
wp_print_styles( 'imgareaselect' );
|
|
wp_print_styles( 'buttons' );
|
|
wp_print_styles( 'dashicons' );
|
|
?>
|
|
</head>
|
|
<body class="woonoow-standalone">
|
|
<div id="woonoow-admin-app"></div>
|
|
|
|
<script>
|
|
// Minimal config - no WordPress bloat
|
|
window.WNW_CONFIG = {
|
|
restUrl: <?php echo wp_json_encode( $rest_url ); ?>,
|
|
nonce: <?php echo wp_json_encode( $nonce ); ?>,
|
|
standaloneMode: true,
|
|
wpAdminUrl: <?php echo wp_json_encode( $wp_admin_url ); ?>,
|
|
isAuthenticated: <?php echo $is_authenticated ? 'true' : 'false'; ?>,
|
|
currentUser: <?php echo wp_json_encode( $current_user ); ?>,
|
|
locale: <?php echo wp_json_encode( get_locale() ); ?>,
|
|
siteUrl: <?php echo wp_json_encode( home_url() ); ?>,
|
|
siteName: <?php echo wp_json_encode( get_bloginfo( 'name' ) ); ?>
|
|
};
|
|
|
|
// Also set WNW_API for API compatibility
|
|
window.WNW_API = {
|
|
root: <?php echo wp_json_encode( $rest_url ); ?>,
|
|
nonce: <?php echo wp_json_encode( $nonce ); ?>,
|
|
isDev: <?php echo ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? 'true' : 'false'; ?>
|
|
};
|
|
|
|
// WooCommerce store settings (currency, formatting, etc.)
|
|
window.WNW_STORE = <?php echo wp_json_encode( $store_settings ); ?>;
|
|
|
|
// Navigation tree (single source of truth from PHP)
|
|
window.WNW_NAV_TREE = <?php echo wp_json_encode( \WooNooW\Compat\NavigationRegistry::get_frontend_nav_tree() ); ?>;
|
|
|
|
// WordPress REST API settings (for media upload compatibility)
|
|
window.wpApiSettings = {
|
|
root: <?php echo wp_json_encode( untrailingslashit( rest_url() ) ); ?>,
|
|
nonce: <?php echo wp_json_encode( $nonce ); ?>,
|
|
versionString: 'wp/v2/'
|
|
};
|
|
</script>
|
|
|
|
<?php
|
|
// Print WordPress media library scripts (needed for wp.media)
|
|
wp_print_scripts( 'media-editor' );
|
|
wp_print_scripts( 'media-audiovideo' );
|
|
|
|
// Print media templates (required for media modal to work)
|
|
wp_print_media_templates();
|
|
?>
|
|
|
|
<script type="module" src="<?php echo esc_url( $js_url ); ?>"></script>
|
|
</body>
|
|
</html>
|
|
<?php
|
|
}
|
|
|
|
/**
|
|
* Get WooCommerce store settings for frontend
|
|
*
|
|
* @return array Store settings (currency, decimals, separators, etc.)
|
|
*/
|
|
private static function get_store_settings(): array {
|
|
// Get WooCommerce settings with fallbacks
|
|
$currency = function_exists( 'get_woocommerce_currency' ) ? get_woocommerce_currency() : 'USD';
|
|
$currency_sym = function_exists( 'get_woocommerce_currency_symbol' ) ? get_woocommerce_currency_symbol( $currency ) : '$';
|
|
$decimals = function_exists( 'wc_get_price_decimals' ) ? wc_get_price_decimals() : 2;
|
|
$thousand_sep = function_exists( 'wc_get_price_thousand_separator' ) ? wc_get_price_thousand_separator() : ',';
|
|
$decimal_sep = function_exists( 'wc_get_price_decimal_separator' ) ? wc_get_price_decimal_separator() : '.';
|
|
$currency_pos = get_option( 'woocommerce_currency_pos', 'left' );
|
|
|
|
return [
|
|
'currency' => $currency,
|
|
'currency_symbol' => $currency_sym,
|
|
'decimals' => (int) $decimals,
|
|
'thousand_sep' => (string) $thousand_sep,
|
|
'decimal_sep' => (string) $decimal_sep,
|
|
'currency_pos' => (string) $currency_pos,
|
|
];
|
|
}
|
|
}
|