Site Cloning

CloneSiteJob runs CloneEngine::clone() to copy an existing site to a target (e.g. staging → production or new clone). Files are synced with rsync, database is dumped and restored, then URLs are rewritten.

Flow

flowchart LR subgraph clone [CloneEngine] A[ensureTargetSystemUser] B[ensureTargetDatabase] C[syncFiles] D[syncDatabase] E[rewriteUrls] F[ensureConfig] G[ensureWphosterAgent] H[configureCloudflare] end A --> B --> C --> D --> E --> F --> G --> H

Steps

  1. ensureTargetSystemUser — Creates OS user for target site if not set (UserManager::createSiteUser).
  2. ensureTargetDatabase — Creates MySQL database and user for target (or reuses if direction !== 'clone').
  3. syncFilesrsync -a --delete --exclude wp-config.php from source root to target root. wp-config is not copied so target gets its own DB credentials later.
  4. syncDatabasemysqldump source DB to temp file, then mysql ... source <file> into target DB.
  5. rewriteUrlswp search-replace source FQDN → target FQDN (all tables, skip guid), then wp option update home and siteurl.
  6. ensureConfigwp config create with target DB credentials and wp config shuffle-salts.
  7. ensureWphosterAgent — Re-install or update agent on target (same as provisioning).
  8. configureCloudflare — Upsert A record for target FQDN.

Key files

PathPurpose
app/Services/Provisioning/CloneEngine.phpClone logic
app/Jobs/CloneSiteJob.phpQueue job

Code snippet (syncFiles)

$this->runner->run([
    'rsync',
    '-a',
    '--delete',
    '--exclude',
    'wp-config.php',
    rtrim($source->root_path, '/') . '/',
    rtrim($target->root_path, '/') . '/',
]);

Code snippet (rewriteUrls)

$this->runAsSiteUser($target, [
    $wpCli,
    'search-replace',
    $source->fqdn,
    $target->fqdn,
    '--all-tables',
    '--skip-columns=guid',
]);
$this->runAsSiteUser($target, [$wpCli, 'option', 'update', 'home', $target->fqdn]);
$this->runAsSiteUser($target, [$wpCli, 'option', 'update', 'siteurl', $target->fqdn]);