=== Flex Explorer ===
Contributors: flexatech
Tags: file manager, files, download, zip, trash
Requires at least: 6.0
Tested up to: 7.1
Requires PHP: 8.0
Stable tag: 1.4.0
License: GPL v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html

A sandboxed file manager for WordPress: browse, upload, zip, download and recover your site's files from a fast admin app.

== Description ==

Flex Explorer adds a single-page file manager to wp-admin. Every operation runs
through a sandboxed REST surface that resolves paths against a configurable
root, refuses symlink escapes, and never lets a request reach outside the site.

**What it does**

* **Browse** in icon, list or macOS-style column views, with a folder tree, drag-and-drop move, multi-select, sorting, dotfile toggle and recursive filename search.
* **Upload** with drag-and-drop, enforcing the site's size cap and WordPress filename sanitisation.
* **Create, rename, copy, move and delete** files and folders.
* **Trash** catches deletions: items move to a recoverable store with restore, purge, and automatic cleanup after a retention period you set. Turn it off and deletions are permanent again.
* **Zip and download** a single file or a whole folder. Large selections run as background jobs with live progress, cancel, HTTP Range (resumable) downloads, and a single-use signed token per archive.
* **Extract** a zip in place or into a named folder.
* **Risky-operation gate** asks for confirmation before touching load-bearing files. A file is flagged only when it matches a "Risky file patterns" glob *and* sits inside a "Risky folders" entry, so a stray `*.php` under `uploads/` stays quiet.
* **Preview** images inline; anything else downloads.
* **Per-user interface language** and a light / dark / cream theme, independent of the rest of wp-admin.
* **WP-CLI**: `wp flex-explorer reset` clears the plugin's options and tables.

**There is no file editor in this build**

WordPress.org does not allow a plugin in the directory to edit site files, so
this build ships no editor: the Edit action explains that and points you at the
build that has one. That build is free as well, and it is downloaded from
[flexacommerce.com/products/flex-explorer](https://flexacommerce.com/products/flex-explorer).
Settings, trash contents and background jobs carry over, because both builds use
the same slug, options and tables. Installing one over the other keeps your
configuration.

**Security model**

Access is limited to administrators (`manage_options`, filterable via
`flex_explorer/capabilities/manage`). Mutating calls require a nonce. A site
defining `DISALLOW_FILE_EDIT` switches the plugin off entirely, and on multisite
only network super admins pass, because the sandbox root is the whole network's
filesystem. `wp-config.php`, `.htpasswd`, `.htaccess` and the WordPress core
files at the site root can never be deleted, renamed or moved by anyone, with no
bypass: removing any of them would take the site down.

== External services ==

Your files never leave your server. Flex Explorer reads and writes the
filesystem locally, and the file manager itself makes no outbound calls. The
plugin connects to one external service, only in the admin, for the reason
below.

= Deactivation feedback (Flexa Product Intelligence) =

When you go to deactivate Flex Explorer on the Plugins screen, a short optional
survey asks why. This is served by Flexa's product intelligence service at
https://product-intelligence.flexacommerce.com. It runs only on
`wp-admin/plugins.php`, never on the front end, and never blocks deactivation:
if the service is unreachable, the normal Deactivate link still works.

What is sent, and when:

* On opening the Plugins screen: a request to `/api/v1/config` (product slug and tier) to load the survey configuration. Cached for 6 hours.
* When you deactivate or interact with the survey: the reason you pick and any optional message you type, sent to `/api/v1/deactivations`, `/api/v1/events`, `/api/v1/feedback`, `/api/v1/feature-requests` and `/api/v1/recovery-events`.

Every request includes an anonymous per-site identifier (a random UUID), the
plugin version, and by default your WordPress version, PHP version
and locale. No email, site domain, user identity, file name, file content or
raw IP is collected.

Turn the environment details off with:
`add_filter( 'flex_explorer/deactivation_survey/config', fn( $c ) => array( 'collect_environment' => false ) + $c );`

Disable the survey entirely with:
`add_filter( 'flex_explorer/deactivation_survey/enabled', '__return_false' );`

Service terms and privacy policy: https://flexacommerce.com/pages/terms and https://flexacommerce.com/pages/privacy

== Installation ==

1. Upload the plugin files to `/wp-content/plugins/flex-explorer`, or install through the WordPress **Plugins** screen.
2. Activate the plugin through the **Plugins** screen.
3. Open **Flex Explorer** from the admin menu.

== Frequently Asked Questions ==

= Who can use Flex Explorer? =

Only users with the `manage_options` capability, which in practice means
administrators. The gating capability is filterable via
`flex_explorer/capabilities/manage`.

= Does it work on multisite? =

Yes, with access restricted to network super admins. `manage_options` is a
per-site capability, but the sandbox root is the whole network's filesystem, so a
subsite administrator would otherwise reach every other site's files. A network
that does want per-site access can opt in with the
`flex_explorer/capabilities/require_super_admin` filter.

= Why is there no Flex Explorer menu entry? =

The most likely reason is that your site defines `DISALLOW_FILE_EDIT`, which
switches the plugin off completely: it is a much bigger lever than the core file
editor that constant disables. The Plugins screen shows a note when this is the
case. To keep the constant and still use the file manager, filter
`flex_explorer/capabilities/enabled` to true.

= Where did the file editor go? =

Plugins distributed through the WordPress.org directory are not allowed to edit
site files, so this build has no editor and no write-content route at all: only
"new empty file" remains. Choosing **Edit** opens a dialog with a link to the
full build at
[flexacommerce.com/products/flex-explorer](https://flexacommerce.com/products/flex-explorer),
which is free and keeps the editor. Both builds share the same slug, settings
and tables, so switching between them loses nothing.

= Can files like wp-config.php be deleted? =

No, and that is not configurable. `wp-config.php`, `.htpasswd`, `.htaccess` and
the WordPress core files at the site root (`wp-settings.php`, `wp-load.php`, the
root `index.php`, `wp-login.php`, `xmlrpc.php`, `wp-cron.php` and friends) are
refused for delete, trash, rename and move, for everyone. The core-file guard
matches only the copy at the site root, so a plugin's own `index.php` in a
subfolder stays yours to manage.

= What does "risky operation" mean? =

Deleting, renaming, moving or overwriting an existing load-bearing file shows an
extra confirmation. You control exactly what counts, with two lists under
**Settings → Risky operations**: "Risky file patterns" (e.g. `*.php`,
`.htaccess`) and "Risky folders" (the tokens `@wp-core`, `@active-theme`,
`@active-plugins`, `@mu-plugins`, `@self`, or literal paths). A file is flagged
only when it matches a pattern AND lives inside one of the folders.

= Can I change the root folder? =

Yes. The sandbox root defaults to `ABSPATH` and is overridable via the
`root_path` setting or the `flex_explorer/sandbox/root` filter.

= Is large-file download safe on shared hosting? =

Yes. Big zips run as background jobs that write to a protected temp directory,
poll for cancellation, and serve the finished archive over a single-use sha256
token with HTTP Range support, so an interrupted download can resume.

= Does anything get sent off my site? =

Only the optional deactivation survey, documented under "External services"
above, and only when you go to deactivate the plugin. File names and file
contents are never sent anywhere.

== Screenshots ==

1. List view: the folder tree, the breadcrumb, the toolbar and the right-click menu.
2. Column view, macOS style, with details of the selected file in the last pane.
3. Background zip jobs: one archive still queued and cancellable, one finished and ready to download.
4. Trash: each deleted file keeps its original location, so Restore puts it back where it came from.
5. Settings: the confirmation gate for risky operations, plus the patterns and folders that trigger it.

== Changelog ==

= 1.4.0 =
* First WordPress.org release. Same plugin as the direct download, minus the file editor, which the directory guidelines do not allow. The Edit action links to the free full build instead.
* New: an optional deactivation survey. If you deactivate Flex Explorer, a short form asks why, so the next release fixes what actually went wrong. Answering is optional, the form never blocks deactivation, and what it sends is documented under "External services", including the filters to switch it off.
* New: "File manager" and "Get the full version" links on the plugin's row on the Plugins screen.

= 1.3.0 =
* Security: on a network, access is limited to network super admins (filterable via `flex_explorer/capabilities/require_super_admin`), because `manage_options` is per-site while the sandbox root is the whole network's filesystem.
* Security: a site defining `DISALLOW_FILE_EDIT` disables the plugin entirely (no menu, no REST, no admin page), with a note on the Plugins screen explaining why and a `flex_explorer/capabilities/enabled` filter to override it.
* Fix: bundled translations now load. WordPress only looks for plugin translations in its own languages directory unless the plugin registers its path; the plugin now registers `i18n/languages` on `init`.
* Fix: column view panes scroll vertically again when a folder has more rows than fit.
* Change: the minimum PHP version is now 8.0, down from 8.2.
* Harden: `$_SERVER` reads are sanitized and the dev-only scripts refuse to run outside WP-CLI.

= 1.2.0 =
* New: trash. Deleting moves items to a recoverable store with restore, purge and automatic cleanup; turning the setting off restores immediate deletion.

= 1.1.0 =
* New: configurable risky-operation confirmation gate. A file is flagged only when it both matches a "Risky file patterns" glob and sits inside a "Risky folders" entry. Folders accept the dynamic tokens `@wp-core`, `@active-theme`, `@active-plugins`, `@mu-plugins`, `@self`, or literal paths. New filter: `flex_explorer/risk/folders`.
* Improve: the Settings dialog body scrolls on short screens, so content is never clipped.
* Improve: a consistent thin scrollbar rail across the column view and other scrolling panes.
* Fix: removed the WordPress admin focus halo from the plugin's checkboxes and radios.

= 1.0.0 =
* React 18 admin single-page app (Vite 6, Tailwind v4) with TanStack Query and Zustand.
* Sandboxed REST surface (`flex-explorer/v1`) for browse, preview, upload, create, delete, rename, copy, move, zip, unzip and search.
* Icon, list and macOS-style column views with drag-and-drop move, multi-select and per-folder search.
* 3-tier zip pipeline (buffered, streamed, background job) with HTTP Range download support and a single-use sha256 token gate.
* Confirmation prompt before destructive operations on load-bearing files.
* Per-user locale override and an OS-aware light/dark theme toggle.
* WP-CLI: `wp flex-explorer reset`.

= 0.2.3 =
* Resolve the content directory through `wp_upload_dir()` instead of the `WP_CONTENT_DIR` constant, so the browser root follows custom content and uploads locations.
* Restore the original `zlib.output_compression` setting after a download streams, keeping the change confined to that one request.

= 0.2.2 =
* New: search filenames in the current folder and all subfolders (results are bounded); matching folds multibyte characters where available.

= 0.2.1 =
* Lowered the ZIP size limit to 50 MB so archives stay within typical shared-hosting execution limits.

= 0.2.0 =
* New: download an individual file (sent as an attachment, never rendered inline).
* New: download the current folder as a ZIP, with file-count and total-size limits, skipping symlinks and blocked files.
* Downloads flush pending output buffers and disable on-the-fly compression before streaming, so binary files and archives are never corrupted or truncated.

= 0.1.1 =
* Security: on multisite, restrict access to network super admins instead of every per-site administrator.
* Security: disable the plugin (including its admin menu) when `DISALLOW_FILE_EDIT` is defined as true.

= 0.1.0 =
* Initial release: read-only browsing of wp-content with inline text and image preview.

== Upgrade Notice ==

= 1.4.0 =
First release in the WordPress.org directory. Adds an optional "why are you leaving?" survey on deactivation; nothing is sent unless you deactivate, and a filter turns it off entirely.
