PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.0
4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 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 / Administrator.php
wp-staging / Backend Last commit date
Activation 1 day ago DashboardWidget 1 day ago Modules 1 day ago Optimizer 1 day ago Pluginmeta 1 day ago Upgrade 1 day ago Administrator.php 1 day ago
Administrator.php
1371 lines
1 <?php
2
3 namespace WPStaging\Backend;
4
5 use WPStaging\Backend\Modules\Jobs\Job;
6 use WPStaging\Core\WPStaging;
7 use WPStaging\Framework\Settings\Settings as SettingsService;
8 use WPStaging\Framework\Analytics\Actions\AnalyticsStagingReset;
9 use WPStaging\Framework\Analytics\Actions\AnalyticsStagingUpdate;
10 use WPStaging\Framework\Assets\Assets;
11 use WPStaging\Framework\Facades\Hooks;
12 use WPStaging\Framework\SiteInfo;
13 use WPStaging\Framework\Security\Auth;
14 use WPStaging\Framework\Mails\Report\Report;
15 use WPStaging\Framework\Filesystem\Filters\ExcludeFilter;
16 use WPStaging\Framework\Filesystem\PathIdentifier;
17 use WPStaging\Framework\TemplateEngine\TemplateEngine;
18 use WPStaging\Framework\Utils\Math;
19 use WPStaging\Framework\Utils\WpDefaultDirectories;
20 use WPStaging\Framework\Notices\DismissNotice;
21 use WPStaging\Framework\Job\Exception\ProcessLockedException;
22 use WPStaging\Staging\Sites;
23 use WPStaging\Backend\Modules\Jobs\Cancel;
24 use WPStaging\Backend\Modules\Jobs\CancelUpdate;
25 use WPStaging\Backend\Modules\Jobs\Cloning;
26 use WPStaging\Backend\Modules\Jobs\Updating;
27 use WPStaging\Backend\Modules\Jobs\Scan;
28 use WPStaging\Backend\Modules\Jobs\Logs;
29 use WPStaging\Backend\Modules\Jobs\ProcessLock;
30 use WPStaging\Backend\Modules\SystemInfo;
31 use WPStaging\Backend\Modules\Views\Tabs\Tabs;
32 use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
33 use WPStaging\Backend\Activation;
34 use WPStaging\Backend\Pro\Modules\Jobs\Processing;
35 use WPStaging\Backend\Pro\Modules\Jobs\Backups\BackupUploadsDir;
36 use WPStaging\Backend\Pluginmeta\Pluginmeta;
37 use WPStaging\Framework\Database\SelectedTables;
38 use WPStaging\Framework\Utils\Sanitize;
39 use WPStaging\Backend\Pro\Modules\Jobs\Scan as ScanProModule;
40 use WPStaging\Basic\Feedback\Feedback;
41 use WPStaging\Core\CloningJobProvider;
42 use WPStaging\Framework\Utils\PluginInfo;
43 use WPStaging\Framework\Security\Nonce;
44 use WPStaging\Framework\Newsfeed\NewsfeedProvider;
45 use WPStaging\Framework\Language\Language;
46 use WPStaging\Pro\License\Licensing;
47
48
49
50
51
52 class Administrator
53 {
54
55
56
57 const MENU_POSITION_ORDER = 65;
58
59
60
61
62 const MENU_POSITION_ORDER_MULTISITE = 20;
63
64
65
66
67 const FILTER_MAIN_SETTING_TABS = 'wpstg.main_settings_tabs';
68
69
70
71
72
73 const ADMIN_PAGE_SLUGS = [
74 'wpstg_clone',
75 'wpstg_backup',
76 'wpstg-settings',
77 'wpstg-tools',
78 'wpstg-welcome',
79 'wpstg-restorer',
80 'wpstg-license',
81 'wpstg-install',
82 ];
83
84
85 private $viewsPath;
86
87
88
89
90 private $assets;
91
92
93
94
95 private $auth;
96
97
98
99
100 private $siteInfo;
101
102
103 private $sanitize;
104
105
106 private $report;
107
108
109 private $pluginInfo;
110
111 public function __construct()
112 {
113 $this->auth = WPStaging::make(Auth::class);
114 $this->assets = WPStaging::make(Assets::class);
115 $this->siteInfo = WPStaging::make(SiteInfo::class);
116 $this->report = WPStaging::make(Report::class);
117 $this->pluginInfo = WPStaging::make(PluginInfo::class);
118 $this->viewsPath = WPSTG_VIEWS_DIR;
119
120 $this->defineHooks();
121
122 $this->sanitize = WPStaging::make(Sanitize::class);
123
124
125 $this->loadMeta();
126 }
127
128
129
130
131 public function loadMeta()
132 {
133 new Pluginmeta();
134 }
135
136
137
138
139 private function defineHooks()
140 {
141 if (!defined('WPSTGPRO_VERSION')) {
142 new Activation\Welcome();
143 }
144
145 if ($this->pluginInfo->canShowAdminMenu()) {
146 add_action("admin_menu", [$this, "addMenu"], 10);
147 add_action('network_admin_menu', [$this, "addMenu"]);
148 }
149
150 add_action("admin_init", [$this, "upgrade"]);
151 add_action("admin_post_wpstg_download_sysinfo", [$this, "downloadSystemInfoAndLogFiles"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
152
153 if (defined('WPSTGPRO_VERSION') && class_exists('WPStaging\Backend\Pro\WpstgRestoreDownloader')) {
154 add_action("admin_post_wpstg_download_restorer", [$this, "downloadWpstgRestoreFile"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
155 }
156
157 if (!defined('WPSTGPRO_VERSION') && $this->isPluginsPage()) {
158 add_filter('admin_footer', [$this, 'loadFeedbackForm']);
159 }
160
161
162 add_action("wp_ajax_wpstg_scanning", [$this, "ajaxCloneScan"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
163 add_action("wp_ajax_wpstg_check_clone", [$this, "ajaxCheckCloneDirectoryName"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
164 add_action("wp_ajax_wpstg_restart", [$this, "ajaxRestart"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
165 add_action("wp_ajax_wpstg_update", [$this, "ajaxUpdateProcess"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
166 add_action("wp_ajax_wpstg_reset", [$this, "ajaxResetProcess"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
167 add_action("wp_ajax_wpstg_cloning", [$this, "ajaxStartClone"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
168 add_action("wp_ajax_wpstg_processing", [$this, "ajaxCloneDatabase"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
169 add_action("wp_ajax_wpstg_clone_prepare_directories", [$this, "ajaxPrepareDirectories"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
170 add_action("wp_ajax_wpstg_clone_files", [$this, "ajaxCopyFiles"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
171 add_action("wp_ajax_wpstg_clone_replace_data", [$this, "ajaxReplaceData"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
172 add_action("wp_ajax_wpstg_clone_finish", [$this, "ajaxFinish"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
173 add_action("wp_ajax_wpstg_cancel_clone", [$this, "ajaxCancelClone"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
174 add_action("wp_ajax_wpstg_cancel_update", [$this, "ajaxCancelUpdate"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
175 add_action("wp_ajax_wpstg_hide_rating", [$this, "ajaxHideRating"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
176 add_action("wp_ajax_wpstg_hide_later", [$this, "ajaxHideLaterRating"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
177 add_action("wp_ajax_wpstg_hide_beta", [$this, "ajaxHideBeta"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
178 add_action("wp_ajax_wpstg_logs", [$this, "ajaxLogs"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
179 add_action("wp_ajax_wpstg_send_report", [$this, "ajaxSendReport"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
180 add_action("wp_ajax_wpstg_send_feedback", [$this, "sendFeedback"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
181 add_action("wp_ajax_wpstg_enable_staging_cloning", [$this, "ajaxEnableStagingCloning"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
182 add_action("wp_ajax_wpstg_clone_excludes_settings", [$this, "ajaxCloneExcludesSettings"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
183 add_action("wp_ajax_wpstg_fetch_dir_children", [$this, "ajaxFetchDirChildren"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
184 add_action("wp_ajax_wpstg_modal_error", [$this, "ajaxModalError"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
185 add_action("wp_ajax_wpstg_dismiss_notice", [$this, "ajaxDismissNotice"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
186 add_action("wp_ajax_wpstg_restore_settings", [$this, "ajaxRestoreSettings"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
187 add_action("wp_ajax_wpstg_send_debug_log_report", [$this->report, "ajaxSendDebugLog"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
188
189
190
191 add_action("wp_ajax_wpstg_scan", [$this, "ajaxPushScan"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
192 add_action("wp_ajax_wpstg_push_tables", [$this, "ajaxPushTables"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
193 add_action("wp_ajax_wpstg_push_processing", [$this, "ajaxPushProcessing"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
194 add_action("wp_ajax_nopriv_wpstg_push_processing", [$this, "ajaxPushProcessing"]); // phpcs:ignore WPStaging.Security.AuthorizationChecked
195
196
197
198 if (class_exists('WPStaging\Backend\Pro\Modules\Jobs\Backups\BackupUploadsDir')) {
199 add_action(BackupUploadsDir::BACKUP_DELETE_CRON_HOOK_NAME, [$this, "removeOldUploadsBackup"]); // phpcs:ignore WPStaging.Security.FirstArgNotAString -- Cron callback
200 }
201 }
202
203
204
205
206 public function loadFeedbackForm()
207 {
208 $form = WPStaging::make(Feedback::class);
209 $form->loadForm();
210 }
211
212
213
214
215 public function sendFeedback()
216 {
217 if (!$this->isAuthenticated()) {
218 return;
219 }
220
221 $form = WPStaging::make(Feedback::class);
222 $form->sendDeactivateFeedback();
223 }
224
225
226
227
228
229
230 public function upgrade()
231 {
232 if (defined('WPSTGPRO_VERSION') && class_exists('WPStaging\Backend\Pro\Upgrade\Upgrade')) {
233 $upgrade = WPStaging::make('WPStaging\Backend\Pro\Upgrade\Upgrade');
234 } else {
235 $upgrade = WPStaging::make('WPStaging\Backend\Upgrade\Upgrade');
236 }
237 $upgrade->doUpgrade();
238 }
239
240
241
242
243 public function addMenu()
244 {
245 global $wp_version;
246 $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
247
248 $pos = self::MENU_POSITION_ORDER;
249 if (is_multisite()) {
250 $pos = self::MENU_POSITION_ORDER_MULTISITE;
251 }
252
253
254
255 if (version_compare($wp_version, '4.4', '<')) {
256 $pos++;
257 }
258
259 $proSlug = defined('WPSTGPRO_VERSION') ? 'Pro' : '';
260
261 $defaultPageSlug = "wpstg_clone";
262 $defaultPageCallback = "getClonePage";
263
264 $defaultPageTitle = "Staging Sites";
265 $secondaryPageSlug = "wpstg_backup";
266 $secondaryPageCallback = "getBackupPage";
267
268 $secondaryPageTitle = "Backup &amp; Migration";
269
270 $siteInfo = WPStaging::make(SiteInfo::class);
271 if ($siteInfo->isHostedOnWordPressCom()) {
272 $defaultPageSlug = "wpstg_backup";
273 $defaultPageCallback = "getBackupPage";
274
275 $defaultPageTitle = "Backup &amp; Migration";
276 $secondaryPageSlug = "wpstg_clone";
277 $secondaryPageCallback = "getClonePage";
278
279 $secondaryPageTitle = "Staging Sites";
280 }
281
282
283 add_menu_page(
284 "WP STAGING",
285 esc_html("WP Staging " . $proSlug),
286 "manage_options",
287 $defaultPageSlug,
288 [$this, $defaultPageCallback],
289 $logo,
290 $pos
291 );
292
293
294 add_submenu_page(
295 $defaultPageSlug,
296
297 "WP Staging - Staging",
298 $defaultPageTitle,
299 "manage_options",
300 $defaultPageSlug,
301 [$this, $defaultPageCallback]
302 );
303
304
305 add_submenu_page(
306 $defaultPageSlug,
307
308 "WP Staging - Backup &amp; Migration",
309 $secondaryPageTitle,
310 "manage_options",
311 $secondaryPageSlug,
312 [$this, $secondaryPageCallback]
313 );
314
315
316
317 $canUseRemoteSync = defined('WPSTGPRO_VERSION')
318 && WPStaging::make(Licensing::class)->isActiveAgencyOrDeveloperPlan();
319
320 if ($canUseRemoteSync) {
321 add_submenu_page(
322 $defaultPageSlug,
323 esc_html__("WP Staging - Remote Sync", "wp-staging"),
324 esc_html__("Remote Sync", "wp-staging"),
325 "manage_options",
326 "wpstg_backup&wpstgOpenRemoteSync=true",
327 [$this, "getBackupPage"]
328 );
329
330
331
332 add_filter('submenu_file', function ($submenuFile) {
333 if (!isset($_GET['page']) || $_GET['page'] !== 'wpstg_backup') {
334 return $submenuFile;
335 }
336
337 if (isset($_GET['wpstgOpenRemoteSync']) && $this->sanitize->sanitizeBool($_GET['wpstgOpenRemoteSync'])) {
338 return 'wpstg_backup&wpstgOpenRemoteSync=true';
339 }
340
341 return $submenuFile;
342 });
343 } else {
344
345
346 global $submenu;
347 $remoteSyncDocsUrl = esc_url(Language::localizeDocsUrl('https://wp-staging.com/docs/pull-a-wordpress-site-from-one-server-to-another/'));
348 $remoteSyncLabel = esc_html__("Remote Sync", "wp-staging")
349 . ' <span class="wpstg-menu-pro-badge">' . esc_html__("Pro", "wp-staging") . '</span>';
350 $submenu[$defaultPageSlug][] = [$remoteSyncLabel, "manage_options", $remoteSyncDocsUrl];
351
352 add_action('admin_head', [$this, 'printRemoteSyncMenuBadgeStyle']);
353 add_action('admin_footer', [$this, 'printRemoteSyncMenuBadgeScript']);
354 }
355
356
357 add_submenu_page(
358 $defaultPageSlug,
359 esc_html__("WP Staging - Temporary Logins", "wp-staging"),
360 esc_html__("Temporary Logins", "wp-staging"),
361 "manage_options",
362 "wpstg-settings&tab=temporary-login",
363 [$this, "getTempLoginsPage"]
364 );
365
366
367 add_submenu_page(
368 $defaultPageSlug,
369 esc_html__("WP Staging - Settings", "wp-staging"),
370 esc_html__("Settings", "wp-staging"),
371 "manage_options",
372 "wpstg-settings",
373 [$this, "getSettingsPage"]
374 );
375
376
377 add_submenu_page(
378 $defaultPageSlug,
379 esc_html__("WP Staging - System Info", "wp-staging"),
380 esc_html__("System Info", "wp-staging"),
381 "manage_options",
382 "wpstg-tools",
383 [$this, "getToolsPage"]
384 );
385
386 if (!defined('WPSTGPRO_VERSION')) {
387
388 add_submenu_page(
389 $defaultPageSlug,
390 esc_html__("WP Staging - Welcome", "wp-staging"),
391 esc_html__("Get WP Staging Pro", "wp-staging"),
392 "manage_options",
393 "wpstg-welcome",
394 [$this, "getWelcomePage"]
395 );
396 }
397
398 if (defined('WPSTGPRO_VERSION')) {
399
400 add_submenu_page(
401 $defaultPageSlug,
402 esc_html__("WP Staging - Restore", "wp-staging"),
403 '',
404 "manage_options",
405 "wpstg-restorer",
406 [$this, "getRestorerPage"]
407 );
408
409
410 add_filter('submenu_file', function ($submenu_file) use ($defaultPageSlug) {
411 remove_submenu_page($defaultPageSlug, 'wpstg-restorer');
412 });
413
414
415 add_submenu_page(
416 $defaultPageSlug,
417 esc_html__("WP Staging - Licence", "wp-staging"),
418 esc_html__("License", "wp-staging"),
419 "manage_options",
420 "wpstg-license",
421 [$this, "getLicensePage"]
422 );
423 }
424 }
425
426
427
428
429
430
431
432 public function printRemoteSyncMenuBadgeStyle()
433 {
434 echo '<style>
435 #adminmenu .wpstg-menu-pro-badge {
436 display: inline-block;
437 margin-left: 5px;
438 padding: 1px 6px;
439 border-radius: 9px;
440 background: #2563eb;
441 color: #fff;
442 font-size: 10px;
443 font-weight: 600;
444 line-height: 1.6;
445 letter-spacing: .3px;
446 }
447 </style>';
448 }
449
450
451
452
453
454
455
456 public function printRemoteSyncMenuBadgeScript()
457 {
458 echo '<script>
459 document.querySelectorAll("#adminmenu .wpstg-menu-pro-badge").forEach(function (badge) {
460 var link = badge.closest("a");
461 if (link) {
462 link.target = "_blank";
463 link.rel = "noopener noreferrer";
464 }
465 });
466 </script>';
467 }
468
469
470
471
472 public function getSettingsPage()
473 {
474
475 $license = get_option('wpstg_license_status');
476
477
478 $tabs = new Tabs(Hooks::applyFilters(self::FILTER_MAIN_SETTING_TABS, [
479 "general" => __("General", "wp-staging"),
480 ]));
481
482 WPStaging::getInstance()
483
484 ->set("tabs", $tabs)
485
486 ->set("forms", new FormSettings($tabs));
487
488 require_once "{$this->viewsPath}settings/main-settings.php";
489 }
490
491
492
493
494 public function getClonePage()
495 {
496
497 $license = get_option('wpstg_license_status');
498
499 $availableClones = get_option(Sites::STAGING_SITES_OPTION, []);
500
501 $isStagingPage = true;
502 $isBackupPage = false;
503 require_once "{$this->viewsPath}clone/index.php";
504 }
505
506
507
508
509 public function getBackupPage()
510 {
511 $license = get_option('wpstg_license_status');
512
513
514 $availableClones = get_option(Sites::STAGING_SITES_OPTION, []);
515
516 $isBackupPage = true;
517 $isStagingPage = false;
518 require_once "{$this->viewsPath}clone/index.php";
519 }
520
521
522
523
524 public function getWelcomePage()
525 {
526 if (defined('WPSTGPRO_VERSION')) {
527 return;
528 }
529
530 require_once "{$this->viewsPath}welcome/welcome.php";
531 }
532
533
534
535
536 public function getToolsPage()
537 {
538
539 $tabs = new Tabs([
540 "system-info" => __("System Info", "wp-staging"),
541 ]);
542
543 WPStaging::getInstance()->set("tabs", $tabs);
544
545 WPStaging::getInstance()->set("systemInfo", new SystemInfo());
546
547
548 $license = get_option('wpstg_license_status');
549
550 require_once "{$this->viewsPath}tools/index.php";
551 }
552
553
554
555
556
557 public function getRestorerPage()
558 {
559
560 $license = get_option('wpstg_license_status');
561
562 require_once "{$this->viewsPath}pro/wpstg-restorer-ui.php";
563 }
564
565
566
567
568
569
570
571 public function downloadWpstgRestoreFile()
572 {
573 if (!defined('WPSTGPRO_VERSION') || !class_exists('WPStaging\Backend\Pro\WpstgRestoreDownloader', false)) {
574 wp_die('Invalid access', 'WP Staging Restore', ['response' => 403, 'back_link' => true]);
575 }
576
577 $WpstgRestore = WPStaging::make('WPStaging\Backend\Pro\WpstgRestoreDownloader');
578 $WpstgRestore->downloadFile();
579 }
580
581
582
583
584
585 public function downloadSystemInfoAndLogFiles()
586 {
587 if (!current_user_can("update_plugins")) {
588 return;
589 }
590
591 $reportHandle = WPStaging::make(Report::class);
592 $downloadFile = $reportHandle->getBundledLogs();
593 if (empty($downloadFile)) {
594 wp_die('Failed to get All Log Files', 'WP Staging', ['response' => 200, 'back_link' => true]);
595 }
596
597 $isZipFile = count($downloadFile) === 1 && substr($downloadFile[0], -4) === '.zip';
598
599 nocache_headers();
600
601 if ($isZipFile) {
602 header('Content-Type: application/zip');
603 header('Content-Disposition: attachment; filename="wpstg-bundled-logs.zip"');
604 readfile($downloadFile[0]); // phpcs:ignore
605 $reportHandle->deleteBundledLogs();
606 exit();
607 }
608
609 header('Content-Type: text/plain');
610 header('Content-Disposition: attachment; filename="wpstg-bundled-logs.txt"');
611
612 $separator = "\n\n" . str_repeat('-', 100) . "\n\n";
613
614 foreach ($downloadFile as $logFile) {
615 $header = $separator . 'Log File: ' . basename($logFile) . $separator;
616 echo esc_html($header);
617 readfile($logFile); // phpcs:ignore
618 }
619
620 $reportHandle->deleteBundledLogs();
621 exit();
622 }
623
624
625
626
627
628
629
630 public function render($file, $vars = [])
631 {
632 $fullPath = $this->viewsPath . $file . ".php";
633 $fullPath = wp_normalize_path($fullPath);
634
635 if (!file_exists($fullPath) || !is_readable($fullPath)) {
636 return "Can't render : {$fullPath} either file doesn't exist or can't read it";
637 }
638
639 $contents = @file_get_contents($fullPath);
640
641
642 if (count($vars) > 0) {
643 $vars = array_combine(
644 array_map(function ($key) {
645 return "{{" . $key . "}}";
646 }, array_keys($vars)),
647 $vars
648 );
649
650 $contents = str_replace(array_keys($vars), array_values($vars), $contents);
651 }
652
653 return $contents;
654 }
655
656
657
658
659 private function isAuthenticated($nonce = Nonce::WPSTG_NONCE)
660 {
661 return $this->auth->isAuthenticatedRequest($nonce);
662 }
663
664
665
666
667 public function ajaxRestart()
668 {
669 if (!$this->isAuthenticated()) {
670 return;
671 }
672
673 $process = WPStaging::make(ProcessLock::class);
674 $process->restart();
675 }
676
677
678
679
680
681
682 public function ajaxCloneScan()
683 {
684 if (!$this->isAuthenticated()) {
685 return;
686 }
687
688
689 $processLock = WPStaging::make(ProcessLock::class);
690 $response = $processLock->ajaxIsRunning();
691 if ($response !== false) {
692 echo json_encode($response);
693
694 exit();
695 }
696
697 $siteInfo = WPStaging::make(SiteInfo::class);
698
699 $db = WPStaging::make('wpdb');
700
701
702 $scan = WPStaging::make(Scan::class);
703 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
704 $scan->setInfoIcon($this->assets->getAssetsUrl('svg/info-outline.svg'));
705 $scan->start();
706
707
708 $options = $scan->getOptions();
709 $excludeUtils = WPStaging::make(ExcludeFilter::class);
710 $wpDefaultDirectories = WPStaging::make(WpDefaultDirectories::class);
711 $isPro = WPStaging::isPro();
712
713 if ($isPro) {
714 require_once "{$this->viewsPath}pro/clone/ajax/scan.php";
715 } else {
716 require_once "{$this->viewsPath}clone/ajax/scan.php";
717 }
718
719 wp_die();
720 }
721
722
723
724
725 public function ajaxFetchDirChildren()
726 {
727 if (!$this->isAuthenticated()) {
728 wp_send_json(['success' => false]);
729 return;
730 }
731
732 $isChecked = isset($_POST['isChecked']) ? $this->sanitize->sanitizeBool($_POST['isChecked']) : false;
733 $forceDefault = isset($_POST['forceDefault']) ? $this->sanitize->sanitizeBool($_POST['forceDefault']) : false;
734 $path = isset($_POST['dirPath']) ? $this->sanitize->sanitizePath($_POST['dirPath']) : "";
735 $prefix = isset($_POST['prefix']) ? $this->sanitize->sanitizePath($_POST['prefix']) : "";
736 $basePath = ABSPATH;
737 if ($prefix === PathIdentifier::IDENTIFIER_WP_CONTENT) {
738 $basePath = WP_CONTENT_DIR;
739 }
740
741 $path = trailingslashit($basePath) . $path;
742
743
744 $resolvedPath = realpath($path);
745 $resolvedBase = realpath($basePath);
746 if ($resolvedPath === false || $resolvedBase === false) {
747 wp_send_json(['success' => false]);
748 return;
749 }
750
751
752 if ($resolvedPath !== $resolvedBase && strpos(trailingslashit($resolvedPath), trailingslashit($resolvedBase)) !== 0) {
753 wp_send_json(['success' => false]);
754 return;
755 }
756
757 $path = $resolvedPath;
758 $scan = new Scan($path);
759 $scan->setBasePath($basePath);
760 $scan->setPathIdentifier($prefix);
761 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
762 $scan->getDirectories($path);
763 wp_send_json([
764 "success" => true,
765 "directoryListing" => json_encode($scan->directoryListing($isChecked, $forceDefault)),
766 ]);
767 }
768
769
770
771
772 public function ajaxCheckCloneDirectoryName()
773 {
774 if (!$this->isAuthenticated()) {
775 return;
776 }
777
778
779 $sitesHelper = WPStaging::make(Sites::class);
780 $cloneDirectoryName = isset($_POST["directoryName"]) ? $sitesHelper->sanitizeDirectoryName($_POST["directoryName"]) : '';
781
782 if (strlen($cloneDirectoryName) < 1) {
783 return;
784 }
785
786 $result = $sitesHelper->isCloneExists($cloneDirectoryName);
787 if ($result === false) {
788 wp_send_json(["status" => "success"]);
789 return;
790 }
791
792 wp_send_json([
793 "status" => "failed",
794 "message" => $result,
795 ]);
796 }
797
798
799
800
801 public function ajaxUpdateProcess()
802 {
803 if (!$this->isAuthenticated()) {
804 return;
805 }
806
807 $cloning = WPStaging::make(Updating::class);
808
809 if (!$cloning->save()) {
810 wp_die('Can not save clone data');
811 }
812
813 $options = $cloning->getOptions();
814 WPStaging::make(AnalyticsStagingUpdate::class)->enqueueStartEvent($options->jobIdentifier, $options);
815
816 require_once "{$this->viewsPath}clone/ajax/update.php";
817
818 wp_die();
819 }
820
821
822
823
824 public function ajaxResetProcess()
825 {
826 if (!$this->isAuthenticated()) {
827 return;
828 }
829
830 $cloning = WPStaging::make(Updating::class);
831 $cloning->setMainJob(Job::RESET);
832 if (!$cloning->save()) {
833 wp_die('can not save clone data');
834 }
835
836 $options = $cloning->getOptions();
837 WPStaging::make(AnalyticsStagingReset::class)->enqueueStartEvent($options->jobIdentifier, $options);
838
839 require_once "{$this->viewsPath}clone/ajax/update.php";
840 wp_die();
841 }
842
843
844
845
846 public function ajaxStartClone()
847 {
848 if (!$this->isAuthenticated()) {
849 return;
850 }
851
852
853 $processLock = WPStaging::make(ProcessLock::class);
854 $processLock->isRunning();
855
856 $cloning = $this->getCloningJob();
857
858 if (!$cloning->save()) {
859 $message = $cloning->getErrorMessage();
860 wp_send_json([
861 'success' => false,
862 'message' => $message !== '' ? $message : 'Can not save clone data',
863 ]);
864
865 wp_die();
866 }
867
868 require_once "{$this->viewsPath}clone/ajax/start.php";
869
870 wp_die();
871 }
872
873
874
875
876 public function ajaxCloneDatabase()
877 {
878 if (!$this->isAuthenticated()) {
879 return;
880 }
881
882 $cloning = $this->getCloningJob();
883 wp_send_json($cloning->start());
884 }
885
886
887
888
889 public function ajaxPrepareDirectories()
890 {
891 if (!$this->isAuthenticated()) {
892 return;
893 }
894
895 $cloning = $this->getCloningJob();
896 wp_send_json($cloning->start());
897 }
898
899
900
901
902 public function ajaxCopyFiles()
903 {
904 if (!$this->isAuthenticated()) {
905 return;
906 }
907
908 $cloning = $this->getCloningJob();
909 wp_send_json($cloning->start());
910 }
911
912
913
914
915 public function ajaxReplaceData()
916 {
917 if (!$this->isAuthenticated()) {
918 return;
919 }
920
921 $cloning = $this->getCloningJob();
922 wp_send_json($cloning->start());
923 }
924
925
926
927
928 public function ajaxFinish()
929 {
930 if (!$this->isAuthenticated()) {
931 return;
932 }
933
934 $cloning = $this->getCloningJob();
935 wp_send_json($cloning->start());
936 }
937
938
939
940
941 public function ajaxCancelClone()
942 {
943 if (!$this->isAuthenticated()) {
944 return;
945 }
946
947 $cancel = WPStaging::make(Cancel::class);
948 wp_send_json($cancel->start());
949 }
950
951
952
953
954 public function ajaxCancelUpdate()
955 {
956 if (!$this->isAuthenticated()) {
957 return;
958 }
959
960 $cancelUpdate = WPStaging::make(CancelUpdate::class);
961 wp_send_json($cancelUpdate->start());
962 }
963
964
965
966
967
968
969 public function ajaxHideRating()
970 {
971 if (!$this->isAuthenticated()) {
972 return;
973 }
974
975 if (update_option("wpstg_rating", "no") !== false) {
976 wp_send_json(true);
977 }
978
979 wp_send_json(null);
980 }
981
982
983
984
985
986
987
988
989
990
991
992 public function ajaxHideLaterRating()
993 {
994 if (!$this->isAuthenticated()) {
995 return;
996 }
997
998 $snoozeCount = (int)get_option('wpstg_rating_snooze_count', 0) + 1;
999 update_option('wpstg_rating_snooze_count', $snoozeCount);
1000
1001 $days = 180;
1002 if ($snoozeCount <= 1) {
1003 $days = 14;
1004 } elseif ($snoozeCount === 2) {
1005 $days = 30;
1006 }
1007
1008 $date = date('Y-m-d', strtotime(date('Y-m-d') . ' + ' . $days . ' days'));
1009 if (update_option('wpstg_rating', $date) !== false) {
1010 wp_send_json(true);
1011 }
1012
1013 wp_send_json(false);
1014 }
1015
1016
1017
1018
1019 public function ajaxHideBeta()
1020 {
1021 if (!$this->isAuthenticated()) {
1022 return;
1023 }
1024
1025 wp_send_json(update_option("wpstg_beta", "no"));
1026 }
1027
1028
1029
1030
1031 public function ajaxDismissNotice()
1032 {
1033 if (!$this->isAuthenticated()) {
1034 return;
1035 }
1036
1037
1038 if (!isset($_POST['wpstg_notice'])) {
1039 wp_send_json(null);
1040 return;
1041 }
1042
1043
1044 $dismissNotice = WPStaging::make(DismissNotice::class);
1045 $dismissNotice->dismiss($this->sanitize->sanitizeString($_POST['wpstg_notice']));
1046 }
1047
1048
1049
1050
1051 public function ajaxLogs()
1052 {
1053 if (!$this->isAuthenticated()) {
1054 return;
1055 }
1056
1057 $logs = WPStaging::make(Logs::class);
1058 wp_send_json($logs->start());
1059 }
1060
1061
1062
1063
1064
1065
1066
1067 public function ajaxPushScan()
1068 {
1069 if (!$this->isAuthenticated()) {
1070 return false;
1071 }
1072
1073 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Scan')) {
1074 return false;
1075 }
1076
1077
1078 $scan = WPStaging::make(ScanProModule::class);
1079
1080 $scan->start();
1081
1082
1083 $options = $scan->getOptions();
1084
1085
1086 $utilsMath = WPStaging::make(Math::class);
1087
1088 require_once "{$this->viewsPath}pro/scan.php";
1089
1090 wp_die();
1091 }
1092
1093
1094
1095
1096 public function ajaxPushTables()
1097 {
1098 if (!$this->isAuthenticated()) {
1099 return false;
1100 }
1101
1102 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Scan')) {
1103 return false;
1104 }
1105
1106
1107 $scan = WPStaging::make(ScanProModule::class);
1108 $scan->loadStagingDBTables($onlyLoadStagingPrefixTables = false);
1109 $scan->start();
1110 $options = $scan->getOptions();
1111
1112 $includedTables = isset($_POST['includedTables']) ? $this->sanitize->sanitizeString($_POST['includedTables']) : '';
1113 $excludedTables = isset($_POST['excludedTables']) ? $this->sanitize->sanitizeString($_POST['excludedTables']) : '';
1114 $selectedTablesWithoutPrefix = isset($_POST['selectedTablesWithoutPrefix']) ? $this->sanitize->sanitizeString($_POST['selectedTablesWithoutPrefix']) : '';
1115 $selectedTables = new SelectedTables($includedTables, $excludedTables, $selectedTablesWithoutPrefix);
1116 $selectedTables->setDatabaseInfo($options->databaseServer, $options->databaseUser, $options->databasePassword, $options->databaseDatabase, empty($options->databasePrefix) ? $options->prefix : $options->databasePrefix, $options->databaseSsl);
1117 $tables = $selectedTables->getSelectedTables($options->networkClone);
1118
1119 $templateEngine = WPStaging::make(TemplateEngine::class);
1120
1121 echo json_encode([
1122 'success' => true,
1123 "content" => $templateEngine->render("pro/selections/tables.php", [
1124 'isNetworkClone' => $scan->isNetworkClone(),
1125 'options' => $options,
1126 'showAll' => true,
1127 'selected' => $tables,
1128 ]),
1129 ]);
1130
1131 exit();
1132 }
1133
1134
1135
1136
1137 public function ajaxPushProcessing()
1138 {
1139 if (!$this->isAuthenticated()) {
1140 return false;
1141 }
1142
1143 if (!class_exists('WPStaging\Backend\Pro\Modules\Jobs\Processing')) {
1144 return false;
1145 }
1146
1147
1148 try {
1149 $response = WPStaging::make(Processing::class)->start();
1150 } catch (ProcessLockedException $e) {
1151 wp_send_json_error($e->getMessage(), $e->getCode());
1152
1153 return false;
1154 }
1155
1156 wp_send_json($response);
1157
1158 return false;
1159 }
1160
1161
1162
1163
1164 public function getLicensePage()
1165 {
1166
1167 $license = get_option('wpstg_license_status');
1168
1169 $licensing = WPStaging::make(Licensing::class);
1170 $licenseEntitlements = $licensing->getEntitlements();
1171 $manualActivationUrl = $licensing->buildManualActivationBaseUrl();
1172 $manualActivationNonce = $licensing->generateActivationNonce();
1173 $manualActivationSiteUrl = home_url();
1174 $manualActivationItemName = Licensing::WPSTG_ITEM_NAME;
1175
1176 require_once "{$this->viewsPath}pro/licensing.php";
1177 }
1178
1179
1180
1181
1182 public function getTempLoginsPage()
1183 {
1184 Hooks::applyFilters(Administrator::FILTER_MAIN_SETTING_TABS, [
1185 "temporary-logins" => __("Temporary Logins", "wp-staging"),
1186 ]);
1187 }
1188
1189
1190
1191
1192
1193 public function ajaxSendReport($args = [])
1194 {
1195 if (!$this->isAuthenticated()) {
1196 return;
1197 }
1198
1199
1200 if (empty($args)) {
1201 $args = stripslashes_deep($_POST);
1202 }
1203
1204
1205 $emailRecipient = '';
1206 if (isset($args['wpstg_email'])) {
1207 $emailRecipient = $this->sanitize->sanitizeEmail($args['wpstg_email']);
1208 }
1209
1210
1211 $providerName = '';
1212 if (!empty($args['wpstg_provider'])) {
1213 $providerName = $this->sanitize->sanitizeString($args['wpstg_provider']);
1214 }
1215
1216
1217 $messageBody = '';
1218 if (!empty($args['wpstg_message'])) {
1219 $messageBody = $this->sanitize->sanitizeString($args['wpstg_message']);
1220 }
1221
1222
1223 $sendLogFiles = false;
1224 if (isset($args['wpstg_syslog'])) {
1225 $sendLogFiles = $this->sanitize->sanitizeBool($args['wpstg_syslog']);
1226 }
1227
1228
1229 $termsAccepted = false;
1230 if (isset($args['wpstg_terms'])) {
1231 $termsAccepted = $this->sanitize->sanitizeBool($args['wpstg_terms']);
1232 }
1233
1234
1235 $forceSend = isset($_POST['wpstg_force_send']) && $this->sanitize->sanitizeBool($_POST['wpstg_force_send']);
1236
1237 $report = WPStaging::make(Report::class);
1238 $errors = $report->send($emailRecipient, $messageBody, $termsAccepted, $sendLogFiles, $providerName, $forceSend);
1239
1240 echo json_encode(['errors' => $errors]);
1241 exit;
1242 }
1243
1244
1245
1246
1247
1248
1249 public function ajaxModalError()
1250 {
1251 if (!$this->isAuthenticated()) {
1252 return;
1253 }
1254
1255 $type = isset($_POST['type']) ? $this->sanitize->sanitizeString($_POST['type']) : null;
1256 if ($type === 'processLock') {
1257 $process = WPStaging::make(ProcessLock::class);
1258 $process->restart();
1259
1260 exit();
1261 }
1262 }
1263
1264
1265
1266
1267 public function ajaxCloneExcludesSettings()
1268 {
1269 if (!$this->isAuthenticated()) {
1270 return;
1271 }
1272
1273 $processLock = WPStaging::make(ProcessLock::class);
1274 $response = $processLock->ajaxIsRunning();
1275 if ($response !== false) {
1276 echo json_encode($response);
1277
1278 exit();
1279 }
1280
1281 $templateEngine = WPStaging::make(TemplateEngine::class);
1282
1283
1284 $scan = WPStaging::make(Scan::class);
1285 $scan->setGifLoaderPath($this->assets->getAssetsUrl('img/spinner.gif'));
1286 $scan->start();
1287
1288 echo json_encode([
1289 'success' => true,
1290 "html" => $templateEngine->render("clone/ajax/exclude-settings.php", [
1291 'scan' => $scan,
1292 'options' => $scan->getOptions(),
1293 'excludeUtils' => WPStaging::make(ExcludeFilter::class),
1294 ]),
1295 ]);
1296
1297 exit();
1298 }
1299
1300
1301
1302
1303 public function ajaxEnableStagingCloning()
1304 {
1305 if (!$this->isAuthenticated()) {
1306 return;
1307 }
1308
1309 if ($this->siteInfo->enableStagingSiteCloning()) {
1310 echo json_encode(['success' => 'true']);
1311 exit();
1312 }
1313
1314 echo json_encode(['success' => 'false', 'message' => __('Unable to enable cloning in the staging site', 'wp-staging')]);
1315 exit();
1316 }
1317
1318
1319
1320
1321 public function ajaxRestoreSettings()
1322 {
1323 if (!$this->isAuthenticated()) {
1324 return;
1325 }
1326
1327 WPStaging::make(SettingsService::class)->restoreDefaults();
1328 }
1329
1330
1331
1332
1333 public function removeOldUploadsBackup()
1334 {
1335 $backup = new BackupUploadsDir(null);
1336 $backup->removeUploadsBackup();
1337 }
1338
1339
1340
1341
1342
1343 protected function isPro()
1344 {
1345 if (!defined("WPSTGPRO_VERSION")) {
1346 return false;
1347 }
1348
1349 return true;
1350 }
1351
1352
1353
1354
1355 private function getCloningJob(): Cloning
1356 {
1357 return WPStaging::make(CloningJobProvider::class)->getCloningJob();
1358 }
1359
1360
1361
1362
1363
1364
1365 private function isPluginsPage()
1366 {
1367 global $pagenow;
1368 return ($pagenow === 'plugins.php');
1369 }
1370 }
1371