Skip to content

Release v2.1.0

Latest

Choose a tag to compare

@github-actions github-actions released this 15 May 00:21
· 27 commits to main since this release

Security

  • Private Export Storage: Moved generated export ZIPs out of public uploads and into WordPress' private temporary directory. Exports now fail with an actionable error if the resolved temp directory is inside the WordPress web root.
  • Export Directory Protection: Kept .htaccess and index.php defense-in-depth files in the export directory when the filesystem supports them.
  • Private API Removal: Removed usage of _get_cron_array() (WordPress private/internal function) from cron failure diagnostics. Uses only public APIs (wp_next_scheduled(), wp_schedule_single_event()) now.
  • Filesystem Compatibility: Replaced glob() with scandir() in sse_bulk_cleanup_exports_handler() for cross-platform compatibility and consistency with WordPress filesystem conventions.
  • SSRF Hardening: File download functions now use realpath()-resolved paths for all filesystem operations (readfile(), is_readable(), is_file()), preventing TOCTOU and SSRF attack vectors. sse_validate_file_output_security() now returns the resolved path for direct use.
  • CSP Compliance: Replaced inline onclick JavaScript handler with external js/admin.js file to comply with Content Security Policy headers and prevent inline script execution risks.
  • Native Admin Actions: Switched export, download, and delete handlers to authenticated admin-post.php actions with check_admin_referer() validation.
  • Scheduled Cleanup Hardening: Scheduled export deletion now deletes only the validated export directory path rather than the raw cron argument.
  • Symlink Export Hardening: WordPress file archive creation now skips symbolic links and verifies resolved paths stay within the WordPress root before adding them.
  • WP-CLI Path Hardening: Removed PATH lookup for WP-CLI and now only executes WP-CLI from explicit allowed locations.
  • Download Boundary Hardening: Final download path validation now uses normalized trailing-slash directory containment checks.
  • Destructive Action Hardening: Manual export deletion now uses POST with nonce verification instead of a GET link.
  • Extension Policy Tightening: Export download validation now allows only .zip files.
  • Delete Containment: File deletion now uses WordPress' wp_delete_file_from_directory() containment helper for generated export files.

Bug Fixes

  • Documentation Fix: Corrected README.md Security Features section from "after 1 hour" to "after 5 minutes" to match actual cleanup timer.
  • Unused Variable: Removed unused $export_dir_name variable assignment in sse_exporter_page_html().
  • phpcs Suppression: Removed unnecessary phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped comment on a line already properly escaped with esc_html().
  • GEMINI.md Accuracy: Updated WP-CLI Integration section to reflect that WP-CLI is a required dependency (returns WP_Error if unavailable), replacing outdated "graceful fallback" language.
  • WP-CLI Language: Updated README.md and readme.txt from "when available" to "Requires WP-CLI" to match v2.0.0 behavior.
  • PHPUnit Discovery: Renamed the generated WordPress compatibility test file/class pair to EngineScriptSiteExporterTest so PHPUnit can discover it reliably.
  • WordPress Test Compatibility: Pinned the generated WordPress compatibility test job to PHPUnit 9.6 with Yoast PHPUnit Polyfills 4.x because the WordPress test library still calls PHPUnit APIs removed in PHPUnit 10+.
  • WordPress Compatibility Coverage: Added PHP syntax linting, PHPUnit dependency verification, hook registration checks, constant checks, security helper tests, and a PHP 8.2/latest WordPress lowest-dependency matrix run.
  • Release Packaging: Fixed release and CI package builds to include required includes/, css/, js/, languages/, and readme.txt files.
  • Release Package Hygiene: Excluded Composer files, CI metadata, tests, static-analysis stubs/configs, and source-only docs from generated plugin release packages.
  • Archive Failure Reporting: File archive creation now returns a WP_Error when a file cannot be added instead of logging the failure and reporting success.

Architecture

  • EngineScript Archive Format: Updated exports to match the canonical EngineScript combined site archive: outer ZIP named <site>_enginescript_site_export_<timestamp>.zip, root manifest.txt, database/<site>_db_<timestamp>.sql.gz, and files/<site>_files_<timestamp>.tar.gz.

  • File Splitting: Split monolithic enginescript-site-exporter.php (~1,400 lines) into a 112-line bootstrap file plus 7 focused include files under includes/: helpers.php, security.php, admin-page.php, export.php, archive.php, cleanup.php, download.php. Each file is guarded by ABSPATH check.

  • Plugin File Constant: Added SSE_PLUGIN_FILE constant defined as __FILE__ in bootstrap, used by includes/admin-page.php for plugin_dir_url() calls since __FILE__ resolves to the include path, not the plugin root.

  • Filter Name Constant: Replaced hardcoded 'sse_max_file_size_for_export' filter name string with SSE_FILTER_MAX_FILE_SIZE constant for discoverability.

  • Shell Output Sanitization: Added sanitize_text_field() to WP-CLI error output in sse_export_database() for defense-in-depth.

  • Explicit Null Return: Added explicit return null; to sse_process_file_for_tar() to match PHPDoc return type true|null.

  • RuntimeException Catch: Changed sse_add_wordpress_files_to_tar() to catch RuntimeException specifically before generic Exception fallback.

  • DirectoryIterator: Replaced scandir() with DirectoryIterator in sse_bulk_cleanup_exports_handler() for more efficient file iteration.

  • PHPStan Level Increase: Increased PHPStan analysis level from 5 to 6, added includes/ directory to scan paths.

  • Inline CSS Removal: Extracted 7 inline style attributes from admin page and success notice into dedicated css/admin.css file with semantic CSS classes (sse-section-spacing, sse-form-table, sse-warning-text, sse-action-button).

  • Inline JS Removal: Extracted inline onclick confirmation dialog into dedicated js/admin.js file with a sse-confirm-delete form submit listener.

  • Asset Enqueueing: Added sse_enqueue_admin_assets() function hooked to admin_enqueue_scripts with page-slug check (tools_page_enginescript-site-exporter) to load CSS/JS only on the plugin's admin page. Uses wp_localize_script() for i18n of JavaScript confirmation string.

  • EngineScript Documentation: Clarified that the plugin does not detect EngineScript servers; it produces an EngineScript-compatible archive format usable from any supported WordPress server.

  • Copilot Instructions Revision: Rewrote .github/copilot-instructions.md to remove irrelevant references (WooCommerce, package.json, admin.php), consolidate redundant security subsections, add plugin-specific naming conventions (sse_, SSE_), and fix version file list.

  • WP_Filesystem Helper: Extracted duplicated WP_Filesystem initialization from 4 functions into a single sse_init_filesystem() helper that returns true|WP_Error, reducing ~40 lines of duplicated code to ~10.

  • Removed Wrapper Functions: Inlined 3 pass-through wrapper functions (sse_validate_download_request(), sse_validate_file_deletion(), sse_validate_export_file_for_deletion()) — callers now invoke the underlying functions directly.

  • Download Validation Consolidation: Removed 2 redundant intermediate validation passes (sse_validate_download_file_data(), sse_validate_download_file_access()) from the download flow. Entry validation and final readfile() security gate remain; intermediate re-validation of already-validated data removed.

  • Path Resolution Consolidation: Consolidated 7-function-deep path resolution chain into a single sse_resolve_file_path() function. Removed 6 single-use intermediary functions (sse_resolve_nonexistent_file_path(), sse_get_upload_directory_info(), sse_build_validated_file_path(), sse_validate_parent_directory_safety(), sse_construct_final_file_path(), sse_resolve_parent_directory(), sse_sanitize_filename()).

  • Dead Code Removal: Removed no-op sse_prepare_execution_environment() function and its call from the export flow.

  • Debug Code Removal: Removed sse_test_cron_scheduling() debug function that created/verified/removed a test cron event on every export — no longer needed after v2.0.0 cron fixes.

  • Cron Logging Reduction: Reduced cron scheduling functions from 5+ log entries each to 2 (success/failure), keeping DISABLE_WP_CRON diagnostic on failure only.

PHP 8.2 Baseline

  • Minimum PHP Version: Raised the supported PHP baseline to 8.2 across plugin metadata, Composer, PHPCS, documentation, and GitHub guidance.
  • CI Compatibility Matrix: Updated WordPress compatibility testing to cover PHP 8.2, 8.3, 8.4, and 8.5.
  • PHPUnit Tooling: Updated PHPUnit and Yoast PHPUnit Polyfills constraints for the PHP 8.2+ baseline.
  • QA Tooling Constraints: Kept PHPCS on the stable WPCS/PHPCompatibility-compatible 3.13 line, added PHPMD as a Composer-managed dev dependency, and aligned workflow-installed coding standards with current stable package constraints.
  • Type Declarations: Added parameter types and return types to all functions where deterministic.
  • Short Array Syntax: Standardized all array() constructor calls to short [] syntax throughout the plugin.
  • Null Coalescing Assignment: Replaced explicit null check + assignment pattern with ??= in sse_should_exclude_file() file size cache, and ?: Elvis operator for the ternary fallback.
  • PHPStan Array Shapes: Added PHPStan array{} shape annotations to all functions accepting or returning associative arrays, resolving 10 level-6 "no value type specified in iterable type array" errors.
  • Trailing Whitespace: Removed trailing whitespace (tabs on blank lines) across export.php, download.php, cleanup.php, admin-page.php, and security.php.
  • JS File Header: Converted admin.js file header from JSDoc (/** @package, @since) to plain block comment to avoid TSDoc linter false positives.
  • Bulk Cleanup Complexity: Extracted per-file deletion logic from sse_bulk_cleanup_exports_handler() into sse_cleanup_expired_export_file() helper, reducing cyclomatic complexity from 13 to 8 and NPath complexity from 336 to under 200.
  • PHPStan Array Shape: Added array{filepath: string, filename: string} shape annotation to sse_validate_export_file_path() return type in security.php, resolving level-6 error.
  • PHPStan Ignore Cleanup: Removed three obsolete ignoreErrors patterns from phpstan.neon ($post, $wp_query, $wpdb) that are now resolved by the WordPress stubs.

Installation

  1. Download the zip file
  2. Upload to your WordPress site through the Plugins > Add New > Upload menu
  3. Activate the plugin

Full Documentation