{"id":368952,"date":"2026-09-21T19:19:18","date_gmt":"2026-09-21T19:19:18","guid":{"rendered":"https:\/\/wordpress.org\/plugins\/sitecarry\/"},"modified":"2026-09-21T19:44:03","modified_gmt":"2026-09-21T19:44:03","slug":"sitecarry","status":"publish","type":"plugin","link":"https:\/\/pcd.wordpress.org\/plugins\/sitecarry\/","author":23562247,"comment_status":"closed","ping_status":"closed","template":"","meta":{"version":"1.31.1","stable_tag":"1.31.1","tested":"7.1.2","requires":"6.2","requires_php":"7.4","requires_plugins":null,"header_name":"Sitecarry","header_author":"Usman","header_description":"Backup, clone and migrate any WordPress site \u2014 files and database in one restorable package.","assets_banners_color":"59646b","last_updated":"2026-09-21 19:44:03","external_support_url":"","external_repository_url":"","donate_link":"","header_plugin_uri":"https:\/\/dotance.com\/plugins\/sitecarry\/","header_author_uri":"https:\/\/dotance.com","rating":0,"author_block_rating":0,"active_installs":0,"downloads":59,"num_ratings":0,"support_threads":0,"support_threads_resolved":0,"author_block_count":0,"sections":["description","installation","faq","changelog"],"tags":{"1.31.0":{"tag":"1.31.0","author":"dotance","date":"2026-09-21 19:18:55","revision":3706208},"1.31.1":{"tag":"1.31.1","author":"dotance","date":"2026-09-21 19:44:03","revision":3706237}},"upgrade_notice":{"1.15.0":"<p>Housekeeping and a proper uninstall. Deleting the plugin now clears its settings and\nschedules; your backup packages are left where they are.<\/p>","1.14.0":"<p>Fixes ten bugs, most of them cases where an interrupted backup could resume into a\ncorrupt archive. Worth taking.<\/p>"},"ratings":[],"assets_icons":{"icon-128x128.png":{"filename":"icon-128x128.png","revision":3706208,"resolution":"128x128","location":"assets","locale":"","width":128,"height":128},"icon-256x256.png":{"filename":"icon-256x256.png","revision":3706208,"resolution":"256x256","location":"assets","locale":"","width":256,"height":256}},"assets_banners":{"banner-1544x500.png":{"filename":"banner-1544x500.png","revision":3706208,"resolution":"1544x500","location":"assets","locale":"","width":1544,"height":500},"banner-772x250.png":{"filename":"banner-772x250.png","revision":3706208,"resolution":"772x250","location":"assets","locale":"","width":772,"height":250}},"assets_blueprints":{},"all_blocks":[],"tagged_versions":["1.31.0","1.31.1"],"block_files":[],"assets_screenshots":{"screenshot-1.png":{"filename":"screenshot-1.png","revision":3706223,"resolution":"1","location":"assets","locale":"","width":1280,"height":1200},"screenshot-2.png":{"filename":"screenshot-2.png","revision":3706223,"resolution":"2","location":"assets","locale":"","width":1280,"height":1382},"screenshot-3.png":{"filename":"screenshot-3.png","revision":3706223,"resolution":"3","location":"assets","locale":"","width":1280,"height":1753},"screenshot-4.png":{"filename":"screenshot-4.png","revision":3706223,"resolution":"4","location":"assets","locale":"","width":1280,"height":653}},"screenshots":{"1":"Every package, whether it has been proven to restore, and what has actually happened over the past month \u2014 with one line at the top for the only question that matters: is this site protected right now.","2":"When backups run, how many are kept, and the weekly rehearsal that proves the newest one still restores.","3":"Sending finished packages to Google Drive, Amazon S3, anything that speaks the same protocol, or FTP \u2014 each with the set-up it honestly takes, and the error you get when you miss a step.","4":"Being told when a backup fails, by email or into Slack or Discord."}},"plugin_section":[],"plugin_tags":[151,10698,10718,152,23756],"plugin_category":[59],"plugin_contributors":[280364],"plugin_business_model":[],"class_list":["post-368952","plugin","type-plugin","status-publish","hentry","plugin_tags-backup","plugin_tags-cloud-backup","plugin_tags-database-backup","plugin_tags-restore","plugin_tags-site-migration","plugin_category-utilities-and-tools","plugin_contributors-dotance","plugin_committers-dotance"],"banners":{"banner":"https:\/\/ps.w.org\/sitecarry\/assets\/banner-772x250.png?rev=3706208","banner_2x":"https:\/\/ps.w.org\/sitecarry\/assets\/banner-1544x500.png?rev=3706208","banner_rtl":false,"banner_2x_rtl":false},"icons":{"svg":false,"icon":"https:\/\/ps.w.org\/sitecarry\/assets\/icon-128x128.png?rev=3706208","icon_2x":"https:\/\/ps.w.org\/sitecarry\/assets\/icon-256x256.png?rev=3706208","generated":false},"screenshots":[{"src":"https:\/\/ps.w.org\/sitecarry\/assets\/screenshot-1.png?rev=3706223","caption":"Every package, whether it has been proven to restore, and what has actually happened over the past month \u2014 with one line at the top for the only question that matters: is this site protected right now."},{"src":"https:\/\/ps.w.org\/sitecarry\/assets\/screenshot-2.png?rev=3706223","caption":"When backups run, how many are kept, and the weekly rehearsal that proves the newest one still restores."},{"src":"https:\/\/ps.w.org\/sitecarry\/assets\/screenshot-3.png?rev=3706223","caption":"Sending finished packages to Google Drive, Amazon S3, anything that speaks the same protocol, or FTP \u2014 each with the set-up it honestly takes, and the error you get when you miss a step."},{"src":"https:\/\/ps.w.org\/sitecarry\/assets\/screenshot-4.png?rev=3706223","caption":"Being told when a backup fails, by email or into Slack or Discord."}],"raw_content":"<!--section=description-->\n<p>Sitecarry builds a single package containing your site's files and a full database\nexport, then lets you download it from the WordPress admin.<\/p>\n\n<p>The build runs in short, resumable slices, so it works on shared hosting where a\nsingle PHP request is capped at 30 seconds. If a request times out, the next one\npicks up exactly where the last one stopped.<\/p>\n\n<p>Each package comes with a standalone installer that restores it onto any server \u2014\nthe same file works for moving a site to new hosting, cloning live to staging, or\nrolling a site back.<\/p>\n\n<p><strong>What it does<\/strong><\/p>\n\n<ul>\n<li>Full site package: files plus a complete SQL export<\/li>\n<li>Your <code>wp-config.php<\/code> is never archived, so the database password and the login\nkeys and salts stay on the server; the restore writes that file itself<\/li>\n<li>Scheduled backups \u2014 hourly, twice daily, daily or weekly, with retention<\/li>\n<li>Optional incremental file backups, with automatic full backups in between<\/li>\n<li>Upload to Amazon S3, any S3-compatible storage, FTP or Google Drive<\/li>\n<li>Restore straight from storage when the archives are no longer on the server<\/li>\n<li>Email or Slack\/Discord notification when a backup fails<\/li>\n<li>Verify that a package is intact, from the admin or WP-CLI<\/li>\n<li><strong>Rehearse a backup<\/strong>, by hand or every week \u2014 import it into scratch tables, check\nthe row count, prove the result would work as a site, and\nconfirm serialized data survives a domain change. Then throw the tables away.\nNothing on the site is touched<\/li>\n<li>WP-CLI commands for backing up, listing, verifying and checking status<\/li>\n<li>Backups run in the background \u2014 start one and close the tab<\/li>\n<li>Resumable build and resumable restore \u2014 both survive short PHP execution limits<\/li>\n<li>Live progress throughout<\/li>\n<li>Standalone <code>installer.php<\/code>: no WordPress needed on the target server<\/li>\n<li>Serialization-safe URL rewriting, so page builder content survives the move<\/li>\n<li>Skips caches, <code>node_modules<\/code>, <code>.git<\/code>, and other backup plugins' folders, which is\nusually the difference between a 400MB package and a 40GB one<\/li>\n<li>Records a manifest describing the origin site (URLs, table prefix, versions)<\/li>\n<\/ul>\n\n<p><strong>Why URL rewriting is the hard part<\/strong><\/p>\n\n<p>WordPress stores a lot of settings as PHP serialized data, where every string\ncarries its own byte length. Replacing an old domain with a longer one using a\nplain search and replace breaks those lengths, and WordPress can then no longer\nread the value \u2014 which is how a migration quietly wipes widget settings and page\nbuilder layouts. Sitecarry rewrites the serialized form directly and repairs the\nlengths, and it also handles the JSON-escaped form (<code>https:\\\/\\\/<\/code>) that page\nbuilders such as Elementor store their content in.<\/p>\n\n<p><strong>Security<\/strong><\/p>\n\n<p>Packages contain a complete copy of your database. Sitecarry stores them in a\nprotected folder with an unguessable filename, blocks direct web access via\n    .htaccess and <code>web.config<\/code>, and serves downloads only through an authenticated\nadmin request \u2014 never a public URL.<\/p>\n\n<p>Every package has its own restore passphrase, shown in the admin and kept out of\nthe archive. The installer refuses to do anything without it, so an installer\nleft behind on a server cannot be used by anyone else to overwrite the site. It\nalso deletes itself and the archive when the restore finishes.<\/p>\n\n<h3>External services<\/h3>\n\n<p>Out of the box Sitecarry talks to nothing but your own server. It contacts an\noutside service only when you switch one on, and only with what that service needs\nto do its job. It never sends usage data, analytics or licence checks anywhere.<\/p>\n\n<p><strong>Amazon S3, or any S3-compatible storage<\/strong> \u2014 used only when you set Storage to S3.\nSitecarry sends your backup archives, and the requests needed to list and delete\nthem, to the endpoint you enter (by default <code>https:\/\/s3.&lt;region&gt;.amazonaws.com<\/code>, or\nyour own for Backblaze B2, Wasabi, DigitalOcean Spaces, MinIO and so on). What is\nsent: the archive itself \u2014 which contains your site's files and a full database\nexport \u2014 plus the access key you configured, used to sign each request. Nothing is\nsent until you save S3 credentials and run a backup.\nFor any other S3-compatible provider, the terms are that provider's own.<\/p>\n\n<ul>\n<li>Service: Amazon S3, provided by Amazon Web Services (<code>amazonaws.com<\/code>)<\/li>\n<li>Terms of service: <a href=\"https:\/\/aws.amazon.com\/service-terms\/\">https:\/\/aws.amazon.com\/service-terms\/<\/a><\/li>\n<li>Privacy policy: <a href=\"https:\/\/aws.amazon.com\/privacy\/\">https:\/\/aws.amazon.com\/privacy\/<\/a><\/li>\n<\/ul>\n\n<p><strong>FTP \/ FTPS server<\/strong> \u2014 used only when you set Storage to FTP. Sitecarry connects to\nthe host, port and path you enter and uploads the same archives, authenticating with\nthe username and password you configured. The server is one you choose, so its terms\nare your host's. Plain FTP sends that password and the whole archive unencrypted;\nthe settings screen recommends FTP over TLS for this reason.<\/p>\n\n<p><strong>Google Drive<\/strong> \u2014 used only when you set Storage to Google Drive and complete the\nconnection. Sitecarry sends you to <code>https:\/\/accounts.google.com<\/code> to authorise,\nexchanges the code at <code>https:\/\/oauth2.googleapis.com\/token<\/code>, and uploads, lists and\ndeletes archives through <code>https:\/\/www.googleapis.com\/drive\/v3<\/code> and\n    https:\/\/www.googleapis.com\/upload\/drive\/v3. What is sent: the archives, and an\nOAuth token belonging to the Google account you authorise. The connection uses an\nOAuth client you create yourself, so the traffic is between your site and Google \u2014\nit is not routed through us. Only the <code>drive.file<\/code> scope is requested, which limits\nSitecarry to files it created itself.<\/p>\n\n<ul>\n<li>Service: Google Drive API, provided by Google (<code>googleapis.com<\/code>, <code>accounts.google.com<\/code>)<\/li>\n<li>Terms of service: <a href=\"https:\/\/policies.google.com\/terms\">https:\/\/policies.google.com\/terms<\/a> and <a href=\"https:\/\/developers.google.com\/terms\">https:\/\/developers.google.com\/terms<\/a><\/li>\n<li>Privacy policy: <a href=\"https:\/\/policies.google.com\/privacy\">https:\/\/policies.google.com\/privacy<\/a><\/li>\n<\/ul>\n\n<p><strong>Slack, Discord, or any incoming webhook<\/strong> \u2014 used only when you enter a webhook URL\non the Notifications screen. Sitecarry posts a short message to that URL when a\nbackup finishes or fails: the site name, the outcome, the step it stopped on and the\nerror text. No archive and no credentials are sent. The destination is the URL you\nsupply, commonly <code>https:\/\/hooks.slack.com\/...<\/code>.<\/p>\n\n<ul>\n<li>Service: Slack incoming webhooks (<code>hooks.slack.com<\/code>)<\/li>\n<li>Terms of service: <a href=\"https:\/\/slack.com\/terms-of-service\">https:\/\/slack.com\/terms-of-service<\/a><\/li>\n<li>Privacy policy: <a href=\"https:\/\/slack.com\/trust\/privacy\/privacy-policy\">https:\/\/slack.com\/trust\/privacy\/privacy-policy<\/a><\/li>\n<li>Service: Discord webhooks (<code>discord.com<\/code>)<\/li>\n<li>Terms of service: <a href=\"https:\/\/discord.com\/terms\">https:\/\/discord.com\/terms<\/a><\/li>\n<li>Privacy policy: <a href=\"https:\/\/discord.com\/privacy\">https:\/\/discord.com\/privacy<\/a><\/li>\n<\/ul>\n\n<p><strong>Your own site<\/strong> \u2014 Sitecarry sends an HTTP request to your site's own\n    admin-ajax.php to start and continue a background backup. That is a loopback\nrequest to your server, not a third party.<\/p>\n\n<!--section=installation-->\n<ol>\n<li>Upload the plugin folder to <code>\/wp-content\/plugins\/<\/code>.<\/li>\n<li>Activate it through the <strong>Plugins<\/strong> screen.<\/li>\n<li>Open <strong>Sitecarry<\/strong> in the admin menu and click <strong>Create Backup<\/strong>.<\/li>\n<\/ol>\n\n<!--section=faq-->\n<dl>\n<dt id=\"where%20are%20packages%20stored%3F\"><h3>Where are packages stored?<\/h3><\/dt>\n<dd><p>In <code>wp-content\/uploads\/sitecarry\/<\/code>, protected from direct web access.<\/p><\/dd>\n<dt id=\"what%20happens%20if%20i%20delete%20the%20plugin%3F\"><h3>What happens if I delete the plugin?<\/h3><\/dt>\n<dd><p>Sitecarry removes its settings and its scheduled events from the database, and stops\nscheduling anything. Your packages in <code>wp-content\/uploads\/sitecarry\/<\/code> are left\nexactly where they are, on purpose \u2014 deleting a plugin should never be the thing\nthat destroys your last copy of the site. Delete that folder yourself once you are\nsure you no longer need what is in it.<\/p><\/dd>\n<dt id=\"it%20says%20to%20keep%20the%20tab%20open.%20why%3F\"><h3>It says to keep the tab open. Why?<\/h3><\/dt>\n<dd><p>Background backups need the site to be able to send an HTTP request to itself. Some\nhosts block that. When Sitecarry detects it cannot, it falls back to running the\nbackup from your browser instead, which works everywhere but needs the tab left\nopen. Ask your host to allow loopback requests if you want unattended backups.<\/p><\/dd>\n<dt id=\"how%20do%20i%20roll%20this%20site%20back%20to%20a%20package%3F\"><h3>How do I roll this site back to a package?<\/h3><\/dt>\n<dd><p>Press <strong>Get installer<\/strong> next to the package, and <strong>Download archive<\/strong> under More.\nUpload both files into this site's folder \u2014 the one that holds wp-admin \u2014 and open\n    installer.php in a browser. You will need the package passphrase, shown beside the\npackage, and this site's database password. Your stored packages are not touched.<\/p>\n\n<p>A restore replaces the very files WordPress is running from, so it cannot be done\nfrom inside WordPress, and a plugin has no business writing a program into your site\nfolder to do it. That upload is yours to make.<\/p><\/dd>\n<dt id=\"a%20backup%20seems%20stuck.%20what%20do%20i%20do%3F\"><h3>A backup seems stuck. What do I do?<\/h3><\/dt>\n<dd><p>While a backup is running there is a <strong>Stop backup<\/strong> button under the progress bar,\nand it will tell you if that backup has stopped making progress. Stopping clears\naway the half-built package. From the command line, <code>wp sitecarry stop<\/code> does the\nsame \u2014 useful if the admin screen is not loading.<\/p>\n\n<p>Nothing is lost by stopping: a partial package cannot be restored from anyway.<\/p><\/dd>\n<dt id=\"can%20i%20run%20backups%20from%20the%20command%20line%3F\"><h3>Can I run backups from the command line?<\/h3><\/dt>\n<dd><p>Yes. <code>wp sitecarry backup<\/code> builds one and waits for it, with no execution limit and\nnothing to keep open. <code>wp sitecarry verify --all<\/code> checks every package and exits\nnon-zero if any fails, so it works in a monitoring script. <code>wp sitecarry status<\/code>\nprints how the site is protected.<\/p><\/dd>\n<dt id=\"does%20verifying%20prove%20the%20backup%20will%20restore%3F\"><h3>Does verifying prove the backup will restore?<\/h3><\/dt>\n<dd><p>No, and nothing short of restoring it does. Verifying proves the archive is the one\nthat was written, still opens, and holds the files a restore starts from. That\ncatches truncated uploads, disks that filled mid-write and silent corruption. It\ncannot tell you the database inside will import cleanly on a different server.<\/p>\n\n<p>That last gap is exactly what rehearsing closes \u2014 see the next two questions.<\/p><\/dd>\n<dt id=\"what%20is%20the%20difference%20between%20verifying%20and%20rehearsing%3F\"><h3>What is the difference between verifying and rehearsing?<\/h3><\/dt>\n<dd><p>Verifying reads the archive: it confirms the file is the one that was written, that\nit still opens, and that the two files a restore cannot start without are inside. It\ntakes seconds and it cannot tell you the database will import.<\/p>\n\n<p>Rehearsing imports it. The whole database export is run into tables of the plugin's\nown, the row count is compared against what was recorded at backup time, and the\ntables are then dropped. Nothing on your site is written to at any point.<\/p>\n\n<p>That is the difference between \"this file is intact\" and \"this backup works\".<\/p><\/dd>\n<dt id=\"can%20it%20rehearse%20on%20its%20own%3F\"><h3>Can it rehearse on its own?<\/h3><\/dt>\n<dd><p>Yes. Turn on <strong>Rehearse weekly<\/strong> in Settings and Sitecarry proves the newest full\nbackup once a week, on Sunday, three hours after your backup hour. You hear from it\nonly when it fails \u2014 the same failures-only rule backups use, for the same reason: a\nweekly all-clear stops being read within a month and takes the important one with it.<\/p>\n\n<p>The hour is not a setting on purpose. It follows the backup hour so the two cannot be\npointed at each other, and a rehearsal stands aside if it finds a backup running.<\/p>\n\n<p>What gets rehearsed is the newest package that stands on its own. With incremental\nbackups on, the newest package is usually a difference, so it walks back to the most\nrecent full one rather than skipping that week.<\/p><\/dd>\n<dt id=\"is%20rehearsing%20safe%20to%20run%20on%20a%20live%20site%3F\"><h3>Is rehearsing safe to run on a live site?<\/h3><\/dt>\n<dd><p>Yes, and it is built to be. Every table it creates carries a prefix of its own, every\nstatement is checked to be acting on one of those tables before it runs, and the\ntables are dropped whether the rehearsal passes, fails or is interrupted. Anything a\ncrash leaves behind is swept away within a day.<\/p>\n\n<p>It does use processor time and, briefly, database space roughly the size of your\ndatabase. It will not start while a backup is running.<\/p><\/dd>\n<dt id=\"what%20does%20rehearsing%20actually%20check%3F\"><h3>What does rehearsing actually check?<\/h3><\/dt>\n<dd><p>Six things, in order, and it stops at the first that fails:<\/p>\n\n<ol>\n<li>The archive is the one that was written, and still opens.<\/li>\n<li>Every file in it decompresses to the size it claims.<\/li>\n<li>The whole database export imports, into tables of the plugin's own.<\/li>\n<li>The number of rows matches what was recorded when the backup was taken \u2014 which\ncatches a dump that imported without error and is simply short.<\/li>\n<li>Serialized data survives a domain change.<\/li>\n<li>What imported is a WordPress that would work: it knows its own address, it has\nroles, and at least one user holds a role that still exists.<\/li>\n<\/ol>\n\n<p>The fifth is the one worth explaining. Widget settings, theme options and every\npage-builder layout are stored as serialized data, where each string records its own\nbyte length. Move to a longer address without repairing those lengths and WordPress\ncan no longer read the value: the site loads, looks right, and the layouts are gone.\nSo a rehearsal rewrites the imported rows to a deliberately longer address and checks\nWordPress can still read every one of them back.<\/p>\n\n<p>The sixth catches the other silent one. WordPress stores roles in an option named\nafter the table prefix, and each user's capabilities under a meta key named after it\ntoo. Restore under a different prefix and rename only the tables, and you get a site\nthat loads perfectly and locks everybody out. A rehearsal moves the prefix in the\ndata as a real restore would, then checks a user is still left holding a role that\nexists.<\/p>\n\n<p>To be plain about what step six is: it reads what WordPress reads on its way up. It\ndoes not execute WordPress against the scratch tables. Booting a second WordPress\nwould mean either a second PHP process \u2014 <code>proc_open<\/code> and <code>exec<\/code> are disabled on most\nshared hosting \u2014 or writing a web-reachable bootstrap into your document root on a\nschedule, which is a worse thing to own than the gap it closes.<\/p>\n\n<p>Nothing is written to your site at any point. The rows are tested in memory, and the\nscratch tables are dropped when it finishes.<\/p><\/dd>\n<dt id=\"does%20a%20passing%20rehearsal%20guarantee%20the%20restore%20will%20work%3F\"><h3>Does a passing rehearsal guarantee the restore will work?<\/h3><\/dt>\n<dd><p>It guarantees more than anything else short of doing it, and less than everything.\nIt proves the package restores <strong>onto this server<\/strong> \u2014 this PHP, this MySQL. The\nserver you would actually use in a disaster is a different one, and nothing but a\nreal restore proves that.<\/p>\n\n<p>What it does catch is the whole class of failures that make a backup useless without\nannouncing itself: a truncated dump, a corrupt entry in the middle of the archive, a\ndatabase export that is short of rows.\nThat last gap is what <strong>rehearsing<\/strong> closes \u2014 see below.<\/p><\/dd>\n<dt id=\"the%20server%20is%20gone.%20how%20do%20i%20restore%3F\"><h3>The server is gone. How do I restore?<\/h3><\/dt>\n<dd><p>Upload <code>installer.php<\/code> into the target folder on the new server, open it, and enter\nthe package passphrase. If it cannot find the archives it will offer to download\nthem from your storage \u2014 enter a read-only key for that bucket when it asks. Keep a\ncopy of <code>installer.php<\/code> somewhere other than the site it protects; it is small, and\nwithout it you would have only the archives.<\/p><\/dd>\n<dt id=\"what%20do%20i%20need%20to%20restore%20an%20incremental%20backup%3F\"><h3>What do I need to restore an incremental backup?<\/h3><\/dt>\n<dd><p>Every archive from the last full backup up to the one you are restoring. The\nSitecarry screen tells you how many that is, and the installer refuses to start\nwhile any of them is missing rather than restoring half a site. If that sounds\nfragile, leave incremental off \u2014 every package is then complete on its own.<\/p><\/dd>\n<dt id=\"how%20do%20i%20move%20a%20site%20to%20a%20different%20server%3F\"><h3>How do I move a site to a different server?<\/h3><\/dt>\n<dd><p>Download both the Archive and the Installer from the Sitecarry screen, upload them\ninto the target folder on the other server, create an empty database there, then\nopen <code>installer.php<\/code> in a browser and enter the package's restore passphrase.<\/p><\/dd>\n<dt id=\"does%20it%20work%20on%20sqlite%3F\"><h3>Does it work on SQLite?<\/h3><\/dt>\n<dd><p>No, and it tells you rather than pretending. The database export is MySQL, and the\nrestore installer connects through mysqli, so a package taken on SQLite could not be\nrestored. On such a site \u2014 WordPress Playground, or the SQLite database integration\nplugin \u2014 the Backups screen says so and the button is disabled.<\/p><\/dd>\n<dt id=\"is%20wp-config.php%20inside%20the%20package%3F\"><h3>Is wp-config.php inside the package?<\/h3><\/dt>\n<dd><p>No, and deliberately. It holds your database password and the eight authentication\nkeys and salts that sign every login cookie on the site \u2014 secrets that should never\nleave the server, least of all inside an archive that gets uploaded to cloud storage.<\/p>\n\n<p>A restore does not need it. Onto an existing WordPress install the installer keeps\nthat site's own <code>wp-config.php<\/code> and rewrites the database settings in it; into an\nempty folder it writes a fresh one from what you type in, with newly generated keys.\nOn a multisite, add the multisite constants back by hand after restoring into an\nempty folder.<\/p><\/dd>\n<dt id=\"why%20does%20the%20restore%20not%20run%20inside%20wordpress%3F\"><h3>Why does the restore not run inside WordPress?<\/h3><\/dt>\n<dd><p>Because it replaces the very files WordPress is running from. Anything doing that\nfrom inside WordPress would be pulling the floor out from under itself partway\nthrough. The installer is a standalone program that never loads WordPress.<\/p><\/dd>\n<dt id=\"can%20it%20restore%20into%20a%20database%20that%20already%20has%20a%20wordpress%20install%3F\"><h3>Can it restore into a database that already has a WordPress install?<\/h3><\/dt>\n<dd><p>Only if it uses the same table prefix, and it will replace those tables. Changing\nthe table prefix during a restore is not supported yet \u2014 use an empty database.<\/p><\/dd>\n<dt id=\"how%20large%20a%20site%20can%20it%20handle%3F\"><h3>How large a site can it handle?<\/h3><\/dt>\n<dd><p>Comfortably into the tens of gigabytes. Sitecarry writes its own archive format\nrather than using PHP's zip extension, appending each file to the end and never\nrewriting what is already there \u2014 so the work grows with the size of the site\ninstead of with the square of it. ZIP64 is used automatically, so neither the\narchive nor any file in it is capped at 4GB.<\/p>\n\n<p>You still need free disk space for the package, and enough for the database export\nwhile it is being written.<\/p><\/dd>\n<dt id=\"can%20i%20make%20backups%20faster%3F\"><h3>Can I make backups faster?<\/h3><\/dt>\n<dd><p>Three things matter, in order.<\/p>\n\n<p>Compression is the big one, and Sitecarry already avoids most of the cost: images,\nvideo, audio, fonts and archives are stored as they are, whatever level you pick,\nbecause compressing them again is pure waste. If the server is slow and disk is\ncheap, set compression to None.<\/p>\n\n<p>Second, exclude what you do not need. A folder of raw video in uploads will\ndominate everything else.<\/p>\n\n<p>Third, let it run in the background rather than from a browser tab, or use\n    wp sitecarry backup, which has no execution limit at all.<\/p><\/dd>\n<dt id=\"where%20can%20i%20see%20what%20is%20inside%20before%20installing%3F\"><h3>Where can I see what is inside before installing?<\/h3><\/dt>\n<dd><p>Screenshots, what is inside, the release history and answers to setup questions are on the <a href=\"https:\/\/dotance.com\/plugins\/sitecarry\/\">Sitecarry page at dotance.com<\/a>.<\/p><\/dd>\n\n<\/dl>\n\n<!--section=changelog-->\n<h4>1.31.1<\/h4>\n\n<ul>\n<li>Fixed on Windows servers: each backup included every earlier package, and its\npassphrase file, so packages doubled in size with every run. Windows reports the\nuploads folder with backslashes, so the check that skips Sitecarry's own folder\nnever matched. Both paths are now normalised the way WordPress does it. Linux and\nmacOS servers were not affected.<\/li>\n<\/ul>\n\n<h4>1.31.0<\/h4>\n\n<ul>\n<li>Sitecarry now says so plainly on a site whose database it cannot export into a\nrestorable package. The export is MySQL and the installer restores through\nmysqli, so on SQLite \u2014 WordPress Playground, or the SQLite integration plugin \u2014\na backup would build and could never be restored. Backups are refused there\ninstead, with the reason on the screen.<\/li>\n<\/ul>\n\n<h4>1.30.0<\/h4>\n\n<ul>\n<li>The restore installer is never written to this server. It is assembled in memory\nand streamed straight to the browser, so the generated file exists only as the\ndownload itself.<\/li>\n<\/ul>\n\n<h4>1.29.0<\/h4>\n\n<ul>\n<li><strong>wp-config.php is no longer part of a package.<\/strong> It holds the database password\nand the eight keys and salts that sign every login cookie, and a package can be\nuploaded to storage outside your control. A restore writes that file instead:\nonto an existing install it updates the one already there, and into an empty\nfolder it generates a new one with fresh keys.<\/li>\n<li><strong>Restoring starts with a download.<\/strong> The Restore button used to write a restore\ninstaller into the WordPress folder; a plugin should not put a program there, so\nit does not any more. Each package row now offers <strong>Get installer<\/strong>, and the\nscreen explains the three steps: download the installer and the archive, upload\nboth to the site being restored, open installer.php. The restore itself is\nunchanged, including moving to a new domain, server or table prefix.<\/li>\n<li><code>wp sitecarry stage<\/code> is replaced by <code>wp sitecarry installer &lt;id&gt;<\/code>, which prints\nthe installer so you can redirect it to a file.<\/li>\n<li>Loopback requests now pass their SSL verification through core's own\n  https_local_ssl_verify filter rather than switching it off outright.<\/li>\n<li>The readme name matches the plugin header.<\/li>\n<\/ul>\n\n<h4>1.28.0<\/h4>\n\n<ul>\n<li>Requires WordPress 6.2 or later. Every database query that names a table now passes\nthe name through <code>$wpdb-&gt;prepare()<\/code> as an identifier placeholder.<\/li>\n<li>Inside WordPress, all remote requests go through the WordPress HTTP API. The\nstandalone restore installer, which runs without WordPress, keeps its own transport.<\/li>\n<li>The plugin no longer raises PHP's execution time limit. Each step is sized to fit\ninside the host's limit and resumes in the next request.<\/li>\n<li>Settings are sanitized field by field as they are read from the form.<\/li>\n<li>The restore installer downloads from a file on disk instead of being echoed.<\/li>\n<li>Plugin constants now use the <code>SITECARRY_<\/code> prefix.<\/li>\n<li>The package manifest no longer records the content folder path, which nothing read.<\/li>\n<\/ul>\n\n<h4>1.27.0<\/h4>\n\n<ul>\n<li>The status strip no longer wraps. Its date is short and the destination drops the\n\"Uploaded to\" prefix the label above it already implied, so the five boxes stay the\nsame height.<\/li>\n<li>A backup's restore passphrase now sits beside its Restore button, which is what\nasks for it, instead of at the far end of a mostly empty row.<\/li>\n<li>Settings reads lighter. Each control keeps its first line and folds the reasoning\nbehind it into a short link, so the screen is a list of settings again rather than\nthree paragraphs under each one.<\/li>\n<\/ul>\n\n<h4>1.26.0<\/h4>\n\n<p><strong>The screens, redesigned.<\/strong> Same controls, same words, laid out like what they\nare: evidence.<\/p>\n\n<ul>\n<li>One state mark \u2014 a dot that means good, needs attention, or failed \u2014 used the same\nway in the status strip, on every package and down the activity timeline, so it is\nlearned once.<\/li>\n<li>Facts in a monospace face; sentences in the admin's own. Sizes, counts, passphrases\nand log lines read as the records they are, and prose stays prose.<\/li>\n<li>Each package is now a row with its date, its state, its facts and its two actions \u2014\nnot six columns and six buttons.<\/li>\n<li>Recent activity is a timeline with a spine.<\/li>\n<li>Settings, Storage and Notifications group their controls into cards, each with a\none-line explanation on the left. The help on the Backups screen folds away until\nwanted.<\/li>\n<li>Nothing here loads a font or an image. Accents follow your admin colour scheme;\nreds and greens deliberately do not.<\/li>\n<\/ul>\n\n<h4>1.25.0<\/h4>\n\n<ul>\n<li>The status strip no longer wraps its fifth item onto a row of its own. It was\nbuilt for four, and a fifth arrived with rehearsal reporting \u2014 at a 1280px window\nthe five wanted 1080px inside a strip that measures 1063.<\/li>\n<li>Plugin URI now points at the plugin's own page rather than the site home page.<\/li>\n<li>New screenshots, showing the rehearsal, the activity log and the storage set-up\nguides \u2014 the old ones predated all three.<\/li>\n<\/ul>\n\n<h4>1.24.0<\/h4>\n\n<p>The rest of the interface pass.<\/p>\n\n<ul>\n<li><strong>Progress that keeps moving.<\/strong> A percentage sits still for minutes on a large\nsite. The screen now says \"3,200 of 11,045 files\" or \"table 8 of 32\" beside it.<\/li>\n<li><strong>Deleting names what it is deleting<\/strong> \u2014 when it was taken, how big it is, and, if\neither is true, that it has been proven to restore or that no copy exists anywhere\nbut this server.<\/li>\n<li><strong>A first run is told what pressing the button does<\/strong>, and the two things worth\ndoing straight after.<\/li>\n<li><strong>The progress bar follows your admin colour scheme.<\/strong> Failure red and success\ngreen deliberately do not: a scheme that made failed look like fine would be a bug.<\/li>\n<li><strong>Laid out for narrow screens<\/strong> at the same 782px WordPress switches its own admin\nat, where the More menu now sits in the flow instead of hanging off the edge.<\/li>\n<li><strong>Screen readers<\/strong>: the status strip is a definition list, the progress bar reports\nits value, and results that appear after a click are announced.<\/li>\n<\/ul>\n\n<h4>1.23.0<\/h4>\n\n<ul>\n<li><strong>A record of what has actually happened.<\/strong> The Backups screen now shows recent\nactivity \u2014 backups, rehearsals and deletions \u2014 with a thirty-day summary above it.\nEverything else the plugin keeps lives with its package and disappears when\nretention prunes it, so on a site keeping five backups nothing older than five days\nhad ever been visible. This log outlives the packages it describes.<\/li>\n<li><strong>One primary action per backup.<\/strong> Six buttons of equal weight put Restore, which\nreplaces the entire site, next to Delete. Restore now stands alone and the rest fold\ninto a More menu, with Delete set apart at the bottom of it. The menu is built so it\nstill opens on a page where JavaScript never ran, because two of its items are\nordinary download links.<\/li>\n<li>Uninstalling now clears the two cron events the weekly rehearsal added in 1.19.0.<\/li>\n<\/ul>\n\n<h4>1.22.0<\/h4>\n\n<p><strong>The restore installer's buttons did nothing. Fixed, and now checked on every\nbuild.<\/strong> Anyone who downloaded an installer from version 1.16.0 onwards should\ndownload it again \u2014 the archives themselves were always fine.<\/p>\n\n<ul>\n<li>A search-and-replace against the installer template in 1.16.0 mangled one line of\nits JavaScript. That is a syntax error, so the whole inline script failed to load\nand no button on the installer page responded. It survived five releases because\nthe restore had only ever been proven by driving its endpoints directly, never by\nopening the page a person actually uses.<\/li>\n<li>The self-check now assembles the installer exactly as the plugin ships it, lints\nit as PHP, pulls out its script and runs it through a JavaScript parser. All three\nfail on the old bug, so it cannot come back quietly.<\/li>\n<\/ul>\n\n<h4>1.21.1<\/h4>\n\n<ul>\n<li>The Backups screen now shows what is inside an archive: the site files under\n  www\/, the whole database as <code>database.sql<\/code> beside it, and the manifest. Looking\nfor the database among the site files is the usual reason people conclude it is\nnot in there.<\/li>\n<\/ul>\n\n<h4>1.21.0<\/h4>\n\n<ul>\n<li><strong>Every remote destination now explains itself.<\/strong> The Storage screen carries a\nshort set-up guide for Amazon S3, FTP and Google Drive \u2014 collapsed until you want\nit. Each one covers the step people actually miss and names the error you get when\nyou miss it: the IAM policy to paste and why the wrong Region reads as a bad\nsignature; why a backup folder must not be web-reachable, and the login that\nsucceeds then hangs; and, for Drive, publishing the consent screen before pressing\nConnect \u2014 plus why adding yourself as a test user works for a week and then stops.<\/li>\n<\/ul>\n\n<h4>1.20.0<\/h4>\n\n<p><strong>Uploading to Google Drive and to Amazon S3 both worked again.<\/strong> One line broke\nthem both, and it was not the services.<\/p>\n\n<ul>\n<li>WordPress hands response headers back as a case-insensitive dictionary object, not\nan array. Casting that object to an array does not give you the headers \u2014 it gives\nyou its internal store under a key no lookup will ever match. So Google Drive could\nnot find the upload session it had just been given, and S3 could not find the ETag\nfor a multipart part. Both failed as though the service had refused.<\/li>\n<li>When either does genuinely fail now, the message says what came back \u2014 the status\nand the headers \u2014 instead of pointing at the service.<\/li>\n<\/ul>\n\n<h4>1.19.5<\/h4>\n\n<ul>\n<li>A rehearsal now says how many values it skipped because they were already\nunreadable when the backup was taken. Passing quietly over them would be the same\nhalf-truth the check exists to catch.<\/li>\n<\/ul>\n\n<h4>1.19.4<\/h4>\n\n<ul>\n<li>A rehearsal no longer blames the domain rewrite for data that arrived unreadable.\nA value that could not be unserialized before the rewrite is skipped: restoring it\nloses nothing it still had, and failing the package for it was an accusation.<\/li>\n<li>When a rehearsal does find broken data it now names the row \u2014 <code>option_name<\/code> or\n  meta_key rather than only the table and column, so it can be acted on.<\/li>\n<\/ul>\n\n<h4>1.19.3<\/h4>\n\n<ul>\n<li>Rehearsing a package whose tables carry foreign keys no longer reports a failure\nthat is not there. A rehearsal imports its copy into the same database as the live\nsite, and a foreign key's constraint name has to be unique across the whole\ndatabase \u2014 so the copy collided with the constraint the real table already held.<\/li>\n<\/ul>\n\n<h4>1.19.2<\/h4>\n\n<p>The first rehearsal run on a real site found a restore bug, which is the whole\nreason the feature exists.<\/p>\n\n<ul>\n<li><strong>A restore could fail on any site with foreign keys between tables.<\/strong> The export\nswitches foreign key checks off in its first line, but that is a session setting\nand a restore spans many requests on a fresh connection each time. From the second\nslice onward the checks were back on, so a table referencing one the dump had not\nreached yet failed outright. Both the restore installer and the rehearsal now set\nit per slice, and hand it back afterwards.<\/li>\n<\/ul>\n\n<h4>1.19.1<\/h4>\n\n<p>Three things that looked wired up and were not. All found by driving the plugin in a\nbrowser rather than by reading it.<\/p>\n\n<ul>\n<li><strong>Test connection and Test notification did nothing.<\/strong> The admin script gave up on\nany screen without a Create Backup button \u2014 which is every screen those buttons are\non. The destination dropdown stopped switching fields for the same reason.<\/li>\n<li><strong>Rehearse failed with a fatal error.<\/strong> A missing import meant the button called a\nclass that, from where it was calling, did not exist.<\/li>\n<li><strong>The Backups strip said \"This server only\" while packages went to Google Drive.<\/strong>\nIt only ever recognised Amazon S3. FTP and Drive now say where they go.<\/li>\n<\/ul>\n\n<h4>1.19.0<\/h4>\n\n<p>Rehearsing no longer depends on somebody remembering to press the button.<\/p>\n\n<ul>\n<li><strong>Rehearse weekly<\/strong>, in Settings. The newest full backup is proven every Sunday,\nthree hours after your backup hour, and you are told only if it fails.<\/li>\n<li>The hour is derived rather than asked for, so a rehearsal cannot be scheduled on\ntop of a backup \u2014 and it stands aside if it finds one running.<\/li>\n<li>A rehearsal too long for one cron request resumes where it stopped, the same way\nthe button and WP-CLI already did.<\/li>\n<li><code>wp sitecarry status<\/code> now reports the rehearsal schedule and its next run.<\/li>\n<\/ul>\n\n<h4>1.18.0<\/h4>\n\n<p>Rehearsing now finishes the job: proving the imported database is a WordPress that\nwould actually work, not merely one that imported.<\/p>\n\n<ul>\n<li><strong>A sixth rehearsal step.<\/strong> The scratch database is moved onto the rehearsal's own\ntable prefix the way a real restore would \u2014 in the data as well as the table names\n\u2014 and then read the way WordPress reads it on the way up: it knows its own address,\nit has roles, and somebody still holds one. A prefix move that renames the tables\nand forgets the data passes every earlier step and produces a site that loads and\nlocks you out. That one now fails, and says why.<\/li>\n<li>Step six reads the restored data. It does not execute WordPress.<\/li>\n<\/ul>\n\n<h4>1.17.0<\/h4>\n\n<p>Rehearsing now tests the thing that actually breaks migrations, and tells you when\nit fails.<\/p>\n\n<ul>\n<li><strong>Serialized data is put through a domain change and checked.<\/strong> WordPress stores\nwidget settings, theme options and every page-builder layout as serialized data,\nwhere each string records its own byte length. A restore to a longer address that\ndoes not repair those lengths produces a site that loads, looks right, and has\nquietly lost its layouts. A rehearsal now rewrites the imported rows to a\ndeliberately longer address and confirms WordPress can still read every one of\nthem. Nothing is written \u2014 the rows are tested in memory and dropped.<\/li>\n<li><strong>A rehearsal that fails now tells you<\/strong>, by email or webhook, on the same\nfailures-only setting backups use. A rehearsal that passes stays quiet: a weekly\nmessage saying everything is still fine stops being read within a month, and the\none that mattered goes unread with it.<\/li>\n<li>The Backups screen has a <strong>Last proven<\/strong> line, and each package carries its own\nbadge: proven to restore, or rehearsal failed. A package nobody has tested says\nso rather than showing nothing.<\/li>\n<\/ul>\n\n<h4>1.16.0<\/h4>\n\n<p>This release adds the thing a backup plugin should have had from the start: a way\nto prove a package restores, without restoring it over anything.<\/p>\n\n<ul>\n<li><strong>Rehearse<\/strong> a backup from the Backups screen, or with <code>wp sitecarry rehearse<\/code>.\nIt checks the archive, decompresses every file, imports the whole database into\ntables of its own, and compares the row count against what was recorded when the\nbackup was taken. Then it drops those tables again. Nothing on your site is\ntouched at any point.<\/li>\n<li>This is the answer to a question verifying could never answer. Verifying proves\nthe archive is intact; only importing the database proves it will import.<\/li>\n<li>A rehearsal that is interrupted resumes, and one that fails still cleans up after\nitself. Scratch tables left behind by a crash are swept away within a day.<\/li>\n<li><p>Rehearsal covers full backups only. An incremental package is a difference, and\nproving one would mean replaying its whole chain.<\/p><\/li>\n<li><p><strong>Restore can now change the table prefix.<\/strong> Two long-standing problems came out\nwhile building it:<\/p><\/li>\n<li>Fixed: a restore rewrote URLs across every table in the database, not only the\nones it had just written. That was harmless while restores demanded an empty\ndatabase, and would have quietly rewritten a second site sharing one.<\/li>\n<li>Fixed: the <code>wp-config.php<\/code> inside a package kept the prefix it was taken with, so\nrestoring under a different prefix produced a site that loaded the installation\nscreen instead of itself.<\/li>\n<li>The prefix is also stored inside the data \u2014 in the roles option and in every\nuser's capabilities. Both now move with it, so a restored site keeps its accounts\nand their roles rather than silently losing them.<\/li>\n<\/ul>\n\n<h4>1.15.0<\/h4>\n\n<ul>\n<li>Deleting the plugin now clears its settings and scheduled events out of the\ndatabase. Your packages in <code>wp-content\/uploads\/sitecarry\/<\/code> are deliberately left\nalone \u2014 they are backups, and deleting a plugin should not throw away the only\ncopy of someone's site.<\/li>\n<li>Housekeeping for the WordPress.org plugin directory, none of it visible in use:\nbyte order marks removed from the folder guard files, a missing guard file added,\ntemplate variables renamed so they cannot shadow WordPress globals, and the readme\nnow documents every outside service the plugin can be configured to contact.<\/li>\n<li>The restore installer is assembled slightly differently. The files shared between\nthe plugin and the installer now carry the plain guard WordPress expects, and the\nbuilder removes it as it inlines them, rather than each file carrying a guard\nwritten to suit both places at once.<\/li>\n<\/ul>\n\n<h4>1.14.0<\/h4>\n\n<p>This release fixes ten bugs found in a full review, most of them cases where a\nbackup could be silently corrupt or a restore could fail \u2014 the worst kind, because\nyou only find out when you need the backup.<\/p>\n\n<ul>\n<li>A backup interrupted partway and resumed no longer risks a corrupt archive. The\narchive, its index and the database export are each cut back to their last good\npoint before more is written, so nothing is ever duplicated or left in a hole.<\/li>\n<li>The database export now pages through large tables by their primary key. This is\nboth correct \u2014 the old method could skip or double rows on tables like term\nrelationships \u2014 and dramatically faster on tables with millions of rows.<\/li>\n<li>A single very large file no longer lets a second copy of the backup start on top\nof the first.<\/li>\n<li>Switching the storage destination off mid-backup no longer leaves a backup\nspinning forever; it stops with a clear message.<\/li>\n<li>The compression setting now actually changes the compression. \"Light\" is now\ngenuinely lighter on the processor, and \"Maximum\" genuinely smaller.<\/li>\n<li>Stopping a backup mid-upload now cancels the upload at the other end too.<\/li>\n<li>A restore interrupted mid-statement now resumes correctly instead of wedging.<\/li>\n<\/ul>\n\n<h4>1.13.2<\/h4>\n\n<ul>\n<li>A finished backup can no longer be written back into existence as a half-done one.\nAnything still holding an older copy of a job \u2014 a request that was killed and\nrestarted, a second driver that began before the job ended \u2014 is now ignored once\nthe job on disk has finished.<\/li>\n<\/ul>\n\n<h4>1.13.1<\/h4>\n\n<ul>\n<li>Fixed the FTP and Google Drive settings being impossible to find. Each\ndestination's settings were rendered hidden and only revealed by a script, so if\nthat script did not run they stayed invisible with no way to reach them. The\nchosen destination's settings are now shown by the page itself, and the script\nonly handles switching.<\/li>\n<li>The Storage screen now says that choosing a destination is what reveals its\nsettings, rather than showing a lone dropdown and nothing else.<\/li>\n<\/ul>\n\n<h4>1.13.0<\/h4>\n\n<ul>\n<li>A Stop button for a backup that is running, or one that has hung. It appears only\nwhile a backup is in progress, and says so plainly when that backup has stopped\nmaking progress.<\/li>\n<li>Stopping removes the half-built package. A partial package cannot be restored\nfrom, so leaving it would only take up room and look like a backup.<\/li>\n<li>An upload in progress is cancelled at the far end too, rather than left as an\nunfinished multipart upload that storage keeps charging for.<\/li>\n<li><code>wp sitecarry stop<\/code> does the same from the command line, which is the way out if\nthe admin screen itself cannot be reached.<\/li>\n<\/ul>\n\n<h4>1.12.1<\/h4>\n\n<ul>\n<li>Fixed background backups never starting. The request that tells the site to begin\nwork sent the job details in its body, and because that request is deliberately\nabandoned the instant it is made, the body was often never delivered \u2014 so the\nbackup sat at the first step for ever, looking busy. The details now travel in the\naddress, which is how WordPress sends its own equivalent.<\/li>\n<li>If the server says it will carry on by itself and then does not, the open tab now\nnotices after a few seconds and takes over, instead of watching a bar that will\nnever move.<\/li>\n<li>Scanning no longer shows a percentage that falls as more folders are found. A site\nwith a deep folder tree used to sit at a low number looking stuck; it now reports\nhow many files it has found.<\/li>\n<\/ul>\n\n<h4>1.12.0<\/h4>\n\n<ul>\n<li>Large sites are now genuinely practical. Sitecarry writes its own archive instead\nof using PHP's zip extension: every file is appended to the end and nothing already\nwritten is touched again. Previously each batch of files rewrote the whole archive,\nso a build got slower the bigger it grew \u2014 at five gigabytes, dramatically so.<\/li>\n<li>ZIP64 throughout, so neither the archive nor any single file inside it stops at 4GB.<\/li>\n<li>A compression setting: None, Light, Normal or Maximum. Already-compressed files \u2014\nimages, video, audio, fonts, archives \u2014 are stored untouched at every level,\nbecause deflating them costs processor time and saves nothing.<\/li>\n<li>Faster, and not only because of the above: the old limit of 200 files per request\nexisted to avoid running out of file handles, and no longer applies.<\/li>\n<li>Building a package no longer needs PHP's zip extension at all.<\/li>\n<\/ul>\n\n<h4>1.11.0<\/h4>\n\n<ul>\n<li>Two more destinations: FTP and Google Drive. Uploads to all three divide into\nresumable chunks the same way, so a large package survives short execution limits\nwherever it is going.<\/li>\n<li>FTP resumes at a byte offset in both directions, uploads under a temporary name so\nan interrupted transfer is never mistaken for a finished archive, and offers FTP\nover TLS \u2014 which the settings screen recommends, plainly, because plain FTP sends\nthe password and the whole database in clear.<\/li>\n<li>Google Drive uses an OAuth client of your own rather than routing authorisation\nthrough anyone else's servers, and asks only for the scope that lets it see the\nfiles it created itself. A restore cannot pull archives back from Drive: that\nwould mean putting a Google token into a file that can end up at a public URL, so\nthose archives are downloaded from Drive by hand instead.<\/li>\n<li>Google Cloud Storage also works through the S3 setting \u2014 point Endpoint at\n  https:\/\/storage.googleapis.com.<\/li>\n<\/ul>\n\n<h4>1.10.0<\/h4>\n\n<ul>\n<li>Restore from storage. If an archive is no longer on the server \u2014 pruned by\nretention, or because the server it lived on is gone \u2014 the installer downloads it\nfrom S3 before restoring. This is the situation a backup exists for, and until now\nthere was no way back from it.<\/li>\n<li>Downloads are ranged and resumable, into a <code>.part<\/code> file, so a large archive\nsurvives the same short execution limits as everything else and a partial one is\nnever mistaken for a complete one.<\/li>\n<li>Storage keys are never written into the installer. It carries the bucket and\nregion; the operator types the credentials when a download is actually needed.<\/li>\n<\/ul>\n\n<h4>1.9.0<\/h4>\n\n<ul>\n<li>Verify a package: checks its size and checksum against what was recorded, that the\narchive still opens and is structurally sound, and that the two files a restore\ncannot start without are inside it. For an incremental package it checks every\narchive in the set, not just the newest.<\/li>\n<li>WP-CLI: <code>wp sitecarry backup<\/code>, <code>list<\/code>, <code>verify<\/code>, <code>delete<\/code>, <code>status<\/code> and <code>installer<\/code>.\nA backup on the command line has no execution limit and no tab to keep open, and\n  verify exits non-zero on failure so it can run from a script.<\/li>\n<\/ul>\n\n<h4>1.8.0<\/h4>\n\n<ul>\n<li>Split the admin into four screens \u2014 Backups, Settings, Storage, Notifications \u2014\ninstead of one page carrying everything.<\/li>\n<li>The Backups screen now opens with a summary: when the last backup ran, when the\nnext one is due, where packages are kept, and whether anyone gets told if one\nfails.<\/li>\n<li>Each screen saves only its own settings, so changing storage cannot disturb the\nschedule.<\/li>\n<li>Packages are labelled full or incremental, and show whether they were uploaded.<\/li>\n<\/ul>\n\n<h4>1.7.0<\/h4>\n\n<ul>\n<li>Incremental backups: package only the files that changed since the last backup.\nThe database is still exported in full every time, so a restore never depends on\nreassembling it.<\/li>\n<li>A full backup is taken automatically every so often, capping how many archives a\nrestore has to replay.<\/li>\n<li>Files deleted from the site are recorded, so they do not reappear on restore.<\/li>\n<li>Retention now counts complete sets. A set is deleted whole or not at all, because\nremoving its full backup would leave the rest unrestorable.<\/li>\n<li>The restore installer replays a whole set in order, and refuses to start while any\nof its archives is missing \u2014 naming the ones it cannot find.<\/li>\n<\/ul>\n\n<h4>1.6.0<\/h4>\n\n<ul>\n<li>Notifications by email and to Slack or Discord. The default is failures only,\nbecause that is the message you need to still be reading in six months.<\/li>\n<li>A failure names the step it stopped on and quotes the error, and says plainly\nthat the partial package must not be relied on.<\/li>\n<li>Send a test, so notifications can be proved before they are needed.<\/li>\n<li>Every way a backup can end now runs through one place, so a job abandoned by the\nwatchdog reports itself exactly like one that failed outright.<\/li>\n<\/ul>\n\n<h4>1.5.0<\/h4>\n\n<ul>\n<li>Send packages to Amazon S3, or anything S3-compatible \u2014 Backblaze B2, Wasabi,\nDigitalOcean Spaces, MinIO \u2014 by setting a custom endpoint.<\/li>\n<li>Uploading is part of the backup job, using S3 multipart, so a large package\nsurvives short execution limits and a resumed run continues at the next part\nrather than starting the transfer again.<\/li>\n<li>Deleting a package, including by retention, removes the remote copy too.<\/li>\n<li>Test connection writes a small file and deletes it again, so it proves the upload\nand delete permissions a backup actually needs.<\/li>\n<li>Credentials can be defined in wp-config.php as SITECARRY_S3_KEY and\nSITECARRY_S3_SECRET, keeping them out of the database \u2014 and therefore out of the\npackages the database is dumped into.<\/li>\n<\/ul>\n\n<h4>1.4.0<\/h4>\n\n<ul>\n<li>Scheduled backups: hourly, twice daily, daily or weekly, at an hour you choose in\nyour site's own timezone.<\/li>\n<li>Retention \u2014 keep the last N packages and let older ones go, so a schedule cannot\nquietly fill the disk.<\/li>\n<li>A settings screen for what goes into a package: skip transients, include tables\nbelonging to other applications, and your own list of paths to exclude. Manual and\nscheduled backups now build packages identically.<\/li>\n<li>A scheduled run is skipped while a backup is already running, so a tight schedule\ncannot stack jobs on top of each other.<\/li>\n<\/ul>\n\n<h4>1.3.0<\/h4>\n\n<ul>\n<li>Backups now run in the background. Start one and close the tab \u2014 the server keeps\nworking, and the Sitecarry screen re-attaches to a running backup when you return.<\/li>\n<li>A watchdog restarts a backup whose background run is interrupted, picking up from\nwhere it stopped rather than starting over.<\/li>\n<li>Sites that cannot call themselves over HTTP fall back to the previous\nbrowser-driven mode automatically, and the screen says which one is in use.<\/li>\n<\/ul>\n\n<h4>1.2.0<\/h4>\n\n<ul>\n<li>Restore onto the current site with one button, no manual upload. WordPress cannot\noverwrite the files it is running from, so Sitecarry places the restore installer\nin the WordPress folder and hands off to it; the restore runs outside WordPress.<\/li>\n<li>The staged installer knows which site it is on and pre-fills everything except\nthe database password.<\/li>\n<li>An in-place restore never deletes the stored package it was started from.<\/li>\n<li>A staged installer is flagged on every admin screen until it is used or removed,\nwith a one-click Remove.<\/li>\n<\/ul>\n\n<h4>1.1.0<\/h4>\n\n<ul>\n<li>Restore. Every package now comes with a standalone <code>installer.php<\/code> that rebuilds\nthe site on any server: unpacks the export, imports the database, extracts the\nfiles, rewrites URLs and paths, and updates <code>wp-config.php<\/code>.<\/li>\n<li>Serialization-safe search and replace that repairs string lengths, walks\ndoubly-serialized values, and covers the JSON-escaped URLs page builders store.<\/li>\n<li>Per-package restore passphrase; the installer refuses to run without it and\nremoves itself and the archive when it finishes.<\/li>\n<li>Archive entries whose paths point outside the target folder are refused.<\/li>\n<\/ul>\n\n<h4>1.0.0<\/h4>\n\n<ul>\n<li>First release: resumable full-site packaging (files + database), progress UI,\npackage list, authenticated download and delete.<\/li>\n<\/ul>","raw_excerpt":"Back up, restore and migrate your site \u2014 files and database in one package \u2014 and prove each backup restores before you need it.","jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin\/368952","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin"}],"about":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/types\/plugin"}],"replies":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/comments?post=368952"}],"author":[{"embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wporg\/v1\/users\/dotance"}],"wp:attachment":[{"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/media?parent=368952"}],"wp:term":[{"taxonomy":"plugin_section","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_section?post=368952"},{"taxonomy":"plugin_tags","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_tags?post=368952"},{"taxonomy":"plugin_category","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_category?post=368952"},{"taxonomy":"plugin_contributors","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_contributors?post=368952"},{"taxonomy":"plugin_business_model","embeddable":true,"href":"https:\/\/pcd.wordpress.org\/plugins\/wp-json\/wp\/v2\/plugin_business_model?post=368952"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}