# Handling Zip Path Separators for Linux/cPanel Compatibility

## The Problem

When creating a zip file on a Windows machine for use on a Linux-based server (like a typical cPanel/FTP environment), a common issue arises with directory path separators.

-   **Windows uses backslashes (`\`)**: `assets\js\script.js`
-   **Linux/Zip Standard uses forward slashes (`/`)**: `assets/js/script.js`

PowerShell's default `Compress-Archive` cmdlet, and even some underlying .NET methods, may create zip archives using Windows-style backslashes. When a Linux server tries to unzip this archive, it doesn't recognize the backslash as a directory separator. Instead of creating a `js` folder inside an `assets` folder, it might create a single file literally named `assets\js\script.js`, which breaks the application (e.g., a WordPress theme).

## The Solution: Manual Zip Creation

To guarantee that the zip file uses the correct forward-slash separators, we must bypass the high-level cmdlets and manually construct the archive. This gives us explicit control over the name of each entry within the zip file.

The following PowerShell code, implemented in `scripts/bundle.ps1`, demonstrates the correct approach.

```powershell
# Manually create ZipArchive to enforce forward slashes for Linux/FTP compatibility
Add-Type -AssemblyName System.IO.Compression.FileSystem
$ZipArchive = [System.IO.Compression.ZipFile]::Open($ZipPath, [System.IO.Compression.ZipArchiveMode]::Create)
$ThemeBuildDirFull = (Get-Item $ThemeBuildDir).FullName
$Files = Get-ChildItem -Path $ThemeBuildDir -Recurse -File
foreach ($File in $Files) {
    # Get the path of the file relative to the source directory
    $RelativePath = $File.FullName.Substring($ThemeBuildDirFull.Length + 1)
    # CRITICAL: Replace Windows backslashes with Linux/Zip-standard forward slashes
    $EntryName = $RelativePath -replace '\\', '/'
    # Add the file to the archive with the corrected entry name
    [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile($ZipArchive, $File.FullName, $EntryName)
}
# Finalize and close the zip file
$ZipArchive.Dispose()
```

### How It Works

1.  **`Add-Type`**: Loads the necessary .NET assembly for advanced file compression operations.
2.  **`[System.IO.Compression.ZipFile]::Open(...)`**: Creates a new, empty zip archive stream that we can write to.
3.  **`Get-ChildItem -Recurse -File`**: Gathers a list of all *files* (not directories) within our source build directory.
4.  **`foreach ($File in $Files)`**: We loop through each file we need to add.
5.  **`$File.FullName.Substring(...)`**: This calculates the file's path *relative* to the build directory (e.g., `assets\js\script.js`).
6.  **`$RelativePath -replace '\\', '/'`**: This is the most important step. It takes the relative path and explicitly replaces every backslash (`\`) with a forward slash (`/`).
7.  **`CreateEntryFromFile(...)`**: This adds the current file to the zip archive, but it uses our corrected `$EntryName` (with forward slashes) as the internal path.
8.  **`$ZipArchive.Dispose()`**: This closes the stream and saves the final, correctly formatted zip file to disk.

By following this method, the `bundle.ps1` script produces a universally compatible zip file that will be correctly extracted on any server environment.