fix: Standalone nav + REST URL + SVG upload support

##  Issue 1: Standalone Mode Navigation
**Problem:** Standalone mode not getting WNW_NAV_TREE from PHP
**Fixed:** Added WNW_NAV_TREE injection to StandaloneAdmin.php
**Result:** Navigation now works in standalone mode with PHP as single source

##  Issue 2: 404 Errors for branding and customer-settings
**Problem:** REST URLs had trailing slashes causing double slashes
**Root Cause:**
- `rest_url("woonoow/v1")` returns `https://site.com/wp-json/woonoow/v1/`
- Frontend: `restUrl + "/store/branding"` = double slash
- WP-admin missing WNW_CONFIG entirely

**Fixed:**
1. **Removed trailing slashes** from all REST URLs using `untrailingslashit()`
   - StandaloneAdmin.php
   - Assets.php (dev and prod modes)

2. **Added WNW_CONFIG to wp-admin** for API compatibility
   - Dev mode: Added WNW_CONFIG with restUrl, nonce, standaloneMode, etc.
   - Prod mode: Added WNW_CONFIG to localize_runtime()
   - Now both modes use same config structure

**Result:**
-  `/store/branding` works in all modes
-  `/store/customer-settings` works in all modes
-  Consistent API access across standalone and wp-admin

##  Issue 3: SVG Upload Error 500
**Problem:** WordPress blocks SVG uploads by default
**Security:** "Sorry, you are not allowed to upload this file type"

**Fixed:** Created MediaUpload.php with:
1. **Allow SVG uploads** for users with upload_files capability
2. **Fix SVG mime type detection** (WordPress issue)
3. **Sanitize SVG on upload** - reject files with:
   - `<script>` tags
   - `javascript:` protocols
   - Event handlers (onclick, onload, etc.)

**Result:**
-  SVG uploads work securely
-  Dangerous SVG content blocked
-  Only authorized users can upload

---

## Files Modified:
- `StandaloneAdmin.php` - Add nav tree + fix REST URL
- `Assets.php` - Add WNW_CONFIG + fix REST URLs
- `Bootstrap.php` - Initialize MediaUpload
- `MediaUpload.php` - NEW: SVG upload support with security

## Testing:
1.  Navigation works in standalone mode
2.  Branding endpoint works in all modes
3.  Customer settings endpoint works in all modes
4.  SVG logo upload works
5.  Dangerous SVG files rejected
This commit is contained in:
dwindown
2025-11-11 10:28:47 +07:00
parent 677c04dd62
commit 8312c18f64
4 changed files with 136 additions and 5 deletions

View File

@@ -0,0 +1,107 @@
<?php
/**
* Media Upload Handler
*
* Handles file uploads including SVG support with security checks.
*
* @package WooNooW
*/
namespace WooNooW\Core;
class MediaUpload {
/**
* Initialize media upload hooks
*/
public static function init() {
// Allow SVG uploads
add_filter( 'upload_mimes', [ __CLASS__, 'allow_svg_upload' ] );
// Fix SVG mime type detection
add_filter( 'wp_check_filetype_and_ext', [ __CLASS__, 'fix_svg_mime_type' ], 10, 5 );
// Sanitize SVG on upload
add_filter( 'wp_handle_upload_prefilter', [ __CLASS__, 'sanitize_svg_upload' ] );
}
/**
* Allow SVG file uploads
*
* @param array $mimes Allowed mime types
* @return array Modified mime types
*/
public static function allow_svg_upload( $mimes ) {
// Only allow for users with upload_files capability
if ( ! current_user_can( 'upload_files' ) ) {
return $mimes;
}
$mimes['svg'] = 'image/svg+xml';
$mimes['svgz'] = 'image/svg+xml';
return $mimes;
}
/**
* Fix SVG mime type detection
*
* @param array $data File data
* @param string $file File path
* @param string $filename File name
* @param array $mimes Allowed mimes
* @param string $real_mime Real mime type
* @return array Modified file data
*/
public static function fix_svg_mime_type( $data, $file, $filename, $mimes, $real_mime ) {
if ( ! $data['ext'] && ! $data['type'] ) {
$wp_filetype = wp_check_filetype( $filename, $mimes );
$ext = $wp_filetype['ext'];
$type = $wp_filetype['type'];
if ( $ext === 'svg' || $ext === 'svgz' ) {
$data['ext'] = $ext;
$data['type'] = $type;
}
}
return $data;
}
/**
* Sanitize SVG files on upload
*
* @param array $file Upload file data
* @return array Modified file data
*/
public static function sanitize_svg_upload( $file ) {
// Only process SVG files
if ( $file['type'] !== 'image/svg+xml' ) {
return $file;
}
// Read file content
$svg_content = file_get_contents( $file['tmp_name'] );
if ( $svg_content === false ) {
$file['error'] = __( 'Could not read SVG file', 'woonoow' );
return $file;
}
// Basic security check - reject if contains script tags or event handlers
$dangerous_patterns = [
'/<script/i',
'/javascript:/i',
'/on\w+\s*=/i', // onclick, onload, etc.
];
foreach ( $dangerous_patterns as $pattern ) {
if ( preg_match( $pattern, $svg_content ) ) {
$file['error'] = __( 'SVG file contains potentially dangerous content', 'woonoow' );
return $file;
}
}
return $file;
}
}