Backify
Full WordPress backup (files + database) to a single zip file with one-click restore.
Install
No release zip yet. The repository archive installs, but the folder name will carry the branch suffix and updates will not flow:
wp plugin install https://github.com/metahiredigital/backify/archive/refs/heads/master.zipBackify — WordPress Backup Plugin
One-click full WordPress backup (files + database) into a single zip archive, with chunked AJAX processing to handle large sites without server timeouts.
Overview
Backify creates a complete snapshot of your WordPress installation — every file and every database table — packaged into a timestamped zip archive stored securely on your server. Backups run through a multi-phase chunked AJAX system, so even large sites with thousands of files never hit proxy or PHP execution time limits.
Features
- Full-site backup — all WordPress files (themes, plugins, uploads, core) + entire database
- Chunked AJAX processing — splits work into short HTTP requests, each well under 60 s proxy timeout
- Real progress tracking — live progress bar with phase labels and file count
- One-click restore — extracts zip and re-imports SQL dump
- Download — download any backup zip directly from the browser
- Delete — remove old backups from the server
- Secure storage — backups directory protected with
.htaccess(Deny from all) andindex.php - No external dependencies — uses only native PHP and WordPress APIs
Requirements
| Requirement | Minimum |
|---|---|
| PHP | 7.4 or higher |
| WordPress | 5.0 or higher |
| PHP extension | ZipArchive (bundled in most hosts) |
| MySQL / MariaDB | Any version supported by WordPress |
| User role | Administrator (manage_options capability) |
Tested PHP Versions
- PHP 7.4
- PHP 8.0
- PHP 8.1
- PHP 8.2
- PHP 8.3
Installation
- Upload the
backifyfolder to/wp-content/plugins/ - Activate the plugin through Plugins → Installed Plugins
- Go to Tools → Backify
- Click Create Backup Now
How It Works
Backup — 4-Phase Chunked Architecture
Backups run as a sequential chain of short AJAX requests rather than one long request. State is persisted between requests using the WordPress Transients API.
Phase 1 — Init → Scan all files, create empty zip (0% → 5%)
Phase 2 — DB Export → Dump all tables, add SQL to zip (5% → 20%)
Phase 3 — Chunks → Add 150 files per request (loops) (20% → 93%)
Phase 4 — Finalize → Rename tmp zip → final zip, cleanup (93% → 100%)
AJAX Actions
| Action | Handler | Role |
|---|---|---|
sb_backup_init |
SB_Backup::init_chunked() |
Scan files, create empty zip, save state transient |
sb_backup_db |
SB_Backup::export_db_chunked() |
Run DB export, add SQL to zip |
sb_backup_chunk |
SB_Backup::process_chunk() |
Add 150 file/dir entries to zip at current offset |
sb_backup_finalize |
SB_Backup::finalize_chunked() |
Rename tmp_backify-*.zip → backify-*.zip, cleanup |
Transient State Schema
[
'backup_id' => 'sb_1716825600_ab12cd34', // validated: /^sb_\d+_[a-f0-9]{8}$/
'filename' => 'backify-2026-05-16-120000-ab12cd34.zip',
'zip_path' => '/path/to/backups/tmp_backify-….zip',
'sql_path' => '/path/to/backups/sb-db-temp-….sql',
'files' => [ ['/full/path', 'local/path', 'file|dir'], … ],
'total' => 12345,
'offset' => 0,
]
Transient TTL is refreshed to HOUR_IN_SECONDS on every chunk request.
Progress Formula (file phase)
pct = 20 + Math.round((offset / total) * 73)
Database Export
Uses WordPress $wpdb directly — no mysqldump binary required.
Per table:
SHOW TABLES— enumerate all tablesSHOW CREATE TABLE— capture schemaSELECT * FROM … LIMIT 500 OFFSET n— export rows in batches of 500- Writes
INSERT INTOstatements row by row
Output format: plain .sql file with SET FOREIGN_KEY_CHECKS guards.
File Scanning & Exclusions
SB_Backup::scan_files() recursively walks ABSPATH and excludes:
- The
backups/directory (prevents zip-in-zip loop) - Standalone
.zipfiles at the WordPress root level
All other files and directories are included: wp-content/, wp-admin/, wp-includes/, config files, etc.
Restore
SB_Restore::run() unpacks the selected zip and re-imports the SQL dump through $wpdb.
Security
| Measure | Implementation |
|---|---|
| Nonce verification | check_ajax_referer('sb_backup', 'nonce') on every AJAX handler |
| Capability check | current_user_can('manage_options') on every handler |
| Backup ID validation | preg_match('/^sb_\d+_[a-f0-9]{8}$/', $backup_id) |
| Filename validation | preg_match('/^backify-[\d]{4}-…-[a-f0-9]{8}\.zip$/') on delete/download |
| Directory hardening | .htaccess (Deny from all) + index.php created on activation |
| Path traversal prevention | basename() + regex validation before any file operation |
File Structure
backify/
├── backify.php # Plugin entry point, constants, activation hook
├── assets/
│ ├── script.js # jQuery AJAX — chunked backup flow, restore, delete
│ └── style.css # Admin UI styles
├── backups/ # Generated backup zips (created on activation)
│ ├── .htaccess # Deny from all
│ └── index.php # Silence is golden
└── includes/
├── class-sb-admin.php # WP admin page, AJAX handlers (8 actions)
├── class-sb-backup.php # Backup logic — run(), chunked API, DB export
└── class-sb-restore.php # Restore logic
PHP Methods & APIs Used
Native PHP
ZipArchive— create, open, append, close zip archivesscandir()— recursive directory traversalfopen()/fwrite()/fclose()— streaming SQL file writesrename()— atomic tmp-to-final zip renameunlink()— temp file cleanuppreg_match()— input validationdate(),time(),uniqid(),md5()— unique filename generation
WordPress APIs
$wpdb->get_col(),get_row(),get_results(),prepare(),_real_escape()— database accessget_transient()/set_transient()/delete_transient()— inter-request statewp_send_json_success()/wp_send_json_error()— AJAX responsescheck_ajax_referer()/wp_create_nonce()— nonce securitycurrent_user_can()— capability gatingwp_normalize_path()— cross-platform path handlingwp_mkdir_p()— recursive directory creationsize_format()— human-readable file sizesadd_management_page()— Tools menu registrationwp_enqueue_style()/wp_enqueue_script()/wp_localize_script()— asset loadingregister_activation_hook()— plugin activation setupWP_Error— structured error handling throughout
Frontend
- jQuery (WordPress bundled) — AJAX calls, DOM manipulation, progress updates
Backup Filename Format
backify-YYYY-MM-DD-HHmmss-{8-char-hex}.zip
Example: backify-2026-05-16-143022-a1b2c3d4.zip
Limitations
- Restore requires the server to have enough memory to extract the zip
- Very large sites (100k+ files) may produce large transients; ensure your DB
wp_optionstable can handle it - Backups are stored on the same server — download copies offsite for true disaster recovery
Author
Sravan M https://hellosravan.in