Releases: EngineScript/enginescript-site-exporter
Release v2.1.0
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
.htaccessandindex.phpdefense-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()withscandir()insse_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
onclickJavaScript handler with externaljs/admin.jsfile 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.phpactions withcheck_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
.zipfiles. - 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_namevariable assignment insse_exporter_page_html(). - phpcs Suppression: Removed unnecessary
phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscapedcomment on a line already properly escaped withesc_html(). - GEMINI.md Accuracy: Updated WP-CLI Integration section to reflect that WP-CLI is a required dependency (returns
WP_Errorif 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
EngineScriptSiteExporterTestso 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/, andreadme.txtfiles. - 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_Errorwhen 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, rootmanifest.txt,database/<site>_db_<timestamp>.sql.gz, andfiles/<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 underincludes/:helpers.php,security.php,admin-page.php,export.php,archive.php,cleanup.php,download.php. Each file is guarded byABSPATHcheck. -
Plugin File Constant: Added
SSE_PLUGIN_FILEconstant defined as__FILE__in bootstrap, used byincludes/admin-page.phpforplugin_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 withSSE_FILTER_MAX_FILE_SIZEconstant for discoverability. -
Shell Output Sanitization: Added
sanitize_text_field()to WP-CLI error output insse_export_database()for defense-in-depth. -
Explicit Null Return: Added explicit
return null;tosse_process_file_for_tar()to match PHPDoc return typetrue|null. -
RuntimeException Catch: Changed
sse_add_wordpress_files_to_tar()to catchRuntimeExceptionspecifically before genericExceptionfallback. -
DirectoryIterator: Replaced
scandir()withDirectoryIteratorinsse_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
styleattributes from admin page and success notice into dedicatedcss/admin.cssfile with semantic CSS classes (sse-section-spacing,sse-form-table,sse-warning-text,sse-action-button). -
Inline JS Removal: Extracted inline
onclickconfirmation dialog into dedicatedjs/admin.jsfile with asse-confirm-deleteform submit listener. -
Asset Enqueueing: Added
sse_enqueue_admin_assets()function hooked toadmin_enqueue_scriptswith page-slug check (tools_page_enginescript-site-exporter) to load CSS/JS only on the plugin's admin page. Useswp_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.mdto 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_Filesysteminitialization from 4 functions into a singlesse_init_filesystem()helper that returnstrue|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 finalreadfile()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_CRONdiagnostic 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
??=insse_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 W...
Release v2.0.0
Critical Bug Fixes
- Scheduled Deletion Fix: Fixed critical bug where automatic export file cleanup via WordPress cron was completely broken. The referer validation in
sse_validate_basic_export_file()was blocking all cron-triggered deletions since scheduled tasks have no HTTP referer. Referer checks are now correctly applied only to user-facing download and deletion handlers. - Deletion Notice Fix: Fixed bug where success/failure notices after manually deleting an export file were lost due to
add_action('admin_notices')being registered beforewp_safe_redirect()+exit. Notices are now passed via query parameter and displayed on the redirected page.
Security & Escaping Fixes
- Double Escaping Prevention: Fixed 9 instances of double-escaped WP_Error messages where
esc_html__()was used in error construction but messages were escaped again withesc_html()at output time. Changed to__()in WP_Error constructors since escaping belongs at the output boundary. - Admin Menu Escaping: Removed redundant
esc_html__()insse_admin_menu()— WordPress core already escapes page and menu titles internally. - Submit Button Escaping: Removed redundant
esc_html__()insubmit_button()call — the function internally appliesesc_attr()to button text. - Database Export Error: Removed pre-escaping of WP-CLI error output in
sse_export_database()WP_Error to prevent double escaping when displayed viasse_show_error_notice(). - Symlink Compatibility: Removed overly strict
realpath()equality check insse_validate_download_file_access()that could block valid downloads on servers with symlinked upload directories. Directory containment validation already provides equivalent security.
Performance Improvements
- File Size Filter Caching: Cached the
sse_max_file_size_for_exportfilter result using a static variable insse_should_exclude_file()to avoid redundantget_transient(),get_current_user_id(), andapply_filters()calls for every file during export. - Error Log Autoload: Added
falseautoload parameter toupdate_option()insse_store_log_in_database()to prevent debug logs from being loaded into memory on every WordPress page request.
Code Quality
- Dead Code Removal: Removed unused
sse_get_scheduled_deletions()debugging function that was never called from any code path. - Shell Safety: Added
function_exists('shell_exec')check insse_get_safe_wp_cli_path()before attempting PATH lookup, preventing PHP warnings whenshell_execis disabled. - POT File Cleanup: Removed 6 stale translation entries referencing functions that no longer exist. Added missing translatable strings for file size options, error messages, and WP-CLI status messages.
- GEMINI.md: Updated version reference from 1.8.4 to 1.9.1.
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.9.2
Critical Bug Fixes
- Scheduled Deletion Fix: Fixed critical bug where automatic export file cleanup via WordPress cron was completely broken. The referer validation in
sse_validate_basic_export_file()was blocking all cron-triggered deletions since scheduled tasks have no HTTP referer. Referer checks are now correctly applied only to user-facing download and deletion handlers. - Deletion Notice Fix: Fixed bug where success/failure notices after manually deleting an export file were lost due to
add_action('admin_notices')being registered beforewp_safe_redirect()+exit. Notices are now passed via query parameter and displayed on the redirected page.
Security & Escaping Fixes
- Double Escaping Prevention: Fixed 9 instances of double-escaped WP_Error messages where
esc_html__()was used in error construction but messages were escaped again withesc_html()at output time. Changed to__()in WP_Error constructors since escaping belongs at the output boundary. - Admin Menu Escaping: Removed redundant
esc_html__()insse_admin_menu()— WordPress core already escapes page and menu titles internally. - Submit Button Escaping: Removed redundant
esc_html__()insubmit_button()call — the function internally appliesesc_attr()to button text. - Database Export Error: Removed pre-escaping of WP-CLI error output in
sse_export_database()WP_Error to prevent double escaping when displayed viasse_show_error_notice(). - Symlink Compatibility: Removed overly strict
realpath()equality check insse_validate_download_file_access()that could block valid downloads on servers with symlinked upload directories. Directory containment validation already provides equivalent security.
Performance Improvements
- File Size Filter Caching: Cached the
sse_max_file_size_for_exportfilter result using a static variable insse_should_exclude_file()to avoid redundantget_transient(),get_current_user_id(), andapply_filters()calls for every file during export. - Error Log Autoload: Added
falseautoload parameter toupdate_option()insse_store_log_in_database()to prevent debug logs from being loaded into memory on every WordPress page request.
Code Quality
- Dead Code Removal: Removed unused
sse_get_scheduled_deletions()debugging function that was never called from any code path. - Shell Safety: Added
function_exists('shell_exec')check insse_get_safe_wp_cli_path()before attempting PATH lookup, preventing PHP warnings whenshell_execis disabled. - POT File Cleanup: Removed 6 stale translation entries referencing functions that no longer exist. Added missing translatable strings for file size options, error messages, and WP-CLI status messages.
- GEMINI.md: Updated version reference from 1.8.4 to 1.9.1.
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.9.1
Scheduled Deletion System Enhancements
- Enhanced Debugging: Added comprehensive debugging system with
error_log()output for WordPress cron troubleshooting when standard debug logging is disabled - Dual Cleanup System: Implemented redundant scheduled deletion with both individual file cleanup (5 minutes) and bulk directory cleanup (10 minutes) as safety net
- Bulk Cleanup Handler: Added
sse_bulk_cleanup_exports_handler()to scan and clean all export files older than 5 minutes from the entire export directory - Improved Scheduling: Enhanced
sse_schedule_export_cleanup()with detailed logging, DISABLE_WP_CRON detection, and WordPress cron array status monitoring - Test Framework: Added
sse_test_cron_scheduling()function to verify WordPress cron functionality before attempting real scheduling - Cron Diagnostics: Implemented
sse_get_scheduled_deletions()for debugging scheduled events and cron system status - Verification System: Added post-scheduling verification to confirm events are properly added to WordPress cron schedule
Code Quality Improvements
- WordPress VIP Compliance: Replaced direct PHP filesystem function
is_writable()with WordPress Filesystem API (WP_Filesystem) for VIP coding standards compliance - Filesystem API Integration: Added proper WordPress filesystem initialization with error handling in export preparation function
- Code Style: Fixed variable alignment inconsistencies in
sse_test_cron_scheduling()function to maintain consistent spacing standards
Bug Fixes
- Scheduled Deletion: Resolved issue where export files were not being automatically deleted due to WordPress cron scheduling failures
- Fallback System: Removed unnecessary fallback methods as requested, streamlining the system to use only WordPress cron
- Error Logging: Improved error visibility by adding direct
error_log()output for cron debugging when WordPress debug settings are disabled - Export Directory Consistency: Centralized export directory naming via
SSE_EXPORT_DIR_NAMEconstant to eliminate mismatched cleanup paths and ensure all subsystems reference the same location - Filesystem Validation: Added explicit directory creation and writability checks with helpful error messaging when the exports folder can't be prepared
- CI Database Service: Replaced the GitHub Actions MySQL 5.7 test container with MariaDB 10.6 to avoid Docker Hub authentication failures while maintaining WordPress compatibility coverage
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.9.0
Performance Enhancements
- Export Locking: Implemented a lock using transients (
sse_export_lock) to prevent concurrent export processes and reduce server load. - User-Configurable File Size Limits: Added a user-friendly dropdown in the export form to exclude files larger than selected sizes (100MB, 500MB, 1GB, or no limit).
Code Quality Improvements
- Centralized Configuration: Created
SSE_ALLOWED_EXTENSIONSconstant to eliminate code duplication for file extension validation. - Unified Validation: Consolidated file extension validation logic into a single reusable function.
User Experience Improvements
- Enhanced Export Form: Added intuitive file size limit selection directly in the export interface, eliminating the need for developers to write custom filter code.
Security Hardening
- WP-CLI Verification: Added executable/existence verification for PATH-discovered WP-CLI binary
- Error Output Sanitization: Sanitized WP-CLI failure output (path masking, line limiting) to prevent filesystem disclosure
- Graceful Scheduled Deletion: Treats missing file during scheduled cleanup as info (likely already removed) instead of error
- Conditional Root Flag: Added conditional inclusion of
--allow-rootonly when actually running as root - Strict Download Validation: Hardened download file data validation (type checks, required keys, numeric size enforcement)
- Secure File Data Handling: Added stronger sanitization and non-positive size rejection before serving downloads
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.8.4
Code Quality Improvements
- WordPress Coding Standards: Comprehensive PHPCS compliance fixes across all functions
- Fixed function documentation block spacing and alignment
- Standardized parameter formatting with proper spacing (e.g.,
function( $param )) - Corrected Yoda conditions for all boolean comparisons (e.g.,
false === $variable) - Aligned array formatting with consistent spacing (e.g.,
'key' => 'value') - Fixed multi-line function call formatting and indentation
- Resolved all remaining WordPress coding standards violations
- Code Consistency: Enhanced code readability and maintainability through standardized formatting
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.8.3
WordPress Plugin Directory Compliance
- Text Domain Fix: Updated text domain from 'Simple-WP-Site-Exporter' to 'simple-wp-site-exporter' (lowercase) to comply with WordPress.org plugin directory requirements
- Load Textdomain Removal: Removed discouraged
load_plugin_textdomain()function call as WordPress automatically handles translations for plugins hosted on WordPress.org since version 4.6 - Plugin Header Update: Fixed "Text Domain" header to use only lowercase letters, numbers, and hyphens as required by WordPress standards
Security Fix
- Critical Security Fix: Resolved a fatal error caused by a missing
sse_get_safe_wp_cli_path()function. This function is essential for securely locating the WP-CLI executable, and its absence prevented the database export process from running. The new function ensures that the plugin can reliably find WP-CLI in common locations, allowing the export to proceed as intended.
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.8.2
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.8.1
Documentation Workflow Updates
- Version Control: Removed
changelog.txtfile to streamline documentation; maintaining onlyreadme.txt(WordPress.org) andCHANGELOG.md(for developers).
Code Standards Compliance
- Indentation: Fixed tab indentation violations in
sse_handle_secure_download()andsse_handle_export_deletion()functions to use spaces as required by WordPress coding standards.
1.8.1 - June 26, 2025
WordPress Standards Compliance Enhancement
- WordPress Baseline: Updated minimum WordPress version requirement from 6.0 to 6.5+ for better compatibility
- Internationalization: Added complete i18n support with
load_plugin_textdomain()and.potfile generation - Language Files: Created
languages/simple-wp-site-exporter.potwith all translatable strings - Documentation Consistency: Updated README.md, readme.txt, and phpcs.xml to reflect WordPress 6.5+ baseline
- Workflow Updates: Modified compatibility testing to use WordPress 6.5+ as minimum test version
- Standards Alignment: Ensured all code, workflows, and documentation strictly follow WordPress coding standards
Critical Security Fix
- SECURITY: Resolved Server-Side Request Forgery (SSRF) vulnerability in
sse_resolve_parent_directory()function - Filesystem Security: Removed
is_dir()andis_readable()filesystem checks on user-controlled input - Attack Prevention: Eliminated potential filesystem structure probing and information disclosure
- Path Validation: Refactored to use safe string-based path validation while maintaining security
- Codacy Compliance: Addressed "File name based on user input risks server-side request forgery" detection
- Defense in Depth: Maintained multiple layers of path validation without filesystem probing
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin
Release v1.8.0
WordPress Standards Compliance Enhancement
- WordPress Baseline: Updated minimum WordPress version requirement from 6.0 to 6.5+ for better compatibility
- Internationalization: Added complete i18n support with
load_plugin_textdomain()and.potfile generation - Language Files: Created
languages/simple-wp-site-exporter.potwith all translatable strings - Version Control: Added
changelog.txtfile as specified in copilot instructions for complete version documentation - Documentation Consistency: Updated README.md, readme.txt, and phpcs.xml to reflect WordPress 6.5+ baseline
- Workflow Updates: Modified compatibility testing to use WordPress 6.5+ as minimum test version
- Standards Alignment: Ensured all code, workflows, and documentation strictly follow WordPress coding standards
Critical Security Fix
- SECURITY: Resolved Server-Side Request Forgery (SSRF) vulnerability in
sse_resolve_parent_directory()function - Filesystem Security: Removed
is_dir()andis_readable()filesystem checks on user-controlled input - Attack Prevention: Eliminated potential filesystem structure probing and information disclosure
- Path Validation: Refactored to use safe string-based path validation while maintaining security
- Codacy Compliance: Addressed "File name based on user input risks server-side request forgery" detection
- Defense in Depth: Maintained multiple layers of path validation without filesystem probing
Installation
- Download the zip file
- Upload to your WordPress site through the Plugins > Add New > Upload menu
- Activate the plugin