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

271
INLINE_SPACING_FIX.md Normal file
View File

@@ -0,0 +1,271 @@
# Inline Spacing Fix - The Real Root Cause
## The Problem
Images were not filling their containers, leaving whitespace at the bottom. This was NOT a height issue, but an **inline element spacing issue**.
### Root Cause Analysis
1. **Images are inline by default** - They respect text baseline, creating extra vertical space
2. **SVG icons create inline gaps** - SVGs also default to inline display
3. **Line-height affects layout** - Parent containers with text create baseline alignment issues
### Visual Evidence
```
┌─────────────────────┐
│ │
│ IMAGE │
│ │
│ │
└─────────────────────┘
↑ Whitespace gap here (caused by inline baseline)
```
---
## The Solution
### Three Key Fixes
#### 1. Make Images Block-Level
```tsx
// Before (inline by default)
<img className="w-full h-full object-cover" />
// After (block display)
<img className="block w-full h-full object-cover" />
```
#### 2. Remove Inline Whitespace from Container
```tsx
// Add fontSize: 0 to parent
<div style={{ fontSize: 0 }}>
<img className="block w-full h-full object-cover" />
</div>
```
#### 3. Reset Font Size for Text Content
```tsx
// Reset fontSize for text elements inside
<div style={{ fontSize: '1rem' }}>
No Image
</div>
```
---
## Implementation
### ProductCard Component
**All 4 layouts fixed:**
```tsx
// Classic, Modern, Boutique, Launch
<div className="relative w-full h-64 overflow-hidden bg-gray-100"
style={{ fontSize: 0 }}>
{product.image ? (
<img
src={product.image}
alt={product.name}
className="block w-full h-full object-cover object-center"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400"
style={{ fontSize: '1rem' }}>
No Image
</div>
)}
</div>
```
**Key changes:**
- ✅ Added `style={{ fontSize: 0 }}` to container
- ✅ Added `block` class to `<img>`
- ✅ Reset `fontSize: '1rem'` for "No Image" text
- ✅ Added `flex items-center justify-center` to button with Heart icon
---
### Product Page
**Same fix applied:**
```tsx
<div className="relative w-full h-96 rounded-lg overflow-hidden bg-gray-100"
style={{ fontSize: 0 }}>
{product.image ? (
<img
src={product.image}
alt={product.name}
className="block w-full h-full object-cover object-center"
/>
) : (
<div className="w-full h-full flex items-center justify-center text-gray-400"
style={{ fontSize: '1rem' }}>
No image
</div>
)}
</div>
```
---
## Why This Works
### The Technical Explanation
#### Inline Elements and Baseline
- By default, `<img>` has `display: inline`
- Inline elements align to the text baseline
- This creates a small gap below the image (descender space)
#### Font Size Zero Trick
- Setting `fontSize: 0` on parent removes whitespace between inline elements
- This is a proven technique for removing gaps in inline layouts
- Text content needs `fontSize: '1rem'` reset to be readable
#### Block Display
- `display: block` removes baseline alignment
- Block elements fill their container naturally
- No extra spacing or gaps
---
## Files Modified
### 1. ProductCard.tsx
**Location:** `customer-spa/src/components/ProductCard.tsx`
**Changes:**
- Classic layout (line ~43)
- Modern layout (line ~116)
- Boutique layout (line ~183)
- Launch layout (line ~247)
**Applied to all:**
- Container: `style={{ fontSize: 0 }}`
- Image: `className="block ..."`
- Fallback text: `style={{ fontSize: '1rem' }}`
---
### 2. Product/index.tsx
**Location:** `customer-spa/src/pages/Product/index.tsx`
**Changes:**
- Product image container (line ~121)
- Same pattern as ProductCard
---
## Testing Checklist
### Visual Test
1. ✅ Go to `/shop`
2. ✅ Check product images - should fill containers completely
3. ✅ No whitespace at bottom of images
4. ✅ Hover effects should work smoothly
### Product Page Test
1. ✅ Click any product
2. ✅ Product image should fill container
3. ✅ No whitespace at bottom
4. ✅ Image should be 384px tall (h-96)
### Browser Test
- ✅ Chrome
- ✅ Firefox
- ✅ Safari
- ✅ Edge
---
## Best Practices Applied
### Global CSS Recommendation
For future projects, add to global CSS:
```css
img {
display: block;
max-width: 100%;
}
svg {
display: block;
}
```
This prevents inline spacing issues across the entire application.
### Why We Used Inline Styles
- Tailwind doesn't have a `font-size: 0` utility
- Inline styles are acceptable for one-off fixes
- Could be extracted to custom Tailwind class if needed
---
## Comparison: Before vs After
### Before
```tsx
<div className="relative w-full h-64">
<img className="w-full h-full object-cover" />
</div>
```
**Result:** Whitespace at bottom due to inline baseline
### After
```tsx
<div className="relative w-full h-64" style={{ fontSize: 0 }}>
<img className="block w-full h-full object-cover" />
</div>
```
**Result:** Perfect fill, no whitespace
---
## Key Learnings
### 1. Images Are Inline By Default
Always remember that `<img>` elements are inline, not block.
### 2. Baseline Alignment Creates Gaps
Inline elements respect text baseline, creating unexpected spacing.
### 3. Font Size Zero Trick
Setting `fontSize: 0` on parent is a proven technique for removing inline gaps.
### 4. Display Block Is Essential
For images in containers, always use `display: block`.
### 5. SVGs Have Same Issue
SVG icons also need `display: block` to prevent spacing issues.
---
## Summary
**Problem:** Whitespace at bottom of images due to inline element spacing
**Root Cause:** Images default to `display: inline`, creating baseline alignment gaps
**Solution:**
1. Container: `style={{ fontSize: 0 }}`
2. Image: `className="block ..."`
3. Text: `style={{ fontSize: '1rem' }}`
**Result:** Perfect image fill with no whitespace! ✅
---
## Credits
Thanks to the second opinion for identifying the root cause:
- Inline SVG spacing
- Image baseline alignment
- Font-size zero technique
This is a classic CSS gotcha that many developers encounter!