feat: Add product images support with WP Media Library integration

- Add WP Media Library integration for product and variation images
- Support images array (URLs) conversion to attachment IDs
- Add images array to API responses (Admin & Customer SPA)
- Implement drag-and-drop sortable images in Admin product form
- Add image gallery thumbnails in Customer SPA product page
- Initialize WooCommerce session for guest cart operations
- Fix product variations and attributes display in Customer SPA
- Add variation image field in Admin SPA

Changes:
- includes/Api/ProductsController.php: Handle images array, add to responses
- includes/Frontend/ShopController.php: Add images array for customer SPA
- includes/Frontend/CartController.php: Initialize WC session for guests
- admin-spa/src/lib/wp-media.ts: Add openWPMediaGallery function
- admin-spa/src/routes/Products/partials/tabs/GeneralTab.tsx: WP Media + sortable images
- admin-spa/src/routes/Products/partials/tabs/VariationsTab.tsx: Add variation image field
- customer-spa/src/pages/Product/index.tsx: Add gallery thumbnails display
This commit is contained in:
Dwindi Ramadhana
2025-11-26 16:18:43 +07:00
parent 909bddb23d
commit f397ef850f
69 changed files with 12481 additions and 156 deletions

View File

@@ -1,9 +1,13 @@
import React from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { HashRouter, Routes, Route, Navigate } from 'react-router-dom';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { Toaster } from 'sonner';
// Pages (will be created)
// Theme
import { ThemeProvider } from './contexts/ThemeContext';
import { BaseLayout } from './layouts/BaseLayout';
// Pages
import Shop from './pages/Shop';
import Product from './pages/Product';
import Cart from './pages/Cart';
@@ -21,29 +25,56 @@ const queryClient = new QueryClient({
},
});
// Get theme config from window (injected by PHP)
const getThemeConfig = () => {
const config = (window as any).woonoowCustomer?.theme;
// Default config if not provided
return config || {
mode: 'full',
layout: 'modern',
colors: {
primary: '#3B82F6',
secondary: '#8B5CF6',
accent: '#10B981',
},
typography: {
preset: 'professional',
},
};
};
function App() {
const themeConfig = getThemeConfig();
return (
<QueryClientProvider client={queryClient}>
<BrowserRouter basename="/shop">
<Routes>
{/* Shop Routes */}
<Route path="/" element={<Shop />} />
<Route path="/product/:id" element={<Product />} />
{/* Cart & Checkout */}
<Route path="/cart" element={<Cart />} />
<Route path="/checkout" element={<Checkout />} />
{/* My Account */}
<Route path="/account/*" element={<Account />} />
{/* Fallback */}
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
{/* Toast notifications */}
<Toaster position="top-right" richColors />
<ThemeProvider config={themeConfig}>
<HashRouter>
<BaseLayout>
<Routes>
{/* Shop Routes */}
<Route path="/" element={<Shop />} />
<Route path="/shop" element={<Shop />} />
<Route path="/product/:slug" element={<Product />} />
{/* Cart & Checkout */}
<Route path="/cart" element={<Cart />} />
<Route path="/checkout" element={<Checkout />} />
<Route path="/order-received/:orderId" element={<div>Thank You Page</div>} />
{/* My Account */}
<Route path="/my-account/*" element={<Account />} />
{/* Fallback */}
<Route path="*" element={<Navigate to="/shop" replace />} />
</Routes>
</BaseLayout>
</HashRouter>
{/* Toast notifications */}
<Toaster position="top-right" richColors />
</ThemeProvider>
</QueryClientProvider>
);
}