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