PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.3.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.3.1
4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Backend / Modules / Jobs / Cloning.php
wp-staging / Backend / Modules / Jobs Last commit date
Cleaners 5 years ago Exceptions 5 years ago Cancel.php 2 years ago CancelUpdate.php 2 years ago Cloning.php 2 years ago CloningProcess.php 2 years ago Data.php 2 years ago Database.php 2 years ago Delete.php 2 years ago Directories.php 2 years ago Files.php 2 years ago Finish.php 2 years ago Job.php 2 years ago JobExecutable.php 2 years ago Logs.php 3 years ago PreserveDataFirstStep.php 3 years ago PreserveDataSecondStep.php 3 years ago ProcessLock.php 2 years ago Scan.php 2 years ago SearchReplace.php 2 years ago TotalStepsAreNumberOfTables.php 5 years ago Updating.php 2 years ago
Cloning.php
643 lines
1 <?php
2
3 namespace WPStaging\Backend\Modules\Jobs;
4
5 use Countable;
6 use Exception;
7 use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
8 use WPStaging\Backup\Ajax\Restore\PrepareRestore;
9 use WPStaging\Core\WPStaging;
10 use WPStaging\Framework\Analytics\Actions\AnalyticsStagingCreate;
11 use WPStaging\Framework\Database\SelectedTables;
12 use WPStaging\Framework\Filesystem\PathIdentifier;
13 use WPStaging\Framework\Filesystem\Scanning\ScanConst;
14 use WPStaging\Framework\Security\AccessToken;
15 use WPStaging\Framework\Staging\Sites;
16 use WPStaging\Framework\Utils\Urls;
17 use WPStaging\Framework\Utils\Sanitize;
18 use WPStaging\Framework\Adapter\Directory;
19 use WPStaging\Framework\Utils\WpDefaultDirectories;
20
21 use function WPStaging\functions\debug_log;
22
23 /**
24 * Class Cloning
25 * @package WPStaging\Backend\Modules\Jobs
26 */
27 class Cloning extends Job
28 {
29 /**
30 * @var string
31 */
32 const WPSTG_REQUEST = 'wpstg_cloning';
33
34 /**
35 * @var object
36 */
37 private $db;
38
39 /**
40 * @var WpDefaultDirectories
41 */
42 private $dirUtils;
43
44 /**
45 * @var Sites
46 */
47 private $sitesHelper;
48
49 /**
50 * @var string
51 */
52 private $errorMessage;
53
54 /**
55 * @var Sanitize
56 */
57 private $sanitize;
58
59 /**
60 * @var Urls
61 */
62 private $urls;
63
64 /** @var Directory */
65 private $dirAdapter;
66
67 /**
68 * Initialize is called in \Job
69 */
70 public function initialize()
71 {
72 $this->db = WPStaging::getInstance()->get("wpdb");
73 $this->dirUtils = new WpDefaultDirectories();
74 $this->sitesHelper = new Sites();
75 $this->sanitize = WPStaging::make(Sanitize::class);
76 $this->urls = WPStaging::make(Urls::class);
77 $this->dirAdapter = WPStaging::make(Directory::class);
78 }
79
80 public function getErrorMessage(): string
81 {
82 return $this->errorMessage;
83 }
84
85 /**
86 * Save Chosen Cloning Settings
87 * @return bool
88 * @throws \Exception
89 */
90 public function save(): bool
91 {
92 if (!isset($_POST) || !isset($_POST["cloneID"])) {
93 $this->errorMessage = __("clone ID missing", 'wp-staging');
94 return false;
95 }
96
97 // Delete files index cache file
98 $this->filesIndexCache->delete();
99
100 // Generate Options
101 // Clone ID -> timestamp (time at which this clone creation initiated)
102 $this->options->clone = preg_replace("#\W+#", '-', strtolower($this->sanitize->sanitizeString($_POST["cloneID"])));
103 // Clone Name -> Site name that user input, if user left it empty it will be Clone ID
104 $this->options->cloneName = isset($_POST["cloneName"]) ? sanitize_text_field($_POST["cloneName"]) : '';
105 // The slugified version of Clone Name (to use in directory creation)
106 $this->options->cloneDirectoryName = $this->sitesHelper->sanitizeDirectoryName($this->options->cloneName);
107 $result = $this->sitesHelper->isCloneExists($this->options->cloneDirectoryName);
108 if ($result !== false) {
109 $this->errorMessage = $result;
110 return false;
111 }
112
113 $this->options->cloneNumber = 1;
114 $this->options->prefix = $this->setStagingPrefix();
115 $this->options->includedDirectories = [];
116 $this->options->excludedDirectories = [];
117 $this->options->extraDirectories = [];
118 $this->options->excludedFiles = apply_filters('wpstg_clone_excluded_files', [
119 '.DS_Store',
120 '*.git',
121 '*.svn',
122 '*.tmp',
123 'desktop.ini',
124 '.gitignore',
125 '*.log',
126 'web.config', // Important: Windows IIS configuration file. Must not be in the staging site!
127 '.wp-staging', // Determines if a site is a staging site
128 '.wp-staging-cloneable', // File that makes the staging site cloneable.
129 ]);
130
131 $excludedFilesFullPath = [
132 '.htaccess',
133 PathIdentifier::IDENTIFIER_WP_CONTENT . 'db.php',
134 PathIdentifier::IDENTIFIER_WP_CONTENT . 'object-cache.php',
135 PathIdentifier::IDENTIFIER_WP_CONTENT . 'advanced-cache.php',
136 ];
137
138 $this->options->tmpExcludedGoDaddyFiles = [];
139 $muPluginsDir = trailingslashit($this->dirAdapter->getMuPluginsDirectory());
140 if (file_exists($muPluginsDir . 'gd-system-plugin.php')) {
141 $excludedFilesFullPath[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'gd-system-plugin.php';
142 $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'gd-system-plugin.php';
143 }
144
145 $this->options->excludedFilesFullPath = apply_filters('wpstg.clone.excluded_files_full_path', $excludedFilesFullPath);
146
147 $this->options->currentStep = 0;
148
149 // Job
150 $this->options->job = new \stdClass();
151
152 // Check if clone data already exists and use that one
153 if (isset($this->options->existingClones[$this->options->clone])) {
154 $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
155 $this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ? $this->options->existingClones[$this->options->clone]->prefix : $this->setStagingPrefix();
156
157 // Clone does not exist but there are other clones in db
158 // Get data and increment it
159 } elseif (!empty($this->options->existingClones)) {
160 $this->options->cloneNumber = count($this->options->existingClones) + 1;
161 }
162
163 $this->options->networkClone = false;
164 if ($this->isMultisiteAndPro() && is_main_site()) {
165 $this->options->networkClone = isset($_POST['networkClone']) && $this->sanitize->sanitizeBool($_POST['networkClone']);
166 }
167
168 // Included Tables / Prefixed Table - Excluded Tables
169 $includedTables = isset($_POST['includedTables']) ? $this->sanitize->sanitizeString($_POST['includedTables']) : '';
170 $excludedTables = isset($_POST['excludedTables']) ? $this->sanitize->sanitizeString($_POST['excludedTables']) : '';
171 $selectedTablesWithoutPrefix = isset($_POST['selectedTablesWithoutPrefix']) ? $this->sanitize->sanitizeString($_POST['selectedTablesWithoutPrefix']) : '';
172 $selectedTables = new SelectedTables($includedTables, $excludedTables, $selectedTablesWithoutPrefix);
173 $selectedTables->setAllTablesExcluded(empty($_POST['allTablesExcluded']) ? false : $this->sanitize->sanitizeBool($_POST['allTablesExcluded']));
174 $this->options->tables = $selectedTables->getSelectedTables($this->options->networkClone);
175
176 // Exclude File Size Rules
177 $this->options->excludeGlobRules = [];
178 if (!empty($_POST["excludeGlobRules"])) {
179 $this->options->excludeGlobRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeGlobRules"]);
180 }
181
182 // Exclude Glob Rules
183 $this->options->excludeSizeRules = [];
184 if (!empty($_POST["excludeSizeRules"])) {
185 $this->options->excludeSizeRules = $this->sanitize->sanitizeExcludeRules($_POST["excludeSizeRules"]);
186 }
187
188 $this->options->uploadsSymlinked = isset($_POST['uploadsSymlinked']) && $this->sanitize->sanitizeBool($_POST['uploadsSymlinked']);
189
190 /**
191 * @see /WPStaging/Framework/CloningProcess/ExcludedPlugins.php to exclude plugins
192 * Only add other directories here
193 */
194 $excludedDirectories = [
195 PathIdentifier::IDENTIFIER_WP_CONTENT . 'cache',
196 ];
197
198 if (is_dir(trailingslashit($this->dirAdapter->getMuPluginsDirectory()) . 'gd-system-plugin')) {
199 $excludedDirectories[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'gd-system-plugin';
200 $excludedDirectories[] = PathIdentifier::IDENTIFIER_MUPLUGINS . 'vendor';
201
202 $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'gd-system-plugin';
203 $this->options->tmpExcludedGoDaddyFiles[] = $muPluginsDir . 'vendor';
204 }
205
206 // Add upload folder to list of excluded directories for push if symlink option is enabled
207 if ($this->options->uploadsSymlinked) {
208 $excludedDirectories[] = PathIdentifier::IDENTIFIER_UPLOADS;
209 }
210
211 $excludedDirectoriesRequest = isset($_POST["excludedDirectories"]) ? $this->sanitize->sanitizeString($_POST["excludedDirectories"]) : '';
212 $excludedDirectoriesRequest = $this->dirUtils->getExcludedDirectories($excludedDirectoriesRequest);
213
214 $this->options->excludedDirectories = array_merge($excludedDirectories, $excludedDirectoriesRequest);
215
216 // Extra Directories
217 if (isset($_POST["extraDirectories"])) {
218 $this->options->extraDirectories = explode(ScanConst::DIRECTORIES_SEPARATOR, $this->sanitize->sanitizeString($_POST["extraDirectories"]));
219 }
220
221 $this->options->databaseServer = 'localhost';
222 if (!empty($_POST["databaseServer"])) {
223 $this->options->databaseServer = $this->sanitize->sanitizeString($_POST["databaseServer"]);
224 }
225
226 $this->options->databaseUser = '';
227 if (!empty($_POST["databaseUser"])) {
228 $this->options->databaseUser = $this->sanitize->sanitizeString($_POST["databaseUser"]);
229 }
230
231 $this->options->databasePassword = '';
232 if (!empty($_POST["databasePassword"])) {
233 $this->options->databasePassword = $this->sanitize->sanitizePassword($_POST["databasePassword"]);
234 }
235
236 $this->options->databaseDatabase = '';
237 if (!empty($_POST["databaseDatabase"])) {
238 $this->options->databaseDatabase = $this->sanitize->sanitizeString($_POST["databaseDatabase"]);
239 }
240
241 // isExternalDatabase() depends upon databaseUser and databasePassword,
242 // Make sure they are set before calling this.
243 $this->options->databasePrefix = $this->isExternalDatabase() ? $this->db->prefix : '';
244 if (!empty($_POST["databasePrefix"])) {
245 $this->options->databasePrefix = $this->maybeAppendUnderscorePrefix($this->sanitize->sanitizeString($_POST["databasePrefix"]));
246 }
247
248 $this->options->databaseSsl = false;
249 if (isset($_POST["databaseSsl"]) && 'true' === $this->sanitize->sanitizeString($_POST["databaseSsl"])) {
250 $this->options->databaseSsl = true;
251 }
252
253 $this->options->cloneDir = '';
254 if (!empty($_POST["cloneDir"])) {
255 $this->options->cloneDir = trailingslashit(wpstg_urldecode($this->sanitize->sanitizeString($_POST["cloneDir"])));
256 }
257
258 $this->options->cloneHostname = '';
259 if (!empty($_POST["cloneHostname"])) {
260 $this->options->cloneHostname = trim($this->sanitize->sanitizeString($_POST["cloneHostname"]));
261 }
262
263 // Make sure it is always enabled for free version
264 $this->options->emailsAllowed = true;
265 $this->options->cronDisabled = false;
266
267 if (defined('WPSTGPRO_VERSION')) {
268 $this->options->emailsAllowed = apply_filters(
269 'wpstg_cloning_email_allowed',
270 isset($_POST['emailsAllowed']) && $this->sanitize->sanitizeBool($_POST['emailsAllowed'])
271 );
272 $this->options->cronDisabled = !empty($_POST['cronDisabled']) ? $this->sanitize->sanitizeBool($_POST['cronDisabled']) : false;
273 }
274
275 $this->options->destinationDir = $this->getDestinationDir();
276 $this->options->destinationHostname = $this->getDestinationHostname();
277
278 $this->options->homeHostname = $this->urls->getHomeUrlWithoutScheme();
279
280 // Process lock state
281 $this->options->isRunning = true;
282
283 // id of the user creating the clone
284 $this->options->ownerId = get_current_user_id();
285
286 // Save Clone data
287 $this->saveClone();
288
289 WPStaging::make(AnalyticsStagingCreate::class)->enqueueStartEvent($this->options->jobIdentifier, $this->options);
290
291 $this->errorMessage = "";
292 return $this->saveOptions();
293 }
294
295 /**
296 * Save clone data initially
297 * @return void
298 */
299 private function saveClone()
300 {
301 // Save new clone data
302 $this->debugLog("Cloning: {$this->options->clone}'s clone job's data is not in database, generating data");
303
304 $this->options->existingClones[$this->options->clone] = [
305 "cloneName" => $this->options->cloneName,
306 "directoryName" => $this->options->cloneDirectoryName,
307 "path" => trailingslashit($this->options->destinationDir),
308 "url" => $this->getDestinationUrl(),
309 "number" => $this->options->cloneNumber,
310 "version" => WPStaging::getVersion(),
311 "status" => "unfinished or broken (?)",
312 "prefix" => $this->options->prefix,
313 "datetime" => time(),
314 "databaseUser" => $this->options->databaseUser,
315 "databasePassword" => $this->options->databasePassword,
316 "databaseDatabase" => $this->options->databaseDatabase,
317 "databaseServer" => $this->options->databaseServer,
318 "databasePrefix" => $this->options->databasePrefix,
319 "databaseSsl" => (bool)$this->options->databaseSsl,
320 "cronDisabled" => (bool)$this->options->cronDisabled,
321 "emailsAllowed" => (bool)$this->options->emailsAllowed,
322 "uploadsSymlinked" => (bool)$this->options->uploadsSymlinked,
323 "ownerId" => $this->options->ownerId,
324 "includedTables" => $this->options->tables,
325 "excludeSizeRules" => $this->options->excludeSizeRules,
326 "excludeGlobRules" => $this->options->excludeGlobRules,
327 "excludedDirectories" => $this->options->excludedDirectories,
328 "extraDirectories" => $this->options->extraDirectories,
329 "networkClone" => $this->isNetworkClone(),
330 ];
331
332 if ($this->sitesHelper->updateStagingSites($this->options->existingClones) === false) {
333 $this->log("Cloning: Failed to save {$this->options->clone}'s clone job data to database'");
334 }
335 }
336
337 /**
338 * Get destination Hostname depending on whether WP has been installed in sub dir or not
339 * @return string
340 */
341 private function getDestinationUrl(): string
342 {
343 if (!empty($this->options->cloneHostname)) {
344 return $this->options->cloneHostname;
345 }
346
347 return trailingslashit(get_site_url()) . $this->options->cloneDirectoryName;
348 }
349
350 /**
351 * Return target hostname
352 * @return string
353 */
354 private function getDestinationHostname(): string
355 {
356 if (empty($this->options->cloneHostname)) {
357 return $this->urls->getHomeUrlWithoutScheme();
358 }
359
360 return $this->getHostnameWithoutScheme($this->options->cloneHostname);
361 }
362
363 /**
364 * Return Hostname without scheme
365 * @param string $string
366 * @return string
367 */
368 private function getHostnameWithoutScheme(string $string): string
369 {
370 return preg_replace('#^https?://#', '', rtrim($string, '/'));
371 }
372
373 /**
374 * Get Destination Directory including staging subdirectory
375 * @return string
376 */
377 private function getDestinationDir(): string
378 {
379 // Throw fatal error
380 if (!empty($this->options->cloneDir) & (trailingslashit($this->options->cloneDir) === trailingslashit(WPStaging::getWPpath()))) {
381 $this->returnException('Error: Target path must be different from the root of the production website.');
382 }
383
384 // custom destination has been set
385 if (!empty($this->options->cloneDir)) {
386 return trailingslashit($this->options->cloneDir);
387 }
388
389 // No custom destination so default path will be in a subfolder of root or inside wp-content
390 $cloneDestinationPath = $this->dirAdapter->getAbsPath() . $this->options->cloneDirectoryName;
391
392 if ($this->isPro() && !is_writable($this->dirAdapter->getAbsPath())) {
393 $stagingSiteDirectory = $this->dirAdapter->getStagingSiteDirectoryInsideWpcontent();
394 if ($stagingSiteDirectory === false) {
395 debug_log(esc_html('Fail to get destination directory. The staging sites destination folder cannot be created.'));
396 $this->returnException('The staging sites directory is not writable. Please choose another path.');
397 }
398
399 $cloneDestinationPath = trailingslashit($stagingSiteDirectory) . $this->options->cloneDirectoryName;
400 if (empty($this->options->cloneHostname)) {
401 $this->options->cloneHostname = trailingslashit($this->dirAdapter->getStagingSiteUrl()) . $this->options->cloneDirectoryName;
402 }
403 }
404
405 $this->options->cloneDir = trailingslashit($cloneDestinationPath);
406 return $this->options->cloneDir;
407 }
408
409 /**
410 * Make sure prefix ends with underscore
411 *
412 * @param string $string
413 * @return string
414 */
415 private function maybeAppendUnderscorePrefix(string $string): string
416 {
417 $lastCharacter = substr($string, -1);
418 if ($lastCharacter === '_') {
419 return $string;
420 }
421
422 return $string . '_';
423 }
424
425 /**
426 * Create a new staging prefix that does not exist in database
427 */
428 private function setStagingPrefix()
429 {
430 // Find a new prefix that does not already exist in database.
431 // Loop through up to 1000 different possible prefixes should be enough here;)
432 for ($i = 0; $i <= 10000; $i++) {
433 $this->options->prefix = !empty($this->options->existingClones) && $this->options->existingClones instanceof Countable
434 ? 'wpstg' . (count($this->options->existingClones) + $i) . '_'
435 : 'wpstg' . $i . '_';
436
437 $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
438 $tables = $this->db->get_results($sql);
439
440 // Prefix does not exist. We can use it
441 if (!$tables) {
442 return $this->options->prefix;
443 }
444 }
445
446 $message = sprintf("Fatal Error: Can not create staging prefix. '%s' already exists! Stopping for security reasons. Contact support@wp-staging.com", $this->options->prefix);
447 $this->returnException($message);
448 wp_die(esc_html($message));
449 }
450
451
452 /**
453 * Start the cloning job
454 * @throws JobNotFoundException
455 */
456 public function start()
457 {
458 if (!property_exists($this->options, 'currentJob') || $this->options->currentJob === null) {
459 $this->log("Cloning job finished");
460 return true;
461 }
462
463 $methodName = "job" . ucwords($this->options->currentJob);
464
465 if (!method_exists($this, $methodName)) {
466 $this->log("Can't execute job; Job's method $methodName is not found");
467 throw new JobNotFoundException($methodName);
468 }
469
470 if ($this->options->databasePrefix === $this->db->prefix && $this->isStagingDatabaseSameAsProductionDatabase()) {
471 $this->returnException('Table prefix for staging site can not be identical to live database if staging site will be cloned into production database! Please start over and change the table prefix or destination database.');
472 }
473
474 if (defined('WPSTG_DEV') && WPSTG_DEV === true) {
475 return $this->{$methodName}();
476 }
477
478 $tmpPrefixes = [
479 PrepareRestore::TMP_DATABASE_PREFIX,
480 PrepareRestore::TMP_DATABASE_PREFIX_TO_DROP,
481 ];
482
483 if (in_array($this->options->databasePrefix, $tmpPrefixes)) {
484 $this->returnException('Prefix wpstgtmp_ and wpstgbak_ are preserved by WP Staging and cannot be used for CLONING purpose! Please start over and change the table prefix.');
485 }
486
487 // Call the job
488 return $this->{$methodName}();
489 }
490
491 /**
492 * @param object $response
493 * @param string $nextJob
494 * @return object
495 * @throws \Exception
496 */
497 private function handleJobResponse($response, string $nextJob)
498 {
499 // Job is not done
500 if ($response->status !== true) {
501 return $response;
502 }
503
504 $this->options->job = new \stdClass();
505 $this->options->currentJob = $nextJob;
506 $this->options->currentStep = 0;
507 $this->options->totalSteps = 0;
508
509 // Save options
510 $this->saveOptions();
511
512 return $response;
513 }
514
515 /**
516 * Copy data from staging site to temporary column to use it later
517 * @return object
518 * @throws \Exception
519 */
520 public function jobPreserveDataFirstStep()
521 {
522 $this->writeJobSpecificLogStartHeader();
523
524 $preserve = new PreserveDataFirstStep();
525 return $this->handleJobResponse($preserve->start(), 'database');
526 }
527
528 /**
529 * Clone Database
530 * @return object
531 * @throws \Exception
532 */
533 public function jobDatabase()
534 {
535 $database = new Database();
536 return $this->handleJobResponse($database->start(), "SearchReplace");
537 }
538
539 /**
540 * Search & Replace
541 * @return object
542 * @throws \Exception
543 */
544 public function jobSearchReplace()
545 {
546 $searchReplace = new SearchReplace();
547 return $this->handleJobResponse($searchReplace->start(), "PreserveDataSecondStep");
548 }
549
550 /**
551 * Copy tmp data back to staging site
552 * @return object
553 * @throws \Exception
554 */
555 public function jobPreserveDataSecondStep()
556 {
557 $preserve = new PreserveDataSecondStep();
558 return $this->handleJobResponse($preserve->start(), 'directories');
559 }
560
561 /**
562 * Get All Files From Selected Directories Recursively Into a File
563 * @return object
564 * @throws \Exception
565 */
566 public function jobDirectories()
567 {
568 $directories = new Directories();
569 return $this->handleJobResponse($directories->start(), "files");
570 }
571
572 /**
573 * Copy Files
574 * @return object
575 * @throws \Exception
576 */
577 public function jobFiles()
578 {
579 $files = new Files();
580 return $this->handleJobResponse($files->start(), "data");
581 }
582
583
584 /**
585 * Replace Data
586 * @return object
587 * @throws \Exception
588 */
589 public function jobData()
590 {
591 return $this->handleJobResponse((new Data())->start(), "finish");
592 }
593
594 /**
595 * Save Clone Data
596 * @return object
597 * @throws \Exception
598 */
599 public function jobFinish()
600 {
601 // Re-generate the token when the Clone is complete.
602 // Todo: Consider adding a do_action() on jobFinish to hook here.
603 // Todo: Inject using DI
604 $accessToken = new AccessToken();
605 $accessToken->generateNewToken();
606
607 $finish = new Finish();
608 return $this->handleJobResponse($finish->start(), '');
609 }
610
611 /**
612 * @return void
613 */
614 private function writeJobSpecificLogStartHeader()
615 {
616
617 $jobName = empty($this->options->mainJob) ? 'Unknown' : $this->options->mainJob;
618
619 switch ($jobName) {
620 case Job::UPDATE:
621 $jobName = 'Update';
622 break;
623 case Job::RESET:
624 $jobName = 'Reset';
625 break;
626 case Job::STAGING:
627 $jobName = 'Cloning';
628 break;
629 default:
630 $jobName = 'Unknown';
631 break;
632 }
633
634 $this->log('#################### Start ' . $jobName . ' Job ####################', 'INFO');
635 if ($jobName !== 'Cloning' && !empty($this->options->clone)) {
636 $this->logger->info(esc_html('Staging Site ID: ' . $this->options->clone));
637 $this->logger->info(esc_html('Staging Site: ' . $this->options->cloneName));
638 }
639
640 $this->logger->writeLogHeader();
641 }
642 }
643