Skip to content

v0.2.0

Choose a tag to compare

@TBarregren TBarregren released this 10 Jun 08:34
· 111 commits to main since this release

A hardening release for field use: an extremely thorough security and reliability review of v0.1.0 (~30 verified findings) fixed silent photo-loss paths, crash and memory-exhaustion vectors, symlink confinement, and editor breakage.

Added

  • New filter kntnt_photo_drop_max_input_megapixels (default 50): sources declaring more pixels are rejected per-file before any decode, so a decompression bomb or an oversized original can no longer exhaust PHP's memory and kill the upload request or CLI batch.
  • Drop Zone session recovery — when the page has been open long enough for the WordPress session nonce to expire, the uploader now fetches a fresh nonce automatically and retries the upload once; failing that, it shows the server's actionable message instead of a generic "Upload failed".
  • Real upload progress — uploads now report true per-file transfer progress, and a 60-second inactivity watchdog aborts a stalled connection with a retryable error instead of freezing the upload queue indefinitely.
  • The Drop Zone warns before the page is closed or navigated away while files are still queued or uploading.
  • The Drop Zone pre-filters camera-folder noise: RAW files (CR2/CR3/NEF/ARW/DNG/RAF/ORF/RW2/SRW/PEF) and videos are rejected locally with a clear status line instead of uploading hundreds of megabytes only to be rejected by the server.
  • The Drop Zone status list now keeps one row per file that updates through its states (converting, uploading, uploaded, skipped, failed) plus a live summary count, instead of an append-only log with contradictory lines.
  • The Photo Gallery block's editor preview now uses ServerSideRender, so the editor shows the real rendered gallery instead of placeholder tiles.
  • The lightbox shows loading and error states for the enlarged image, locks the page scroll while open, and feeds the enlarged image a responsive srcset.
  • An admin notice warns when the host's PHP can encode WebP with neither GD nor Imagick — previously every upload failed with an opaque error and no explanation anywhere.
  • The plugin row's "View version details" modal now shows the GitHub release notes instead of a "plugin not found" error.
  • Translations now load from the plugin's languages/ directory, and the FilePond interface strings (drag-and-drop prompt, per-file states) are translatable.

Changed

  • WP-CLI exit codes are now scriptable: image import exits non-zero when every source was rejected (a partial failure still succeeds with a warning and counts), and a report-only collection doctor exits non-zero when actionable findings exist.
  • collection doctor --repair --force now also prunes thumbnail directories left behind by a thumbnail-width change, instead of letting de-configured widths accumulate on disk forever.
  • The auto-updater caches the GitHub release lookup in a site transient (6 h, with a short-lived failure marker), sends a proper API Accept header and timeout, and logs failed lookups — previously it hit the GitHub API uncached on every admin load and went silently blind when rate-limited. The update row now reports tested, requires, and requires_php correctly.
  • Gallery sizes hints are layout-aware (derived from the column width or the justified row height) instead of 100vw, so browsers no longer download the full-size main image for every thumbnail-sized tile.
  • The unused FilePond image-resize plugin was removed from the bundle; the Canvas pipeline has always done the actual downscaling.

Fixed

  • Folder drag-and-drop no longer loses photos silently. The folder warning never fired (its listener was attached to an element FilePond removes), and FilePond recursively traversed dropped folders while flattening every path — so same-named files from different camera folders (100CANON/IMG_0001.JPG, 101CANON/IMG_0001.JPG) silently overwrote or skipped each other while the UI claimed success. A dropped folder is now intercepted, warned about, and on confirmation uploads its top-level images flat, exactly as designed.
  • The Photo Gallery block no longer crashes the editor when the Layout panel opens (UnitControl is not a stable @wordpress/components export; the experimental export is now used, as core blocks do).
  • A blank image can no longer be uploaded as if it were the photo: when the browser cannot provide a canvas context (memory pressure) or the image exceeds the safe canvas area on iOS, the original file is uploaded instead and the server performs the conversion.
  • Uploading an image with an extreme aspect ratio (wide panoramas) crashed the request mid-batch with an uncaught ValueError from GD; the scaled height is now clamped to one pixel and any codec failure becomes a clean per-file rejection.
  • Portrait photos imported via wp kntnt-photo-drop image import or POSTed directly to the REST API rendered sideways: the server now applies EXIF orientation to the pixels before scaling and encoding, in both the GD and Imagick codecs.
  • Palette-based PNG/GIF images (screenshots, logos) within the size ceiling were wrongly rejected; they are now promoted to truecolor (transparency preserved) and convert correctly.
  • A truncated or corrupt WebP could pass the header-only check and be stored as a permanently broken image; already-conforming WebP files are now decode-validated before being accepted byte-identical.
  • collection.json — the one irreplaceable file — could be destroyed by a crash or full disk mid-write; the descriptor, the index, every main image, and every thumbnail are now published atomically (temp file + rename) with short writes detected, so a reader only ever sees the old or the complete new file.
  • An image uploaded within the same second as an index rebuild could stay invisible in the gallery indefinitely (mtime has one-second granularity); an index stamped in the current second is no longer persisted, closing the race.
  • A photographer's --ignore glob that happened to match stored images de-classified them and deleted their thumbnails under --repair; ignore globs now apply only to files that are not main images.
  • The doctor flagged the plugin's own directory-listing guard (index.php) as a foreign file in every collection.
  • The REST route's parameter sanitization silently mangled legitimate filenames containing %-sequences or doubled spaces, and bypassed the path guard's documented decoding defence; the raw value now reaches the guard, which is the real sanitizer.
  • A collection containing an unreadable subdirectory white-screened the whole admin page, including the delete action; the image count now degrades to an em-dash with a logged warning.
  • Lightbox keyboard handling went dead after clicking the enlarged image (Escape/arrows stopped working and Tab escaped the dialog); keys are now handled at the document level while the lightbox is open.
  • Pinch-zoom gestures over the lightbox no longer trigger spurious image changes, Cmd/Ctrl/Shift-clicking a thumbnail opens it in a new tab as expected, holding an arrow key no longer floods the network with uncancelled full-resolution preloads, and Alt/Cmd+Arrow (browser back/forward) is no longer hijacked.
  • The justified layout's last row is now corrected client-side against the real container width, so mid-gallery rows no longer render ragged on themes narrower or wider than the assumed width.
  • A failed collection scan (glob() error) and a failed block registration are now logged instead of silently rendering "no collections" or removing the blocks from the inserter.
  • build-release-zip.sh restores the development dependencies even when a build step fails, and excludes macOS junk files from the release archive.
  • Uninstalling now removes the plugin's transients (release cache, admin notices).
  • Documentation: the thumbnail-regeneration examples in the README, the design notes, and ADR-0002 now show the complete, runnable WP-CLI command (wp kntnt-photo-drop collection doctor <slug> --repair --force) instead of a bare collection doctor --repair --force fragment that omitted the wp kntnt-photo-drop prefix.

Security

  • collection doctor --repair can no longer be tricked into deleting or writing files outside the collection — every doctor walk now skips symbolic links and refuses to unlink or write through them, matching the confinement the rest of the plugin already enforced.
  • The gallery's index rebuild also skips symbolic links, so a planted link can no longer send the recursive gallery walk into an infinite loop (denial of service) or expose files outside the collection.
  • GPS positions and other EXIF/XMP metadata are now stripped server-side — losslessly — from already-conforming WebP files that are stored byte-identical, closing a privacy leak where a directly-POSTed WebP published the photographer's location. Re-encoded uploads were already stripped.
  • Every newly created collection directory is seeded with a directory-listing guard (index.php), so a server with autoindex enabled cannot enumerate collection contents.

Full changelog: https://github.com/Kntnt/kntnt-photo-drop/blob/v0.2.0/CHANGELOG.md