WP Staging – DB & File Duplicator & Migration - Version 2.1.3

Version Description

  • New: Add more details to tools->system info log for better debugging
  • New: Add buttons to select all default wp tables with one click
  • New: Show used db table in list of staging sites
  • Fix: Delete staging site not possible if db prefix is same as one of the live site
  • Fix: Edit/Update clone function is duplicating tables.
  • Fix: Other staging site can be overwritten when Edit/Update clone function is executed
  • Fix: Several improvements to improve reliability and prevent timeouts and fatal errors during cloning
Download this release

Release Info

Developer ReneHermi
Plugin Icon 128x128 WP Staging – DB & File Duplicator & Migration
Version 2.1.3
Comparing to
See all releases

Code changes from version 2.1.2 to 2.1.3

apps/Backend/Administrator.php CHANGED
@@ -1,651 +1,695 @@
1
- <?php
2
-
3
- namespace WPStaging\Backend;
4
-
5
- // No Direct Access
6
- if( !defined( "WPINC" ) ) {
7
- die;
8
- }
9
-
10
- use WPStaging\Backend\Modules\Jobs\Cancel;
11
- use WPStaging\Backend\Modules\Jobs\Cloning;
12
- use WPStaging\Backend\Modules\Jobs\Data;
13
- use WPStaging\Backend\Modules\Jobs\Database;
14
- use WPStaging\Backend\Modules\Jobs\Delete;
15
- use WPStaging\Backend\Modules\Jobs\Files;
16
- use WPStaging\Backend\Modules\Jobs\Scan;
17
- use WPStaging\Backend\Modules\Jobs\Logs;
18
- use WPStaging\Backend\Modules\Optimizer;
19
- use WPStaging\Backend\Modules\SystemInfo;
20
- use WPStaging\Backend\Modules\Views\Tabs\Tabs;
21
- use WPStaging\Backend\Notices\Notices;
22
- use WPStaging\DI\InjectionAware;
23
- use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
24
- use WPStaging\Backend\Activation;
25
- use WPStaging\WPStaging;
26
- use WPStaging\Backend\Pro\Modules\Jobs\Processing;
27
- use WPStaging\Backend\Pro\Licensing;
28
-
29
- /**
30
- * Class Administrator
31
- * @package WPStaging\Backend
32
- */
33
- class Administrator extends InjectionAware {
34
-
35
- /**
36
- * @var string
37
- */
38
- private $path;
39
-
40
- /**
41
- * @var string
42
- */
43
- private $url;
44
-
45
- /**
46
- * Initialize class
47
- */
48
- public function initialize() {
49
- $this->defineHooks();
50
-
51
- // Path to backend
52
- $this->path = plugin_dir_path( __FILE__ );
53
-
54
- // URL to public backend folder
55
- $this->url = plugin_dir_url( __FILE__ ) . "public/";
56
-
57
- // Load plugins meta data
58
- $this->loadMeta();
59
- }
60
-
61
- /**
62
- * Load plugn meta data
63
- */
64
- public function loadMeta() {
65
- $run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
66
- }
67
-
68
- /**
69
- * Define Hooks
70
- */
71
- private function defineHooks() {
72
- // Get loader
73
- $loader = $this->di->get( "loader" );
74
-
75
- $Activation = new \WPStaging\Backend\Activation\Activation();
76
-
77
- $Welcome = new Activation\Welcome();
78
-
79
- $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
80
- $loader->addAction( "admin_menu", $this, "addMenu", 10 );
81
- $loader->addAction( "admin_init", $this, "setOptionFormElements" );
82
- $loader->addAction( "admin_init", $this, "upgrade" );
83
- $loader->addAction( "admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload" );
84
- $loader->addAction( "admin_post_wpstg_export", $this, "export" );
85
- $loader->addAction( "admin_post_wpstg_import_settings", $this, "import" );
86
- $loader->addAction( "admin_notices", $this, "messages" );
87
-
88
- // Settings
89
- $settings = $this->di->get( "settings" );
90
-
91
- // Optimizer is ON
92
- if( $settings->isOptimizer() ) {
93
- $optimizer = new Optimizer( $this->di );
94
-
95
- $loader->addAction( "admin_init", $optimizer, "compatibility", 1 );
96
- $loader->addFilter( "option_active_plugins", $optimizer, "excludedPlugins" );
97
- $loader->addFilter( "site_option_active_sitewide_plugins", $optimizer, "excludedPlugins" );
98
- }
99
-
100
- // Ajax Requests
101
- $loader->addAction( "wp_ajax_wpstg_overview", $this, "ajaxOverview" );
102
- $loader->addAction( "wp_ajax_wpstg_scanning", $this, "ajaxScan" );
103
- $loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
104
- $loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
105
- $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
106
- $loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
107
- $loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
108
- $loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
109
- $loader->addAction( "wp_ajax_wpstg_clone_finish", $this, "ajaxFinish" );
110
- $loader->addAction( "wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation" );
111
- $loader->addAction( "wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone" );
112
- $loader->addAction( "wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone" );
113
- $loader->addAction( "wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll" );
114
- $loader->addAction( "wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating" );
115
- $loader->addAction( "wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta" );
116
- $loader->addAction( "wp_ajax_wpstg_logs", $this, "ajaxLogs" );
117
- $loader->addAction( "wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace" );
118
-
119
- // Ajax hooks pro Version
120
- $loader->addAction( "wp_ajax_wpstg_start_processing", $this, "ajaxProcessing" );
121
- $loader->addAction( "wp_ajax_wpstg_push_changes", $this, "ajaxPushChanges" );
122
- }
123
-
124
- /**
125
- * Register options form elements
126
- */
127
- public function setOptionFormElements() {
128
- register_setting( "wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions") );
129
- }
130
-
131
- /**
132
- * Upgrade routine
133
- */
134
- public function upgrade() {
135
- $upgrade = new Upgrade\Upgrade();
136
- $upgrade->doUpgrade();
137
- }
138
-
139
- /**
140
- * Sanitize options data and delete the cache
141
- * @param array $data
142
- * @return array
143
- */
144
- public function sanitizeOptions( $data = array() ) {
145
- $sanitized = $this->sanitizeData( $data );
146
-
147
- add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wpstg" ), "updated" );
148
-
149
- // Return sanitized data
150
- //return $sanitized;
151
- return apply_filters( "wpstg-settings", $sanitized, $data );
152
- }
153
-
154
- /**
155
- * @param array $data
156
- * @return array
157
- */
158
- private function sanitizeData( $data = array() ) {
159
- $sanitized = array();
160
-
161
- foreach ( $data as $key => $value ) {
162
- $sanitized[$key] = (is_array( $value )) ? $this->sanitizeData( $value ) : htmlspecialchars( $value );
163
- }
164
-
165
- return $sanitized;
166
- }
167
-
168
- /**
169
- * Add Admin Menu(s)
170
- */
171
- public function addMenu() {
172
-
173
- $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
174
-
175
- // Main WP Staging Menu
176
- add_menu_page(
177
- "WP-Staging", __( "WP Staging", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage"), $logo
178
- );
179
-
180
- // Page: Clone
181
- add_submenu_page(
182
- "wpstg_clone", __( "WP Staging Jobs", "wpstg" ), __( "Start", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage")
183
- );
184
-
185
- // Page: Settings
186
- add_submenu_page(
187
- "wpstg_clone", __( "WP Staging Settings", "wpstg" ), __( "Settings", "wpstg" ), "manage_options", "wpstg-settings", array($this, "getSettingsPage")
188
- );
189
-
190
- // Page: Tools
191
- add_submenu_page(
192
- "wpstg_clone", __( "WP Staging Tools", "wpstg" ), __( "Tools", "wpstg" ), "manage_options", "wpstg-tools", array($this, "getToolsPage")
193
- );
194
- // Page: Tools
195
- add_submenu_page(
196
- "wpstg_clone", __( "WP Staging Welcome", "wpstg" ), __( "Get WP Staging Pro", "wpstg" ), "manage_options", "wpstg-welcome", array($this, "getWelcomePage")
197
- );
198
-
199
- if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
200
- // Page: License
201
- add_submenu_page(
202
- "wpstg_clone", __( "WP Staging License", "wpstg" ), __( "License", "wpstg" ), "manage_options", "wpstg-license", array($this, "getLicensePage")
203
- );
204
- }
205
- }
206
-
207
- /**
208
- * Settings Page
209
- */
210
- public function getSettingsPage() {
211
- // Tabs
212
- $tabs = new Tabs( array(
213
- "general" => __( "General", "wpstg" )
214
- ) );
215
-
216
-
217
- $this->di
218
- // Set tabs
219
- ->set( "tabs", $tabs )
220
- // Forms
221
- ->set( "forms", new FormSettings( $tabs ) );
222
-
223
- require_once "{$this->path}views/settings/index.php";
224
- }
225
-
226
- /**
227
- * Clone Page
228
- */
229
- public function getClonePage() {
230
- // Existing clones
231
- $availableClones = get_option( "wpstg_existing_clones_beta", array() );
232
-
233
- require_once "{$this->path}views/clone/index.php";
234
- }
235
-
236
- /**
237
- * Welcome Page
238
- */
239
- public function getWelcomePage() {
240
- require_once "{$this->path}views/welcome/welcome.php";
241
- }
242
-
243
- /**
244
- * Tools Page
245
- */
246
- public function getToolsPage() {
247
- // Tabs
248
- $tabs = new Tabs( array(
249
- "import_export" => __( "Import/Export", "wpstg" ),
250
- "system_info" => __( "System Info", "wpstg" )
251
- ) );
252
-
253
- $this->di->set( "tabs", $tabs );
254
-
255
- $this->di->set( "systemInfo", new SystemInfo( $this->di ) );
256
-
257
- require_once "{$this->path}views/tools/index.php";
258
- }
259
-
260
- /**
261
- * System Information Download
262
- */
263
- public function systemInfoDownload() {
264
- if( !current_user_can( "update_plugins" ) ) {
265
- return;
266
- }
267
-
268
- nocache_headers();
269
- header( "Content-Type: text/plain" );
270
- header( "Content-Disposition: attachment; filename='wpstg-system-info.txt'" );
271
- echo wp_strip_all_tags( new SystemInfo( $this->di ) );
272
- }
273
-
274
- /**
275
- * Import JSON settings file
276
- */
277
- public function import() {
278
- if( empty( $_POST["wpstg_import_nonce"] ) ) {
279
- return;
280
- }
281
-
282
- if( !wp_verify_nonce( $_POST["wpstg_import_nonce"], "wpstg_import_nonce" ) ) {
283
- return;
284
- }
285
-
286
- if( !current_user_can( "update_plugins" ) ) {
287
- return;
288
- }
289
-
290
- $fileExtension = explode( '.', $_FILES["import_file"]["name"] );
291
- $fileExtension = end( $fileExtension );
292
- if( "json" !== $fileExtension ) {
293
- wp_die( "Please upload a valid .json file", "wpstg" );
294
- }
295
-
296
-
297
- $importFile = $_FILES["import_file"]["tmp_name"];
298
-
299
- if( empty( $importFile ) ) {
300
- wp_die( __( "Please upload a file to import", "wpstg" ) );
301
- }
302
-
303
- update_option( "wpstg_settings", json_decode( file_get_contents( $importFile, true ) ) );
304
-
305
- wp_safe_redirect( admin_url( "admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported" ) );
306
-
307
- return;
308
- }
309
-
310
- /**
311
- * Export settings to JSON file
312
- */
313
- public function export() {
314
- if( empty( $_POST["wpstg_export_nonce"] ) ) {
315
- return;
316
- }
317
-
318
- if( !wp_verify_nonce( $_POST["wpstg_export_nonce"], "wpstg_export_nonce" ) ) {
319
- return;
320
- }
321
-
322
- if( !current_user_can( "manage_options" ) ) {
323
- return;
324
- }
325
-
326
- $settings = get_option( "wpstg_settings", array() );
327
-
328
- ignore_user_abort( true );
329
-
330
- if( !in_array( "set_time_limit", explode( ',', ini_get( "disable_functions" ) ) ) && !@ini_get( "safe_mode" ) ) {
331
- set_time_limit( 0 );
332
- }
333
-
334
- $fileName = apply_filters( "wpstg_settings_export_filename", "wpstg-settings-export-" . date( "m-d-Y" ) ) . ".json";
335
-
336
- nocache_headers();
337
- header( "Content-Type: application/json; charset=utf-8" );
338
- header( "Content-Disposition: attachment; filename={$fileName}" );
339
- header( "Expires: 0" );
340
-
341
- echo json_encode( $settings );
342
- }
343
-
344
- /**
345
- * Render a view file
346
- * @param string $file
347
- * @param array $vars
348
- * @return string
349
- */
350
- public function render( $file, $vars = array() ) {
351
- $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
352
- $fullPath = str_replace( array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php" );
353
-
354
- if( !file_exists( $fullPath ) || !is_readable( $fullPath ) ) {
355
- return "Can't render : {$fullPath} either file doesn't exist or can't read it";
356
- }
357
-
358
- $contents = @file_get_contents( $fullPath );
359
-
360
- // Variables are set
361
- if( count( $vars ) > 0 ) {
362
- $vars = array_combine(
363
- array_map( function ($key) {
364
- return "{{" . $key . "}}";
365
- }, array_keys( $vars )
366
- ), $vars
367
- );
368
-
369
- $contents = str_replace( array_keys( $vars ), array_values( $vars ), $contents );
370
- }
371
-
372
- return $contents;
373
- }
374
-
375
- /**
376
- * Ajax Overview
377
- */
378
- public function ajaxOverview() {
379
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
380
-
381
- // Existing clones
382
- $availableClones = get_option( "wpstg_existing_clones_beta", array() );
383
-
384
- // Get license data
385
- $license = get_option( 'wpstg_license_status' );
386
-
387
- if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
388
- require_once "{$this->path}Pro/views/single-overview-pro.php";
389
- } else {
390
- require_once "{$this->path}views/clone/ajax/single-overview.php";
391
- }
392
-
393
- wp_die();
394
- }
395
-
396
- /**
397
- * Ajax Scan
398
- */
399
- public function ajaxScan() {
400
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
401
-
402
- // Scan
403
- $scan = new Scan();
404
- $scan->start();
405
-
406
- // Get Options
407
- $options = $scan->getOptions();
408
-
409
- require_once "{$this->path}views/clone/ajax/scan.php";
410
-
411
- wp_die();
412
- }
413
-
414
- /**
415
- * Ajax Check Clone Name
416
- */
417
- public function ajaxCheckCloneName() {
418
- $cloneName = sanitize_key( $_POST["cloneID"] );
419
- $cloneNameLength = strlen( $cloneName );
420
- $clones = get_option( "wpstg_existing_clones_beta", array() );
421
-
422
- // Check clone name length
423
- if( $cloneNameLength < 1 || $cloneNameLength > 16 ) {
424
- echo wp_send_json( array(
425
- "status" => "failed",
426
- "message" => "Clone name must be between 1 - 16 characters"
427
- ) );
428
- } elseif( array_key_exists( $cloneName, $clones ) ) {
429
- echo wp_send_json( array(
430
- "status" => "failed",
431
- "message" => "Clone name is already in use, please choose an another clone name"
432
- ) );
433
- }
434
-
435
- echo wp_send_json( array("status" => "success") );
436
- }
437
-
438
- /**
439
- * Ajax Start Clone (Basically just layout and saving data)
440
- */
441
- public function ajaxStartClone() {
442
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
443
-
444
- $cloning = new Cloning();
445
-
446
- if( !$cloning->save() ) {
447
- wp_die();
448
- }
449
-
450
- require_once "{$this->path}views/clone/ajax/start.php";
451
-
452
- wp_die();
453
- }
454
-
455
- /**
456
- * Ajax Clone Database
457
- */
458
- public function ajaxCloneDatabase() {
459
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
460
-
461
- $cloning = new Cloning();
462
-
463
- wp_send_json( $cloning->start() );
464
- }
465
-
466
- /**
467
- * Ajax Prepare Directories (get listing of files)
468
- */
469
- public function ajaxPrepareDirectories() {
470
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
471
-
472
- $cloning = new Cloning();
473
-
474
- wp_send_json( $cloning->start() );
475
- }
476
-
477
- /**
478
- * Ajax Clone Files
479
- */
480
- public function ajaxCopyFiles() {
481
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
482
-
483
- $cloning = new Cloning();
484
-
485
- wp_send_json( $cloning->start() );
486
- }
487
-
488
- /**
489
- * Ajax Replace Data
490
- */
491
- public function ajaxReplaceData() {
492
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
493
-
494
- $cloning = new Cloning();
495
-
496
- wp_send_json( $cloning->start() );
497
- }
498
-
499
- /**
500
- * Ajax Finish
501
- */
502
- public function ajaxFinish() {
503
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
504
-
505
- $cloning = new Cloning();
506
-
507
- wp_send_json( $cloning->start() );
508
- }
509
-
510
- /**
511
- * Ajax Delete Confirmation
512
- */
513
- public function ajaxDeleteConfirmation() {
514
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
515
-
516
- $delete = new Delete();
517
- $delete->setData();
518
-
519
- $clone = $delete->getClone();
520
-
521
- require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
522
-
523
- wp_die();
524
- }
525
-
526
- /**
527
- * Delete clone
528
- */
529
- public function ajaxDeleteClone() {
530
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
531
-
532
- $delete = new Delete();
533
- wp_send_json( $delete->start() );
534
- }
535
-
536
- /**
537
- * Delete clone
538
- */
539
- public function ajaxCancelClone() {
540
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
541
-
542
- $cancel = new Cancel();
543
- wp_send_json( $cancel->start() );
544
- }
545
-
546
- /**
547
- * Admin Messages
548
- */
549
- public function messages() {
550
- $notice = new Notices( $this->path, $this->url );
551
-
552
- $run = $notice->messages();
553
- }
554
-
555
- /**
556
- * Ajax Hide Poll
557
- * @return mixed boolean | json
558
- */
559
- public function ajaxHidePoll() {
560
- if( false !== update_option( "wpstg_poll", "no" ) ) {
561
- wp_send_json( true );
562
- }
563
- return wp_send_json();
564
- }
565
-
566
- /**
567
- * Ajax Hide Rating
568
- * @return mixed bool | json
569
- */
570
- public function ajaxHideRating() {
571
- if( false !== update_option( "wpstg_rating", "no" ) ) {
572
- wp_send_json( true );
573
- }
574
- return wp_send_json();
575
- }
576
-
577
- /**
578
- * Ajax Hide Beta
579
- */
580
- public function ajaxHideBeta() {
581
- wp_send_json( update_option( "wpstg_beta", "no" ) );
582
- }
583
-
584
- /**
585
- * Clone logs
586
- */
587
- public function ajaxLogs() {
588
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
589
-
590
- $logs = new Logs();
591
- wp_send_json( $logs->start() );
592
- }
593
-
594
- /**
595
- * Ajax Checks Free Disk Space
596
- */
597
- public function ajaxCheckFreeSpace() {
598
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
599
-
600
- $scan = new Scan();
601
- return $scan->hasFreeDiskSpace();
602
- }
603
-
604
- /**
605
- * Ajax Start Push Changes Process
606
- */
607
- public function ajaxProcessing() {
608
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
609
-
610
- if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Scan' ) ) {
611
- return false;
612
- }
613
-
614
- // Scan
615
- $scan = new Pro\Modules\Jobs\Scan();
616
- $scan->start();
617
-
618
- // Get Options
619
- $options = $scan->getOptions();
620
-
621
- require_once "{$this->path}Pro/views/scan.php";
622
-
623
- wp_die();
624
- }
625
-
626
- /**
627
- * Ajax Start Pushing. Needs wp quads pro)
628
- */
629
- public function ajaxPushChanges() {
630
- check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
631
-
632
- if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Processing' ) ) {
633
- return false;
634
- }
635
- // Start the process
636
- $processing = new Processing();
637
- wp_send_json( $processing->start() );
638
- }
639
-
640
- /**
641
- * License Page
642
- */
643
- public function getLicensePage() {
644
-
645
- // Get license data
646
- $license = get_option( 'wpstg_license_status' );
647
-
648
- require_once "{$this->path}Pro/views/licensing.php";
649
- }
650
-
651
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend;
4
+
5
+ // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\Backend\Modules\Jobs\Cancel;
11
+ use WPStaging\Backend\Modules\Jobs\CancelUpdate;
12
+ use WPStaging\Backend\Modules\Jobs\Cloning;
13
+ use WPStaging\Backend\Modules\Jobs\Updating;
14
+ use WPStaging\Backend\Modules\Jobs\Data;
15
+ use WPStaging\Backend\Modules\Jobs\Database;
16
+ use WPStaging\Backend\Modules\Jobs\Delete;
17
+ use WPStaging\Backend\Modules\Jobs\Files;
18
+ use WPStaging\Backend\Modules\Jobs\Scan;
19
+ use WPStaging\Backend\Modules\Jobs\Logs;
20
+ use WPStaging\Backend\Modules\Optimizer;
21
+ use WPStaging\Backend\Modules\SystemInfo;
22
+ use WPStaging\Backend\Modules\Views\Tabs\Tabs;
23
+ use WPStaging\Backend\Notices\Notices;
24
+ use WPStaging\DI\InjectionAware;
25
+ use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
26
+ use WPStaging\Backend\Activation;
27
+ use WPStaging\WPStaging;
28
+ use WPStaging\Backend\Pro\Modules\Jobs\Processing;
29
+ use WPStaging\Backend\Pro\Licensing;
30
+
31
+ /**
32
+ * Class Administrator
33
+ * @package WPStaging\Backend
34
+ */
35
+ class Administrator extends InjectionAware {
36
+
37
+ /**
38
+ * @var string
39
+ */
40
+ private $path;
41
+
42
+ /**
43
+ * @var string
44
+ */
45
+ private $url;
46
+
47
+ /**
48
+ * Initialize class
49
+ */
50
+ public function initialize() {
51
+ $this->defineHooks();
52
+
53
+ // Path to backend
54
+ $this->path = plugin_dir_path( __FILE__ );
55
+
56
+ // URL to public backend folder
57
+ $this->url = plugin_dir_url( __FILE__ ) . "public/";
58
+
59
+ // Load plugins meta data
60
+ $this->loadMeta();
61
+ }
62
+
63
+ /**
64
+ * Load plugn meta data
65
+ */
66
+ public function loadMeta() {
67
+ $run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
68
+ }
69
+
70
+ /**
71
+ * Define Hooks
72
+ */
73
+ private function defineHooks() {
74
+ // Get loader
75
+ $loader = $this->di->get( "loader" );
76
+
77
+ $Activation = new \WPStaging\Backend\Activation\Activation();
78
+
79
+ $Welcome = new Activation\Welcome();
80
+
81
+ $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
82
+ $loader->addAction( "admin_menu", $this, "addMenu", 10 );
83
+ $loader->addAction( "admin_init", $this, "setOptionFormElements" );
84
+ $loader->addAction( "admin_init", $this, "upgrade" );
85
+ $loader->addAction( "admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload" );
86
+ $loader->addAction( "admin_post_wpstg_export", $this, "export" );
87
+ $loader->addAction( "admin_post_wpstg_import_settings", $this, "import" );
88
+ $loader->addAction( "admin_notices", $this, "messages" );
89
+
90
+ // Ajax Requests
91
+ $loader->addAction( "wp_ajax_wpstg_overview", $this, "ajaxOverview" );
92
+ $loader->addAction( "wp_ajax_wpstg_scanning", $this, "ajaxScan" );
93
+ $loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
94
+ //$loader->addAction( "wp_ajax_wpstg_update_struc", $this, "ajaxStartUpdate" );
95
+ $loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
96
+ $loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
97
+ $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
98
+ $loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
99
+ $loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
100
+ $loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
101
+ $loader->addAction( "wp_ajax_wpstg_clone_finish", $this, "ajaxFinish" );
102
+ $loader->addAction( "wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation" );
103
+ $loader->addAction( "wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone" );
104
+ $loader->addAction( "wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone" );
105
+ $loader->addAction( "wp_ajax_wpstg_cancel_update", $this, "ajaxCancelUpdate" );
106
+ $loader->addAction( "wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll" );
107
+ $loader->addAction( "wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating" );
108
+ $loader->addAction( "wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta" );
109
+ $loader->addAction( "wp_ajax_wpstg_logs", $this, "ajaxLogs" );
110
+ $loader->addAction( "wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace" );
111
+
112
+ // Ajax hooks pro Version
113
+ $loader->addAction( "wp_ajax_wpstg_scan", $this, "ajaxPushScan" );
114
+ $loader->addAction( "wp_ajax_wpstg_push_processing", $this, "ajaxPushProcessing" );
115
+ //$loader->addAction( "wp_ajax_wpstg_copy_database", $this, "ajaxCopyDatabase" );
116
+ }
117
+
118
+ /**
119
+ * Register options form elements
120
+ */
121
+ public function setOptionFormElements() {
122
+ register_setting( "wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions") );
123
+ }
124
+
125
+ /**
126
+ * Upgrade routine
127
+ */
128
+ public function upgrade() {
129
+ $upgrade = new Upgrade\Upgrade();
130
+ $upgrade->doUpgrade();
131
+ }
132
+
133
+ /**
134
+ * Sanitize options data and delete the cache
135
+ * @param array $data
136
+ * @return array
137
+ */
138
+ public function sanitizeOptions( $data = array() ) {
139
+ $sanitized = $this->sanitizeData( $data );
140
+
141
+ add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wpstg" ), "updated" );
142
+
143
+ // Return sanitized data
144
+ //return $sanitized;
145
+ return apply_filters( "wpstg-settings", $sanitized, $data );
146
+ }
147
+
148
+ /**
149
+ * @param array $data
150
+ * @return array
151
+ */
152
+ private function sanitizeData( $data = array() ) {
153
+ $sanitized = array();
154
+
155
+ foreach ( $data as $key => $value ) {
156
+ $sanitized[$key] = (is_array( $value )) ? $this->sanitizeData( $value ) : htmlspecialchars( $value );
157
+ }
158
+
159
+ return $sanitized;
160
+ }
161
+
162
+ /**
163
+ * Add Admin Menu(s)
164
+ */
165
+ public function addMenu() {
166
+
167
+ $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
168
+
169
+ // Main WP Staging Menu
170
+ add_menu_page(
171
+ "WP-Staging", __( "WP Staging", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage"), $logo
172
+ );
173
+
174
+ // Page: Clone
175
+ add_submenu_page(
176
+ "wpstg_clone", __( "WP Staging Jobs", "wpstg" ), __( "Start", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage")
177
+ );
178
+
179
+ // Page: Settings
180
+ add_submenu_page(
181
+ "wpstg_clone", __( "WP Staging Settings", "wpstg" ), __( "Settings", "wpstg" ), "manage_options", "wpstg-settings", array($this, "getSettingsPage")
182
+ );
183
+
184
+ // Page: Tools
185
+ add_submenu_page(
186
+ "wpstg_clone", __( "WP Staging Tools", "wpstg" ), __( "Tools", "wpstg" ), "manage_options", "wpstg-tools", array($this, "getToolsPage")
187
+ );
188
+ // Page: Tools
189
+ add_submenu_page(
190
+ "wpstg_clone", __( "WP Staging Welcome", "wpstg" ), __( "Get WP Staging Pro", "wpstg" ), "manage_options", "wpstg-welcome", array($this, "getWelcomePage")
191
+ );
192
+
193
+ if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
194
+ // Page: License
195
+ add_submenu_page(
196
+ "wpstg_clone", __( "WP Staging License", "wpstg" ), __( "License", "wpstg" ), "manage_options", "wpstg-license", array($this, "getLicensePage")
197
+ );
198
+ }
199
+ }
200
+
201
+ /**
202
+ * Settings Page
203
+ */
204
+ public function getSettingsPage() {
205
+ // Tabs
206
+ $tabs = new Tabs( array(
207
+ "general" => __( "General", "wpstg" )
208
+ ) );
209
+
210
+
211
+ $this->di
212
+ // Set tabs
213
+ ->set( "tabs", $tabs )
214
+ // Forms
215
+ ->set( "forms", new FormSettings( $tabs ) );
216
+
217
+ require_once "{$this->path}views/settings/index.php";
218
+ }
219
+
220
+ /**
221
+ * Clone Page
222
+ */
223
+ public function getClonePage() {
224
+ // Existing clones
225
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
226
+
227
+ require_once "{$this->path}views/clone/index.php";
228
+ }
229
+
230
+ /**
231
+ * Welcome Page
232
+ */
233
+ public function getWelcomePage() {
234
+ require_once "{$this->path}views/welcome/welcome.php";
235
+ }
236
+
237
+ /**
238
+ * Tools Page
239
+ */
240
+ public function getToolsPage() {
241
+ // Tabs
242
+ $tabs = new Tabs( array(
243
+ "import_export" => __( "Import/Export", "wpstg" ),
244
+ "system_info" => __( "System Info", "wpstg" )
245
+ ) );
246
+
247
+ $this->di->set( "tabs", $tabs );
248
+
249
+ $this->di->set( "systemInfo", new SystemInfo( $this->di ) );
250
+
251
+ require_once "{$this->path}views/tools/index.php";
252
+ }
253
+
254
+ /**
255
+ * System Information Download
256
+ */
257
+ public function systemInfoDownload() {
258
+ if( !current_user_can( "update_plugins" ) ) {
259
+ return;
260
+ }
261
+
262
+ nocache_headers();
263
+ header( "Content-Type: text/plain" );
264
+ header( "Content-Disposition: attachment; filename='wpstg-system-info.txt'" );
265
+ echo wp_strip_all_tags( new SystemInfo( $this->di ) );
266
+ }
267
+
268
+ /**
269
+ * Import JSON settings file
270
+ */
271
+ public function import() {
272
+ if( empty( $_POST["wpstg_import_nonce"] ) ) {
273
+ return;
274
+ }
275
+
276
+ if( !wp_verify_nonce( $_POST["wpstg_import_nonce"], "wpstg_import_nonce" ) ) {
277
+ return;
278
+ }
279
+
280
+ if( !current_user_can( "update_plugins" ) ) {
281
+ return;
282
+ }
283
+
284
+ $fileExtension = explode( '.', $_FILES["import_file"]["name"] );
285
+ $fileExtension = end( $fileExtension );
286
+ if( "json" !== $fileExtension ) {
287
+ wp_die( "Please upload a valid .json file", "wpstg" );
288
+ }
289
+
290
+
291
+ $importFile = $_FILES["import_file"]["tmp_name"];
292
+
293
+ if( empty( $importFile ) ) {
294
+ wp_die( __( "Please upload a file to import", "wpstg" ) );
295
+ }
296
+
297
+ update_option( "wpstg_settings", json_decode( file_get_contents( $importFile, true ) ) );
298
+
299
+ wp_safe_redirect( admin_url( "admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported" ) );
300
+
301
+ return;
302
+ }
303
+
304
+ /**
305
+ * Export settings to JSON file
306
+ */
307
+ public function export() {
308
+ if( empty( $_POST["wpstg_export_nonce"] ) ) {
309
+ return;
310
+ }
311
+
312
+ if( !wp_verify_nonce( $_POST["wpstg_export_nonce"], "wpstg_export_nonce" ) ) {
313
+ return;
314
+ }
315
+
316
+ if( !current_user_can( "manage_options" ) ) {
317
+ return;
318
+ }
319
+
320
+ $settings = get_option( "wpstg_settings", array() );
321
+
322
+ ignore_user_abort( true );
323
+
324
+ if( !in_array( "set_time_limit", explode( ',', ini_get( "disable_functions" ) ) ) && !@ini_get( "safe_mode" ) ) {
325
+ set_time_limit( 0 );
326
+ }
327
+
328
+ $fileName = apply_filters( "wpstg_settings_export_filename", "wpstg-settings-export-" . date( "m-d-Y" ) ) . ".json";
329
+
330
+ nocache_headers();
331
+ header( "Content-Type: application/json; charset=utf-8" );
332
+ header( "Content-Disposition: attachment; filename={$fileName}" );
333
+ header( "Expires: 0" );
334
+
335
+ echo json_encode( $settings );
336
+ }
337
+
338
+ /**
339
+ * Render a view file
340
+ * @param string $file
341
+ * @param array $vars
342
+ * @return string
343
+ */
344
+ public function render( $file, $vars = array() ) {
345
+ $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
346
+ $fullPath = str_replace( array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php" );
347
+
348
+ if( !file_exists( $fullPath ) || !is_readable( $fullPath ) ) {
349
+ return "Can't render : {$fullPath} either file doesn't exist or can't read it";
350
+ }
351
+
352
+ $contents = @file_get_contents( $fullPath );
353
+
354
+ // Variables are set
355
+ if( count( $vars ) > 0 ) {
356
+ $vars = array_combine(
357
+ array_map( function ($key) {
358
+ return "{{" . $key . "}}";
359
+ }, array_keys( $vars )
360
+ ), $vars
361
+ );
362
+
363
+ $contents = str_replace( array_keys( $vars ), array_values( $vars ), $contents );
364
+ }
365
+
366
+ return $contents;
367
+ }
368
+
369
+ /**
370
+ * Ajax Overview
371
+ */
372
+ public function ajaxOverview() {
373
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
374
+
375
+ // Existing clones
376
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
377
+
378
+ // Get license data
379
+ $license = get_option( 'wpstg_license_status' );
380
+
381
+
382
+ if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
383
+ require_once "{$this->path}Pro/views/single-overview-pro.php";
384
+ } else {
385
+ require_once "{$this->path}views/clone/ajax/single-overview.php";
386
+ }
387
+
388
+ wp_die();
389
+ }
390
+
391
+ /**
392
+ * Ajax Scan
393
+ */
394
+ public function ajaxScan() {
395
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
396
+
397
+ // Scan
398
+ $scan = new Scan();
399
+ $scan->start();
400
+
401
+ // Get Options
402
+ $options = $scan->getOptions();
403
+
404
+ require_once "{$this->path}views/clone/ajax/scan.php";
405
+
406
+ wp_die();
407
+ }
408
+
409
+ /**
410
+ * Ajax Check Clone Name
411
+ */
412
+ public function ajaxCheckCloneName() {
413
+ $cloneName = sanitize_key( $_POST["cloneID"] );
414
+ $cloneNameLength = strlen( $cloneName );
415
+ $clones = get_option( "wpstg_existing_clones_beta", array() );
416
+
417
+ // Check clone name length
418
+ if( $cloneNameLength < 1 || $cloneNameLength > 16 ) {
419
+ echo wp_send_json( array(
420
+ "status" => "failed",
421
+ "message" => "Clone name must be between 1 - 16 characters"
422
+ ) );
423
+ } elseif( array_key_exists( $cloneName, $clones ) ) {
424
+ echo wp_send_json( array(
425
+ "status" => "failed",
426
+ "message" => "Clone name is already in use, please choose an another clone name"
427
+ ) );
428
+ }
429
+
430
+ echo wp_send_json( array("status" => "success") );
431
+ }
432
+
433
+
434
+
435
+
436
+ /**
437
+ * Ajax Start Updating Clone (Basically just layout and saving data)
438
+ */
439
+ // public function ajaxStartUpdate() {
440
+ // check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
441
+ //
442
+ // $cloning = new Updating();
443
+ //
444
+ // if( !$cloning->save() ) {
445
+ // wp_die('can not save clone data');
446
+ // }
447
+ //
448
+ // require_once "{$this->path}views/clone/ajax/update.php";
449
+ //
450
+ // wp_die();
451
+ // }
452
+ /**
453
+ * Ajax Start Updating Clone (Basically just layout and saving data)
454
+ */
455
+ public function ajaxUpdateProcess() {
456
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
457
+
458
+ $cloning = new Updating();
459
+
460
+ if( !$cloning->save() ) {
461
+ wp_die('can not save clone data');
462
+ }
463
+
464
+ require_once "{$this->path}views/clone/ajax/update.php";
465
+
466
+ wp_die();
467
+
468
+ //wp_send_json( $cloning->start() );
469
+ }
470
+ /**
471
+ * Ajax Start Clone (Basically just layout and saving data)
472
+ */
473
+ public function ajaxStartClone() {
474
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
475
+
476
+ $cloning = new Cloning();
477
+
478
+ if( !$cloning->save() ) {
479
+ wp_die('can not save clone data');
480
+ }
481
+
482
+ require_once "{$this->path}views/clone/ajax/start.php";
483
+
484
+ wp_die();
485
+ }
486
+
487
+ /**
488
+ * Ajax Clone Database
489
+ */
490
+ public function ajaxCloneDatabase() {
491
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
492
+
493
+ $cloning = new Cloning();
494
+
495
+ wp_send_json( $cloning->start() );
496
+ }
497
+
498
+ /**
499
+ * Ajax Prepare Directories (get listing of files)
500
+ */
501
+ public function ajaxPrepareDirectories() {
502
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
503
+
504
+ $cloning = new Cloning();
505
+
506
+ wp_send_json( $cloning->start() );
507
+ }
508
+
509
+ /**
510
+ * Ajax Clone Files
511
+ */
512
+ public function ajaxCopyFiles() {
513
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
514
+
515
+ $cloning = new Cloning();
516
+
517
+ wp_send_json( $cloning->start() );
518
+ }
519
+
520
+ /**
521
+ * Ajax Replace Data
522
+ */
523
+ public function ajaxReplaceData() {
524
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
525
+
526
+ $cloning = new Cloning();
527
+
528
+ wp_send_json( $cloning->start() );
529
+ }
530
+
531
+ /**
532
+ * Ajax Finish
533
+ */
534
+ public function ajaxFinish() {
535
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
536
+
537
+ $cloning = new Cloning();
538
+
539
+ wp_send_json( $cloning->start() );
540
+ }
541
+
542
+ /**
543
+ * Ajax Delete Confirmation
544
+ */
545
+ public function ajaxDeleteConfirmation() {
546
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
547
+
548
+ $delete = new Delete();
549
+ $delete->setData();
550
+
551
+ $clone = $delete->getClone();
552
+
553
+ require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
554
+
555
+ wp_die();
556
+ }
557
+
558
+ /**
559
+ * Delete clone
560
+ */
561
+ public function ajaxDeleteClone() {
562
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
563
+
564
+ $delete = new Delete();
565
+ wp_send_json( $delete->start() );
566
+ }
567
+
568
+ /**
569
+ * Delete clone
570
+ */
571
+ public function ajaxCancelClone() {
572
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
573
+
574
+ $cancel = new Cancel();
575
+ wp_send_json( $cancel->start() );
576
+ }
577
+
578
+ /**
579
+ * Cancel updating process / Do not delete clone!
580
+ */
581
+ public function ajaxCancelUpdate() {
582
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
583
+
584
+ $cancel = new CancelUpdate();
585
+ wp_send_json( $cancel->start() );
586
+ }
587
+
588
+ /**
589
+ * Admin Messages
590
+ */
591
+ public function messages() {
592
+ $notice = new Notices( $this->path, $this->url );
593
+
594
+ $run = $notice->messages();
595
+ }
596
+
597
+ /**
598
+ * Ajax Hide Poll
599
+ * @return mixed boolean | json
600
+ */
601
+ public function ajaxHidePoll() {
602
+ if( false !== update_option( "wpstg_poll", "no" ) ) {
603
+ wp_send_json( true );
604
+ }
605
+ return wp_send_json();
606
+ }
607
+
608
+ /**
609
+ * Ajax Hide Rating
610
+ * @return mixed bool | json
611
+ */
612
+ public function ajaxHideRating() {
613
+ if( false !== update_option( "wpstg_rating", "no" ) ) {
614
+ wp_send_json( true );
615
+ }
616
+ return wp_send_json();
617
+ }
618
+
619
+ /**
620
+ * Ajax Hide Beta
621
+ */
622
+ public function ajaxHideBeta() {
623
+ wp_send_json( update_option( "wpstg_beta", "no" ) );
624
+ }
625
+
626
+ /**
627
+ * Clone logs
628
+ */
629
+ public function ajaxLogs() {
630
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
631
+
632
+ $logs = new Logs();
633
+ wp_send_json( $logs->start() );
634
+ }
635
+
636
+ /**
637
+ * Ajax Checks Free Disk Space
638
+ */
639
+ public function ajaxCheckFreeSpace() {
640
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
641
+
642
+ $scan = new Scan();
643
+ return $scan->hasFreeDiskSpace();
644
+ }
645
+
646
+ /**
647
+ * Ajax Start Push Changes Process
648
+ * Start with the module Scan
649
+ */
650
+ public function ajaxPushScan() {
651
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
652
+
653
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Scan' ) ) {
654
+ return false;
655
+ }
656
+
657
+ // Scan
658
+ $scan = new Pro\Modules\Jobs\Scan();
659
+
660
+ $scan->start();
661
+
662
+ // Get Options
663
+ $options = $scan->getOptions();
664
+
665
+ require_once "{$this->path}Pro/views/scan.php";
666
+
667
+ wp_die();
668
+ }
669
+
670
+ /**
671
+ * Ajax Start Pushing. Needs wp quads pro)
672
+ */
673
+ public function ajaxPushProcessing() {
674
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
675
+
676
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Processing' ) ) {
677
+ return false;
678
+ }
679
+ // Start the process
680
+ $processing = new Processing();
681
+ wp_send_json( $processing->start() );
682
+ }
683
+
684
+ /**
685
+ * License Page
686
+ */
687
+ public function getLicensePage() {
688
+
689
+ // Get license data
690
+ $license = get_option( 'wpstg_license_status' );
691
+
692
+ require_once "{$this->path}Pro/views/licensing.php";
693
+ }
694
+
695
+ }
apps/Backend/Modules/Jobs/CancelUpdate.php ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Modules\Jobs;
4
+
5
+ /**
6
+ * Class Cancel Update Processing
7
+ * @package WPStaging\Backend\Modules\Jobs
8
+ */
9
+ class CancelUpdate extends Job {
10
+
11
+ /**
12
+ * Start Module
13
+ * @return bool
14
+ */
15
+ public function start() {
16
+ $cloneData = $this->createCloneData();
17
+
18
+ if (empty($cloneData)) {
19
+ return true;
20
+ }
21
+ // Delete Cache Files
22
+ $this->deleteCacheFiles();
23
+
24
+ $this->returnFinish();
25
+
26
+ }
27
+
28
+ /**
29
+ * @return array
30
+ */
31
+ protected function createCloneData() {
32
+ $clone = array();
33
+
34
+ if (!$this->check()) {
35
+ return $clone;
36
+ }
37
+
38
+ $clone["name"] = $this->options->clone;
39
+ $clone["number"] = $this->options->cloneNumber;
40
+ $clone["path"] = ABSPATH . $this->options->cloneDirectoryName;
41
+ $clone["prefix"] = ABSPATH . $this->options->prefix;
42
+
43
+ return $clone;
44
+ }
45
+
46
+ /**
47
+ * @return bool
48
+ */
49
+ public function check() {
50
+ return (
51
+ isset($this->options) &&
52
+ isset($this->options->clone) &&
53
+ isset($this->options->cloneNumber) &&
54
+ isset($this->options->cloneDirectoryName) &&
55
+ isset($_POST["clone"]) &&
56
+ $_POST["clone"] === $this->options->clone
57
+ );
58
+ }
59
+
60
+ /**
61
+ * Get json response
62
+ * return json
63
+ */
64
+ private function returnFinish($message = '') {
65
+
66
+ wp_die(json_encode(array(
67
+ 'job' => 'delete',
68
+ 'status' => true,
69
+ 'message' => $message,
70
+ 'error' => false,
71
+ 'delete' => 'finished'
72
+ )));
73
+ }
74
+
75
+
76
+ /**
77
+ * Delete Cache Files
78
+ */
79
+ protected function deleteCacheFiles()
80
+ {
81
+ $this->log("Cancel Updating: Deleting clone job's cache files...");
82
+
83
+ // Clean cache files
84
+ $this->cache->delete("clone_options");
85
+ $this->cache->delete("files_to_copy");
86
+
87
+ $this->log("Updating process canceled");
88
+ }
89
+
90
+ }
apps/Backend/Modules/Jobs/Cloning.php CHANGED
@@ -2,6 +2,7 @@
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
 
5
 
6
  /**
7
  * Class Cloning
@@ -9,6 +10,12 @@ use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
9
  */
10
  class Cloning extends Job
11
  {
 
 
 
 
 
 
12
 
13
  /**
14
  * Save Chosen Cloning Settings
@@ -22,26 +29,39 @@ class Cloning extends Job
22
  }
23
 
24
  // Generate Options
25
-
26
  // Clone
27
  $this->options->clone = $_POST["cloneID"];
28
  $this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
29
  $this->options->cloneNumber = 1;
 
 
 
 
 
30
  $this->options->includedDirectories = array();
31
  $this->options->excludedDirectories = array();
32
- $this->options->extraDirectories = array();
33
- $this->options->excludedFiles = array('.htaccess', '.DS_Store', '.git', '.svn', '.tmp', 'desktop.ini', '.gitignore', '.log');
34
 
35
  // Job
36
  $this->options->job = new \stdClass();
37
 
38
- if (isset($this->options->existingClones[$this->options->clone]))
 
39
  {
 
40
  $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
41
- }
 
 
 
 
 
 
42
  elseif (!empty($this->options->existingClones))
43
  {
44
  $this->options->cloneNumber = count($this->options->existingClones)+1;
 
45
  }
46
 
47
  // Excluded Tables
@@ -91,6 +111,47 @@ class Cloning extends Job
91
  return $this->saveOptions();
92
  }
93
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
94
  /**
95
  * Start the cloning job
96
  */
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
+ use WPStaging\WPStaging;
6
 
7
  /**
8
  * Class Cloning
10
  */
11
  class Cloning extends Job
12
  {
13
+ /**
14
+ * Initialize is called in \Job
15
+ */
16
+ public function initialize(){
17
+ $this->db = WPStaging::getInstance()->get("wpdb");
18
+ }
19
 
20
  /**
21
  * Save Chosen Cloning Settings
29
  }
30
 
31
  // Generate Options
 
32
  // Clone
33
  $this->options->clone = $_POST["cloneID"];
34
  $this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
35
  $this->options->cloneNumber = 1;
36
+ //$this->options->prefix = "wpstg1_";
37
+ //$this->options->prefix = '2323';
38
+ $this->options->prefix = $this->getStagingPrefix();
39
+
40
+ //$this->options->prefix = $this->getStagingPrefix();
41
  $this->options->includedDirectories = array();
42
  $this->options->excludedDirectories = array();
43
+ $this->options->extraDirectories = array();
44
+ $this->options->excludedFiles = array('.htaccess', '.DS_Store', '.git', '.svn', '.tmp', 'desktop.ini', '.gitignore', '.log');
45
 
46
  // Job
47
  $this->options->job = new \stdClass();
48
 
49
+ // Check if clone data already exists and use that one
50
+ if (isset($this->options->existingClones[$this->options->clone]) )
51
  {
52
+
53
  $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
54
+
55
+ $this->options->prefix = isset($this->options->existingClones[$this->options->clone]->prefix) ?
56
+ $this->options->existingClones[$this->options->clone]->prefix :
57
+ $this->getStagingPrefix();
58
+
59
+ } // Clone does not exist but there are other clones in db
60
+ // Get data and increment it
61
  elseif (!empty($this->options->existingClones))
62
  {
63
  $this->options->cloneNumber = count($this->options->existingClones)+1;
64
+ $this->options->prefix = $this->getStagingPrefix();
65
  }
66
 
67
  // Excluded Tables
111
  return $this->saveOptions();
112
  }
113
 
114
+ /**
115
+ * Create a new staging prefix which does not already exists in database
116
+ */
117
+ public function getStagingPrefix(){
118
+
119
+ // Find a new prefix that does not already exist in database.
120
+ // 1000 different possible prefixes should be enough here
121
+ for($i=0; $i <= 10000; $i++){
122
+ $this->options->prefix = isset($this->options->existingClones) ?
123
+ 'wpstg' . (count($this->options->existingClones)+$i) . '_' :
124
+ 'wpstg' . $i . '_';
125
+
126
+ $sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
127
+ $tables = $this->db->get_results($sql);
128
+
129
+ // Prefix does not exists. We can use it
130
+ if (!$tables){
131
+ //$this->returnException('new ' . $this->options->prefix);
132
+ return $this->options->prefix;
133
+ }
134
+ }
135
+ $this->returnException("Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
136
+ wp_die("Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com");
137
+ }
138
+
139
+ /**
140
+ * Check if potential new prefix of staging site would be identical with live site.
141
+ * @return boolean
142
+ */
143
+ private function isPrefixIdentical(){
144
+ $db = WPStaging::getInstance()->get("wpdb");
145
+
146
+ $livePrefix = $db->prefix;
147
+ $stagingPrefix = $this->options->prefix;
148
+
149
+ if ($livePrefix == $stagingPrefix){
150
+ return true;
151
+ }
152
+ return false;
153
+ }
154
+
155
  /**
156
  * Start the cloning job
157
  */
apps/Backend/Modules/Jobs/Data.php CHANGED
@@ -1,407 +1,409 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
- }
9
-
10
- use WPStaging\Utils\Logger;
11
- use WPStaging\WPStaging;
12
-
13
- /**
14
- * Class Data
15
- * @package WPStaging\Backend\Modules\Jobs
16
- */
17
- class Data extends JobExecutable
18
- {
19
-
20
- /**
21
- * @var \wpdb
22
- */
23
- private $db;
24
-
25
- /**
26
- * @var string
27
- */
28
- private $prefix;
29
-
30
- /**
31
- * Initialize
32
- */
33
- public function initialize()
34
- {
35
- $this->db = WPStaging::getInstance()->get("wpdb");
36
-
37
- $this->prefix = "wpstg{$this->options->cloneNumber}_";
38
-
39
- // Fix current step
40
- if (0 == $this->options->currentStep)
41
- {
42
- $this->options->currentStep = 1;
43
- }
44
- }
45
-
46
- /**
47
- * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
48
- * @return void
49
- */
50
- protected function calculateTotalSteps()
51
- {
52
- $this->options->totalSteps = 6;
53
- }
54
-
55
- /**
56
- * Start Module
57
- * @return object
58
- */
59
- public function start()
60
- {
61
- // Execute steps
62
- $this->run();
63
-
64
- // Save option, progress
65
- $this->saveOptions();
66
-
67
- // Prepare response
68
- $this->response = array(
69
- "status" => true,
70
- "percentage" => 100,
71
- "total" => $this->options->totalSteps,
72
- "step" => $this->options->totalSteps,
73
- "last_msg" => $this->logger->getLastLogMsg(),
74
- "running_time" => $this->time() - time()
75
- );
76
-
77
- return (object) $this->response;
78
- }
79
-
80
- /**
81
- * Execute the Current Step
82
- * Returns false when over threshold limits are hit or when the job is done, true otherwise
83
- * @return bool
84
- */
85
- protected function execute()
86
- {
87
- // Fatal error. Let this happen never and break here immediately
88
- if ($this->isRoot()){
89
- return false;
90
- }
91
-
92
- // Over limits threshold
93
- if ($this->isOverThreshold())
94
- {
95
- // Prepare response and save current progress
96
- $this->prepareResponse(false, false);
97
- $this->saveOptions();
98
- return false;
99
- }
100
-
101
- // No more steps, finished
102
- if ($this->isFinished())
103
- {
104
- $this->prepareResponse(true, false);
105
- return false;
106
- }
107
-
108
- // Execute step
109
- $stepMethodName = "step" . $this->options->currentStep;
110
- if (!$this->{$stepMethodName}())
111
- {
112
- $this->prepareResponse(false, false);
113
- return false;
114
- }
115
-
116
- // Prepare Response
117
- $this->prepareResponse();
118
-
119
- // Not finished
120
- return true;
121
- }
122
-
123
- /**
124
- * Checks Whether There is Any Job to Execute or Not
125
- * @return bool
126
- */
127
- private function isFinished()
128
- {
129
- return (
130
- $this->options->currentStep > $this->options->totalSteps ||
131
- !method_exists($this, "step" . $this->options->currentStep)
132
- );
133
- }
134
-
135
- /**
136
- * Check if current operation is done on the root folder or on the live DB
137
- * @return boolean
138
- */
139
- private function isRoot(){
140
-
141
- // Prefix is the same as the one of live site
142
- $wpdb = WPStaging::getInstance()->get("wpdb");
143
- if ($wpdb->prefix === $this->prefix){
144
- return true;
145
- }
146
-
147
- // CloneName is empty
148
- $name = (array)$this->options->cloneDirectoryName;
149
- if (empty($name)){
150
- return true;
151
- }
152
-
153
- // Live Path === Staging path
154
- if (get_home_url() . $this->options->cloneDirectoryName === get_home_url()){
155
- return true;
156
- }
157
-
158
- return false;
159
- }
160
-
161
-
162
- /**
163
- * Check if table exists
164
- * @param string $table
165
- * @return boolean
166
- */
167
- protected function isTable($table){
168
- if($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table ){
169
- $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
170
- return false;
171
- }
172
- return true;
173
- }
174
-
175
- /**
176
- * Replace "siteurl"
177
- * @return bool
178
- */
179
- protected function step1() {
180
- $this->log( "Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
181
-
182
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
183
- return true;
184
- }
185
-
186
- // Installed in sub-directory
187
- if( isset( $this->settings->wpSubDirectory ) && "1" === $this->settings->wpSubDirectory ) {
188
- $subDirectory = str_replace( get_home_path(), '', ABSPATH );
189
- $this->log( "Updating siteurl and homeurl to " . get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName );
190
- // Replace URLs
191
- $result = $this->db->query(
192
- $this->db->prepare(
193
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName
194
- )
195
- );
196
- } else {
197
- $this->log( "Updating siteurl and homeurl to " . get_home_url() . '/' . $this->options->cloneDirectoryName );
198
- // Replace URLs
199
- $result = $this->db->query(
200
- $this->db->prepare(
201
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $this->options->cloneDirectoryName
202
- )
203
- );
204
- }
205
-
206
-
207
- // All good
208
- if( $result ) {
209
- return true;
210
- }
211
-
212
- $this->log( "Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
213
- return false;
214
- }
215
-
216
- /**
217
- * Update "wpstg_is_staging_site"
218
- * @return bool
219
- */
220
- protected function step2()
221
- {
222
-
223
- $this->log( "Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
224
-
225
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
226
- return true;
227
- }
228
-
229
- $result = $this->db->query(
230
- $this->db->prepare(
231
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'",
232
- "true"
233
- )
234
- );
235
-
236
- // No errors but no option name such as wpstg_is_staging_site
237
- if ('' === $this->db->last_error && 0 == $result)
238
- {
239
- $result = $this->db->query(
240
- $this->db->prepare(
241
- "INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)",
242
- "true"
243
- )
244
- );
245
- }
246
-
247
- // All good
248
- if ($result)
249
- {
250
- return true;
251
- }
252
-
253
- $this->log("Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
254
- return false;
255
- }
256
-
257
- /**
258
- * Update rewrite_rules
259
- * @return bool
260
- */
261
- protected function step3()
262
- {
263
-
264
- $this->log("Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}");
265
-
266
- if( false === $this->isTable( $this->prefix . 'options' ) ) {
267
- return true;
268
- }
269
-
270
- $result = $this->db->query(
271
- $this->db->prepare(
272
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'",
273
- ' '
274
- )
275
- );
276
-
277
- // All good
278
- if ($result)
279
- {
280
- return true;
281
- }
282
-
283
- $this->log("Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
284
- return false;
285
- }
286
-
287
- /**
288
- * Update Table Prefix in meta_keys
289
- * @return bool
290
- */
291
- protected function step4() {
292
- $this->log( "Updating {$this->prefix}usermeta db prefix {$this->db->last_error}" );
293
-
294
- if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
295
- return true;
296
- }
297
-
298
- $resultOptions = $this->db->query(
299
- $this->db->prepare(
300
- "UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
301
- )
302
- );
303
-
304
- if( !$resultOptions ) {
305
- $this->log( "Failed to update usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
306
- return false;
307
- }
308
-
309
- $this->log( "Updating {$this->prefix}options, option_name database table prefixes; {$this->db->last_error}" );
310
-
311
- $resultUserMeta = $this->db->query(
312
- $this->db->prepare(
313
- "UPDATE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
314
- )
315
- );
316
-
317
- if( !$resultUserMeta ) {
318
- $this->log( "Failed to update options, option_name database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
319
- return false;
320
- }
321
-
322
- return true;
323
- }
324
-
325
- /**
326
- * Update $table_prefix in wp-config.php
327
- * @return bool
328
- */
329
- protected function step5()
330
- {
331
- $path = get_home_path() . $this->options->cloneDirectoryName . "/wp-config.php";
332
-
333
- $this->log("Updating table_prefix in wp-config to " . $this->prefix);
334
- if (false === ($content = file_get_contents($path)))
335
- {
336
- $this->log("Failed to update table_prefix in wp-config; can't read contents", Logger::TYPE_ERROR);
337
- return false;
338
- }
339
-
340
- // Replace table prefix
341
- $content = str_replace('$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content);
342
-
343
- // Replace URLs
344
- $content = str_replace(get_home_url(), get_home_url() . '/' . $this->options->cloneDirectoryName, $content);
345
-
346
- if (false === @file_put_contents($path, $content))
347
- {
348
- $this->log("Failed to update $table_prefix in wp-config to " .$this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
349
- return false;
350
- }
351
-
352
- return true;
353
- }
354
-
355
- /**
356
- * Reset index.php to original file
357
- * Check first if main wordpress is used in subfolder and index.php in parent directory
358
- * @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
359
- * @return bool
360
- */
361
- protected function step6()
362
- {
363
- // No settings, all good
364
- if (!isset($this->settings->wpSubDirectory) || "1" !== $this->settings->wpSubDirectory)
365
- {
366
- $this->log("WP installation is not in a subdirectory! All good, skipping this step");
367
- return true;
368
- }
369
-
370
- $path = get_home_path() . $this->options->cloneDirectoryName . "/index.php";
371
-
372
- if (false === ($content = file_get_contents($path)))
373
- {
374
- $this->log("Failed to reset index.php for sub directory; can't read contents", Logger::TYPE_ERROR);
375
- return false;
376
- }
377
-
378
-
379
- if (!preg_match("/(require(.*)wp-blog-header.php' \);)/", $content, $matches))
380
- {
381
- $this->log(
382
- "Failed to reset index.php for sub directory; wp-blog-header.php is missing",
383
- Logger::TYPE_ERROR
384
- );
385
- return false;
386
- }
387
-
388
- $pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
389
-
390
- $replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
391
- $replace.= " // Changed by WP-Staging";
392
-
393
- if (null === preg_replace($pattern, $replace, $content))
394
- {
395
- $this->log("Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
396
- return false;
397
- }
398
-
399
- if (false === @file_put_contents($path, $content))
400
- {
401
- $this->log("Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR);
402
- return false;
403
- }
404
-
405
- return true;
406
- }
 
 
407
  }
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ // No Direct Access
5
+ if (!defined("WPINC"))
6
+ {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\Utils\Logger;
11
+ use WPStaging\WPStaging;
12
+
13
+ /**
14
+ * Class Data
15
+ * @package WPStaging\Backend\Modules\Jobs
16
+ */
17
+ class Data extends JobExecutable
18
+ {
19
+
20
+ /**
21
+ * @var \wpdb
22
+ */
23
+ private $db;
24
+
25
+ /**
26
+ * @var string
27
+ */
28
+ private $prefix;
29
+
30
+ /**
31
+ * Initialize
32
+ */
33
+ public function initialize()
34
+ {
35
+ $this->db = WPStaging::getInstance()->get("wpdb");
36
+
37
+ //$this->prefix = "wpstg{$this->options->cloneNumber}_";
38
+ $this->prefix = $this->options->prefix;
39
+
40
+ // Fix current step
41
+ if (0 == $this->options->currentStep)
42
+ {
43
+ $this->options->currentStep = 1;
44
+ }
45
+ }
46
+
47
+ /**
48
+ * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
49
+ * @return void
50
+ */
51
+ protected function calculateTotalSteps()
52
+ {
53
+ $this->options->totalSteps = 6;
54
+ }
55
+
56
+ /**
57
+ * Start Module
58
+ * @return object
59
+ */
60
+ public function start()
61
+ {
62
+ // Execute steps
63
+ $this->run();
64
+
65
+ // Save option, progress
66
+ $this->saveOptions();
67
+
68
+ // Prepare response
69
+ $this->response = array(
70
+ "status" => true,
71
+ "percentage" => 100,
72
+ "total" => $this->options->totalSteps,
73
+ "step" => $this->options->totalSteps,
74
+ "last_msg" => $this->logger->getLastLogMsg(),
75
+ "running_time" => $this->time() - time(),
76
+ "job_done" => true
77
+ );
78
+
79
+ return (object) $this->response;
80
+ }
81
+
82
+ /**
83
+ * Execute the Current Step
84
+ * Returns false when over threshold limits are hit or when the job is done, true otherwise
85
+ * @return bool
86
+ */
87
+ protected function execute()
88
+ {
89
+ // Fatal error. Let this happen never and break here immediately
90
+ if ($this->isRoot()){
91
+ return false;
92
+ }
93
+
94
+ // Over limits threshold
95
+ if ($this->isOverThreshold())
96
+ {
97
+ // Prepare response and save current progress
98
+ $this->prepareResponse(false, false);
99
+ $this->saveOptions();
100
+ return false;
101
+ }
102
+
103
+ // No more steps, finished
104
+ if ($this->isFinished())
105
+ {
106
+ $this->prepareResponse(true, false);
107
+ return false;
108
+ }
109
+
110
+ // Execute step
111
+ $stepMethodName = "step" . $this->options->currentStep;
112
+ if (!$this->{$stepMethodName}())
113
+ {
114
+ $this->prepareResponse(false, false);
115
+ return false;
116
+ }
117
+
118
+ // Prepare Response
119
+ $this->prepareResponse();
120
+
121
+ // Not finished
122
+ return true;
123
+ }
124
+
125
+ /**
126
+ * Checks Whether There is Any Job to Execute or Not
127
+ * @return bool
128
+ */
129
+ private function isFinished()
130
+ {
131
+ return (
132
+ $this->options->currentStep > $this->options->totalSteps ||
133
+ !method_exists($this, "step" . $this->options->currentStep)
134
+ );
135
+ }
136
+
137
+ /**
138
+ * Check if current operation is done on the root folder or on the live DB
139
+ * @return boolean
140
+ */
141
+ private function isRoot(){
142
+
143
+ // Prefix is the same as the one of live site
144
+ $wpdb = WPStaging::getInstance()->get("wpdb");
145
+ if ($wpdb->prefix === $this->prefix){
146
+ return true;
147
+ }
148
+
149
+ // CloneName is empty
150
+ $name = (array)$this->options->cloneDirectoryName;
151
+ if (empty($name)){
152
+ return true;
153
+ }
154
+
155
+ // Live Path === Staging path
156
+ if (get_home_url() . $this->options->cloneDirectoryName === get_home_url()){
157
+ return true;
158
+ }
159
+
160
+ return false;
161
+ }
162
+
163
+
164
+ /**
165
+ * Check if table exists
166
+ * @param string $table
167
+ * @return boolean
168
+ */
169
+ protected function isTable($table){
170
+ if($this->db->get_var("SHOW TABLES LIKE '{$table}'") != $table ){
171
+ $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
172
+ return false;
173
+ }
174
+ return true;
175
+ }
176
+
177
+ /**
178
+ * Replace "siteurl"
179
+ * @return bool
180
+ */
181
+ protected function step1() {
182
+ $this->log( "Search & Replace: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
183
+
184
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
185
+ return true;
186
+ }
187
+
188
+ // Installed in sub-directory
189
+ if( isset( $this->settings->wpSubDirectory ) && "1" === $this->settings->wpSubDirectory ) {
190
+ $subDirectory = str_replace( get_home_path(), '', ABSPATH );
191
+ $this->log( "Updating siteurl and homeurl to " . get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName );
192
+ // Replace URLs
193
+ $result = $this->db->query(
194
+ $this->db->prepare(
195
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $subDirectory . $this->options->cloneDirectoryName
196
+ )
197
+ );
198
+ } else {
199
+ $this->log( "Search & Replace:: Updating siteurl and homeurl to " . get_home_url() . '/' . $this->options->cloneDirectoryName );
200
+ // Replace URLs
201
+ $result = $this->db->query(
202
+ $this->db->prepare(
203
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", get_home_url() . '/' . $this->options->cloneDirectoryName
204
+ )
205
+ );
206
+ }
207
+
208
+
209
+ // All good
210
+ if( $result ) {
211
+ return true;
212
+ }
213
+
214
+ $this->log( "Search & Replace: Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
215
+ return false;
216
+ }
217
+
218
+ /**
219
+ * Update "wpstg_is_staging_site"
220
+ * @return bool
221
+ */
222
+ protected function step2()
223
+ {
224
+
225
+ $this->log( "Search & Replace: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
226
+
227
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
228
+ return true;
229
+ }
230
+
231
+ $result = $this->db->query(
232
+ $this->db->prepare(
233
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'",
234
+ "true"
235
+ )
236
+ );
237
+
238
+ // No errors but no option name such as wpstg_is_staging_site
239
+ if ('' === $this->db->last_error && 0 == $result)
240
+ {
241
+ $result = $this->db->query(
242
+ $this->db->prepare(
243
+ "INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)",
244
+ "true"
245
+ )
246
+ );
247
+ }
248
+
249
+ // All good
250
+ if ($result)
251
+ {
252
+ return true;
253
+ }
254
+
255
+ $this->log("Search & Replace: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
256
+ return false;
257
+ }
258
+
259
+ /**
260
+ * Update rewrite_rules
261
+ * @return bool
262
+ */
263
+ protected function step3()
264
+ {
265
+
266
+ $this->log("Search & Replace: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}");
267
+
268
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
269
+ return true;
270
+ }
271
+
272
+ $result = $this->db->query(
273
+ $this->db->prepare(
274
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'",
275
+ ' '
276
+ )
277
+ );
278
+
279
+ // All good
280
+ if ($result)
281
+ {
282
+ return true;
283
+ }
284
+
285
+ $this->log("Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR);
286
+ return true;
287
+ }
288
+
289
+ /**
290
+ * Update Table Prefix in meta_keys
291
+ * @return bool
292
+ */
293
+ protected function step4() {
294
+ $this->log( "Search & Replace: Updating {$this->prefix}usermeta db prefix {$this->db->last_error}" );
295
+
296
+ if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
297
+ return true;
298
+ }
299
+
300
+ $resultOptions = $this->db->query(
301
+ $this->db->prepare(
302
+ "UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
303
+ )
304
+ );
305
+
306
+ if( !$resultOptions ) {
307
+ $this->log( "Search & Replace: Failed to update usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
308
+ return false;
309
+ }
310
+
311
+ $this->log( "Updating {$this->prefix}options, option_name database table prefixes; {$this->db->last_error}" );
312
+
313
+ $resultUserMeta = $this->db->query(
314
+ $this->db->prepare(
315
+ "UPDATE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
316
+ )
317
+ );
318
+
319
+ if( !$resultUserMeta ) {
320
+ $this->log( "Search & Replace: Failed to update options, option_name database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
321
+ return false;
322
+ }
323
+
324
+ return true;
325
+ }
326
+
327
+ /**
328
+ * Update $table_prefix in wp-config.php
329
+ * @return bool
330
+ */
331
+ protected function step5()
332
+ {
333
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
334
+
335
+ $this->log("Search & Replace: Updating table_prefix in {$path} to " . $this->prefix);
336
+ if (false === ($content = file_get_contents($path)))
337
+ {
338
+ $this->log("Search & Replace: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR);
339
+ return false;
340
+ }
341
+
342
+ // Replace table prefix
343
+ $content = str_replace('$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content);
344
+
345
+ // Replace URLs
346
+ $content = str_replace(get_home_url(), get_home_url() . '/' . $this->options->cloneDirectoryName, $content);
347
+
348
+ if (false === @file_put_contents($path, $content))
349
+ {
350
+ $this->log("Search & Replace: Failed to update $table_prefix in {$path} to " .$this->prefix . ". Can't save contents", Logger::TYPE_ERROR);
351
+ return false;
352
+ }
353
+
354
+ return true;
355
+ }
356
+
357
+ /**
358
+ * Reset index.php to original file
359
+ * Check first if main wordpress is used in subfolder and index.php in parent directory
360
+ * @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
361
+ * @return bool
362
+ */
363
+ protected function step6()
364
+ {
365
+ // No settings, all good
366
+ if (!isset($this->settings->wpSubDirectory) || "1" !== $this->settings->wpSubDirectory)
367
+ {
368
+ $this->log("Search & Replace: WP installation is not in a subdirectory! All good, skipping this step");
369
+ return true;
370
+ }
371
+
372
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/index.php";
373
+
374
+ if (false === ($content = file_get_contents($path)))
375
+ {
376
+ $this->log("Search & Replace: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR);
377
+ return false;
378
+ }
379
+
380
+
381
+ if (!preg_match("/(require(.*)wp-blog-header.php' \);)/", $content, $matches))
382
+ {
383
+ $this->log(
384
+ "Search & Replace: Failed to reset index.php for sub directory; wp-blog-header.php is missing",
385
+ Logger::TYPE_ERROR
386
+ );
387
+ return false;
388
+ }
389
+
390
+ $pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
391
+
392
+ $replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
393
+ $replace.= " // Changed by WP-Staging";
394
+
395
+ if (null === preg_replace($pattern, $replace, $content))
396
+ {
397
+ $this->log("Search & Replace: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR);
398
+ return false;
399
+ }
400
+
401
+ if (false === @file_put_contents($path, $content))
402
+ {
403
+ $this->log("Search & Replace: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR);
404
+ return false;
405
+ }
406
+
407
+ return true;
408
+ }
409
  }
apps/Backend/Modules/Jobs/Database.php CHANGED
@@ -1,251 +1,263 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- //ini_set('display_startup_errors', 1);
5
- //ini_set('display_errors', 1);
6
- //error_reporting(-1);
7
-
8
- // No Direct Access
9
- if (!defined("WPINC"))
10
- {
11
- die;
12
- }
13
-
14
- use WPStaging\WPStaging;
15
-
16
- /**
17
- * Class Database
18
- * @package WPStaging\Backend\Modules\Jobs
19
- */
20
- class Database extends JobExecutable
21
- {
22
-
23
- /**
24
- * @var int
25
- */
26
- private $total = 0;
27
-
28
- /**
29
- * @var \WPDB
30
- */
31
- private $db;
32
-
33
- /**
34
- * Initialize
35
- */
36
- public function initialize()
37
- {
38
- // Variables
39
- $this->total = count($this->options->tables);
40
- $this->db = WPStaging::getInstance()->get("wpdb");
41
- }
42
-
43
- /**
44
- * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
45
- * @return void
46
- */
47
- protected function calculateTotalSteps()
48
- {
49
- $this->options->totalSteps = $this->total;
50
- }
51
-
52
- /**
53
- * Execute the Current Step
54
- * Returns false when over threshold limits are hit or when the job is done, true otherwise
55
- * @return bool
56
- */
57
- protected function execute()
58
- {
59
- // Over limits threshold
60
- if ($this->isOverThreshold())
61
- {
62
- // Prepare response and save current progress
63
- $this->prepareResponse(false, false);
64
- $this->saveOptions();
65
- return false;
66
- }
67
-
68
- // No more steps, finished
69
- if ($this->options->currentStep > $this->total || !isset($this->options->tables[$this->options->currentStep]))
70
- {
71
- $this->prepareResponse(true, false);
72
- return false;
73
- }
74
-
75
- // Table is excluded
76
- if (in_array($this->options->tables[$this->options->currentStep]->name, $this->options->excludedTables))
77
- {
78
- $this->prepareResponse();
79
- return true;
80
- }
81
-
82
- // Copy table
83
- if (!$this->copyTable($this->options->tables[$this->options->currentStep]->name))
84
- {
85
- // Prepare Response
86
- $this->prepareResponse(false, false);
87
-
88
- // Not finished
89
- return true;
90
- }
91
-
92
- // Prepare Response
93
- $this->prepareResponse();
94
-
95
- // Not finished
96
- return true;
97
- }
98
-
99
- /**
100
- * No worries, SQL queries don't eat from PHP execution time!
101
- * @param string $tableName
102
- * @return bool
103
- */
104
- private function copyTable($tableName)
105
- {
106
- $newTableName = "wpstg{$this->options->cloneNumber}_" . str_replace($this->db->prefix, null, $tableName);
107
-
108
- // Drop table if necessary
109
- $this->dropTable($newTableName);
110
-
111
- // Save current job
112
- $this->setJob($newTableName);
113
-
114
- // Beginning of the job
115
- if (!$this->startJob($newTableName, $tableName))
116
- {
117
- return true;
118
- }
119
-
120
- // Copy data
121
- $this->copyData($newTableName, $tableName);
122
-
123
- // Finis the step
124
- return $this->finishStep();
125
- }
126
-
127
- /**
128
- * Copy data from old table to new table
129
- * @param string $new
130
- * @param string $old
131
- */
132
- private function copyData($new, $old)
133
- {
134
- $rows = $this->options->job->start+$this->settings->queryLimit;
135
- $this->log(
136
- "Copying {$old} as {$new} between {$this->options->job->start} to {$rows} records"
137
- );
138
-
139
- $limitation = '';
140
-
141
- if (0 < (int) $this->settings->queryLimit)
142
- {
143
- $limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
144
- }
145
-
146
- $this->db->query(
147
- "INSERT INTO {$new} SELECT * FROM {$old} {$limitation}"
148
- );
149
-
150
- // Set new offset
151
- $this->options->job->start += $this->settings->queryLimit;
152
- }
153
-
154
- /**
155
- * Set the job
156
- * @param string $table
157
- */
158
- private function setJob($table)
159
- {
160
- if (isset($this->options->job->current))
161
- {
162
- return;
163
- }
164
-
165
- $this->options->job->current = $table;
166
- $this->options->job->start = 0;
167
- }
168
-
169
- /**
170
- * Start Job
171
- * @param string $new
172
- * @param string $old
173
- * @return bool
174
- */
175
- private function startJob($new, $old)
176
- {
177
- if (0 != $this->options->job->start)
178
- {
179
- return true;
180
- }
181
-
182
- $this->log("Creating table {$new} like {$old}");
183
-
184
- $this->db->query("CREATE TABLE {$new} LIKE {$old}");
185
-
186
- $this->options->job->total = (int) $this->db->get_var("SELECT COUNT(1) FROM {$old}");
187
-
188
- if (0 == $this->options->job->total)
189
- {
190
- $this->finishStep();
191
- return false;
192
- }
193
-
194
- return true;
195
- }
196
-
197
- /**
198
- * Finish the step
199
- */
200
- private function finishStep()
201
- {
202
- // This job is not finished yet
203
- if ($this->options->job->total > $this->options->job->start)
204
- {
205
- return false;
206
- }
207
-
208
- // Add it to cloned tables listing
209
- $this->options->clonedTables[] = $this->options->tables[$this->options->currentStep];
210
-
211
- // Reset job
212
- $this->options->job = new \stdClass();
213
-
214
- return true;
215
- }
216
-
217
- /**
218
- * Drop table if necessary
219
- * @param string $new
220
- */
221
- private function dropTable($new)
222
- {
223
- $old = $this->db->get_var($this->db->prepare("SHOW TABLES LIKE %s", $new));
224
-
225
- if (!$this->shouldDropTable($new, $old))
226
- {
227
- return;
228
- }
229
-
230
- $this->log("{$new} already exists, dropping it first");
231
- $this->db->query("DROP TABLE {$new}");
232
- }
233
-
234
- /**
235
- * Check if table needs to be dropped
236
- * @param string $new
237
- * @param string $old
238
- * @return bool
239
- */
240
- private function shouldDropTable($new, $old)
241
- {
242
- return (
243
- $old === $new &&
244
- (
245
- !isset($this->options->job->current) ||
246
- !isset($this->options->job->start) ||
247
- 0 == $this->options->job->start
248
- )
249
- );
250
- }
 
 
 
 
 
 
 
 
 
 
 
 
251
  }
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ // No Direct Access
5
+ if (!defined("WPINC"))
6
+ {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\WPStaging;
11
+
12
+ /**
13
+ * Class Database
14
+ * @package WPStaging\Backend\Modules\Jobs
15
+ */
16
+ class Database extends JobExecutable
17
+ {
18
+
19
+ /**
20
+ * @var int
21
+ */
22
+ private $total = 0;
23
+
24
+ /**
25
+ * @var \WPDB
26
+ */
27
+ private $db;
28
+
29
+ /**
30
+ * Initialize
31
+ */
32
+ public function initialize()
33
+ {
34
+ // Variables
35
+ $this->total = count($this->options->tables);
36
+ $this->db = WPStaging::getInstance()->get("wpdb");
37
+ }
38
+
39
+ /**
40
+ * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
41
+ * @return void
42
+ */
43
+ protected function calculateTotalSteps()
44
+ {
45
+ $this->options->totalSteps = $this->total;
46
+ }
47
+
48
+ /**
49
+ * Execute the Current Step
50
+ * Returns false when over threshold limits are hit or when the job is done, true otherwise
51
+ * @return bool
52
+ */
53
+ protected function execute()
54
+ {
55
+ // Over limits threshold
56
+ if ($this->isOverThreshold())
57
+ {
58
+ // Prepare response and save current progress
59
+ $this->prepareResponse(false, false);
60
+ $this->saveOptions();
61
+ return false;
62
+ }
63
+
64
+ // No more steps, finished
65
+ if ($this->options->currentStep > $this->total || !isset($this->options->tables[$this->options->currentStep]))
66
+ {
67
+ $this->prepareResponse(true, false);
68
+ return false;
69
+ }
70
+
71
+ // Table is excluded
72
+ if (in_array($this->options->tables[$this->options->currentStep]->name, $this->options->excludedTables))
73
+ {
74
+ $this->prepareResponse();
75
+ return true;
76
+ }
77
+
78
+ // Copy table
79
+ if (!$this->copyTable($this->options->tables[$this->options->currentStep]->name))
80
+ {
81
+ // Prepare Response
82
+ $this->prepareResponse(false, false);
83
+
84
+ // Not finished
85
+ return true;
86
+ }
87
+
88
+ // Prepare Response
89
+ $this->prepareResponse();
90
+
91
+ // Not finished
92
+ return true;
93
+ }
94
+
95
+ /**
96
+ * Get new prefix for the staging site
97
+ * @return string
98
+ */
99
+ private function getStagingPrefix(){
100
+ $stagingPrefix = $this->options->prefix;
101
+ // Make sure prefix of staging site is NEVER identical to prefix of live site!
102
+ if ( $stagingPrefix == $this->db->prefix ){
103
+ wp_die('Fatal error 7: The new database table prefix '. $stagingPrefix .' would be identical to the table prefix of the live site. Please open a support ticket to support@wp-staging.com');
104
+ }
105
+ return $stagingPrefix;
106
+ }
107
+
108
+ /**
109
+ * No worries, SQL queries don't eat from PHP execution time!
110
+ * @param string $tableName
111
+ * @return bool
112
+ */
113
+ private function copyTable($tableName)
114
+ {
115
+ //$this->returnException($this->getStagingPrefix());
116
+
117
+ //$newTableName = "wpstg{$this->options->cloneNumber}_" . str_replace($this->db->prefix, null, $tableName);
118
+ $newTableName = $this->getStagingPrefix() . str_replace($this->db->prefix, null, $tableName);
119
+
120
+ // Drop table if necessary
121
+ $this->dropTable($newTableName);
122
+
123
+ // Save current job
124
+ $this->setJob($newTableName);
125
+
126
+ // Beginning of the job
127
+ if (!$this->startJob($newTableName, $tableName))
128
+ {
129
+ return true;
130
+ }
131
+
132
+ // Copy data
133
+ $this->copyData($newTableName, $tableName);
134
+
135
+ // Finis the step
136
+ return $this->finishStep();
137
+ }
138
+
139
+ /**
140
+ * Copy data from old table to new table
141
+ * @param string $new
142
+ * @param string $old
143
+ */
144
+ private function copyData($new, $old)
145
+ {
146
+ $rows = $this->options->job->start+$this->settings->queryLimit;
147
+ $this->log(
148
+ "DB Copy: {$old} as {$new} between {$this->options->job->start} to {$rows} records"
149
+ );
150
+
151
+ $limitation = '';
152
+
153
+ if (0 < (int) $this->settings->queryLimit)
154
+ {
155
+ $limitation = " LIMIT {$this->settings->queryLimit} OFFSET {$this->options->job->start}";
156
+ }
157
+
158
+ $this->db->query(
159
+ "INSERT INTO {$new} SELECT * FROM {$old} {$limitation}"
160
+ );
161
+
162
+ // Set new offset
163
+ $this->options->job->start += $this->settings->queryLimit;
164
+ }
165
+
166
+ /**
167
+ * Set the job
168
+ * @param string $table
169
+ */
170
+ private function setJob($table)
171
+ {
172
+ if (isset($this->options->job->current))
173
+ {
174
+ return;
175
+ }
176
+
177
+ $this->options->job->current = $table;
178
+ $this->options->job->start = 0;
179
+ }
180
+
181
+ /**
182
+ * Start Job
183
+ * @param string $new
184
+ * @param string $old
185
+ * @return bool
186
+ */
187
+ private function startJob($new, $old)
188
+ {
189
+ if (0 != $this->options->job->start)
190
+ {
191
+ return true;
192
+ }
193
+
194
+ $this->log("DB Copy: Creating table {$new} like {$old}");
195
+
196
+ $this->db->query("CREATE TABLE {$new} LIKE {$old}");
197
+
198
+ $this->options->job->total = (int) $this->db->get_var("SELECT COUNT(1) FROM {$old}");
199
+
200
+ if (0 == $this->options->job->total)
201
+ {
202
+ $this->finishStep();
203
+ return false;
204
+ }
205
+
206
+ return true;
207
+ }
208
+
209
+ /**
210
+ * Finish the step
211
+ */
212
+ private function finishStep()
213
+ {
214
+ // This job is not finished yet
215
+ if ($this->options->job->total > $this->options->job->start)
216
+ {
217
+ return false;
218
+ }
219
+
220
+ // Add it to cloned tables listing
221
+ $this->options->clonedTables[] = $this->options->tables[$this->options->currentStep];
222
+
223
+ // Reset job
224
+ $this->options->job = new \stdClass();
225
+
226
+ return true;
227
+ }
228
+
229
+ /**
230
+ * Drop table if necessary
231
+ * @param string $new
232
+ */
233
+ private function dropTable($new)
234
+ {
235
+ $old = $this->db->get_var($this->db->prepare("SHOW TABLES LIKE %s", $new));
236
+
237
+ if (!$this->shouldDropTable($new, $old))
238
+ {
239
+ return;
240
+ }
241
+
242
+ $this->log("DB Copy: {$new} already exists, dropping it first");
243
+ $this->db->query("DROP TABLE {$new}");
244
+ }
245
+
246
+ /**
247
+ * Check if table needs to be dropped
248
+ * @param string $new
249
+ * @param string $old
250
+ * @return bool
251
+ */
252
+ private function shouldDropTable($new, $old)
253
+ {
254
+ return (
255
+ $old === $new &&
256
+ (
257
+ !isset($this->options->job->current) ||
258
+ !isset($this->options->job->start) ||
259
+ 0 == $this->options->job->start
260
+ )
261
+ );
262
+ }
263
  }
apps/Backend/Modules/Jobs/Delete.php CHANGED
@@ -117,6 +117,49 @@ class Delete extends Job {
117
  * Check and return prefix of the staging site
118
  */
119
  public function getStagingPrefix() {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
120
  // prefix not defined! Happens if staging site has ben generated with older version of wpstg
121
  // Try to get staging prefix from wp-config.php of staging site
122
  //wp_die($this->clone->directoryName);
@@ -146,12 +189,11 @@ class Delete extends Job {
146
 
147
  // Check if staging prefix is the same as the live prefix
148
  if ($this->wpdb->prefix == $this->clone->prefix) {
149
- $this->log("Fatal Error: Can not delete staging site. Prefix. '{$this->clone->prefix}' is used for the live site. Creating a new staging site will likely resolve this the next time. Stopping for security reasons. Contact support@wp-staging.com");
150
- wp_die("Fatal Error: Can not delete staging site. Prefix. '{$this->clone->prefix}' is used for the live site. Creating a new staging site will likely resolve this the next time. Stopping for security reasons. Contact support@wp-staging.com");
151
  }
152
 
153
  // Else
154
- return $this->clone->prefix;
155
  }
156
 
157
  /**
@@ -215,12 +257,23 @@ class Delete extends Job {
215
  return;
216
  }
217
 
218
- // Generate JOB
219
- $this->job = (object) array(
220
- "current" => "tables",
221
- "nextDirectoryToDelete" => $this->clone->path,
222
- "name" => $this->clone->name
223
- );
 
 
 
 
 
 
 
 
 
 
 
224
 
225
  $this->cache->save("delete_job_{$this->clone->name}", $this->job);
226
  }
@@ -263,12 +316,11 @@ class Delete extends Job {
263
  return;
264
  }
265
 
266
- //$wpdb = WPStaging::getInstance()->get("wpdb");
267
 
268
  foreach ($this->getTablesToRemove() as $table) {
269
  // PROTECTION: Never delete any table that beginns with wp prefix of live site
270
  if ($this->startsWith($table, $this->wpdb->prefix)) {
271
- $this->log("Fatal Error: Trying to delete table {$table} of main WP installation!", Logger::TYPE_CRITICAL);
272
  return false;
273
  } else {
274
  $this->wpdb->query("DROP TABLE {$table}");
@@ -328,36 +380,14 @@ class Delete extends Job {
328
  return;
329
  }
330
  }
331
- //rmdir($this->clone->path);
332
- // if (is_dir($this->clone->path)) {
333
- // return $this->returnException('Unable to delete all files in folder' . $this->clone->path . '<br>Please try to delete the folder manually via FTP. Than run the delete function again.');
334
- // } else {
335
- // return $this->returnFinish();
336
- // }
337
- if (@rmdir($this->clone->path)){
338
  return $this->returnFinish();
339
  }
340
  return;
341
-
342
-
343
-
344
  }
345
 
346
- /**
347
- * Delete Directories
348
- */
349
- public function deleteDirectory_old() {
350
- // No deleting directories or root of this clone is deleted
351
- if ($this->isDirectoryDeletingFinished()) {
352
- $this->job->current = "finish";
353
- $this->updateJob();
354
- return;
355
- }
356
-
357
- $this->processDirectory($this->job->nextDirectoryToDelete);
358
 
359
- return;
360
- }
361
 
362
  /**
363
  * @return bool
@@ -456,18 +486,7 @@ class Delete extends Job {
456
  wp_die(json_encode($response));
457
  }
458
 
459
- /**
460
- * Get json response
461
- * return json
462
- */
463
- // private function returnException($message = ''){
464
- // wp_die( json_encode(array(
465
- // 'job' => 'delete',
466
- // 'status' => false,
467
- // 'message' => $message,
468
- // 'error' => true
469
- // )));
470
- // }
471
  /**
472
  * Get json response
473
  * return json
117
  * Check and return prefix of the staging site
118
  */
119
  public function getStagingPrefix() {
120
+ // prefix not defined! Happens if staging site has ben generated with older version of wpstg
121
+ // Try to get staging prefix from wp-config.php of staging site
122
+ //wp_die($this->clone->directoryName);
123
+ if (empty($this->clone->prefix)) {
124
+ // Throw error
125
+ $path = ABSPATH . $this->clone->directoryName . "/wp-config.php";
126
+ if (false === ($content = @file_get_contents($path))) {
127
+ $this->log("Can not open {$path}. Can't read contents", Logger::TYPE_ERROR);
128
+ // Create a random prefix which highly like never exists
129
+ $this->clone->prefix = rand(7, 15) . '_';
130
+ } else {
131
+
132
+ // Get prefix from wp-config.php
133
+ //preg_match_all("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
134
+ preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
135
+
136
+ if (!empty($matches[1])) {
137
+ $this->clone->prefix = $matches[1];
138
+ } else {
139
+ $this->log("Can not find Prefix. '{$matches[1]}'.");
140
+ // Create a random prefix which highly like never exists
141
+ return $this->clone->prefix = rand(7, 15) . '_';
142
+ }
143
+ }
144
+ }
145
+
146
+ // Check if staging prefix is the same as the live prefix
147
+ if ($this->wpdb->prefix == $this->clone->prefix) {
148
+ // Create a random prefix which highly like never exists
149
+ return $this->clone->prefix = rand(7, 15) . '_';
150
+ $this->log("Can not use prefix. '{$this->clone->prefix}', is used for the live site. Creating a new random prefix");
151
+ //wp_die("Fatal Error: Can not delete staging site. Prefix. '{$this->clone->prefix}' is used for the live site. Creating a new staging site will likely resolve this the next time. Stopping for security reasons. Contact support@wp-staging.com");
152
+ }
153
+
154
+ // Else
155
+ return $this->clone->prefix;
156
+ }
157
+
158
+ /**
159
+ * Check if we can delete the staging site tables without affecting live ones
160
+ * @return bool
161
+ */
162
+ public function isInvalidStagingPrefix() {
163
  // prefix not defined! Happens if staging site has ben generated with older version of wpstg
164
  // Try to get staging prefix from wp-config.php of staging site
165
  //wp_die($this->clone->directoryName);
189
 
190
  // Check if staging prefix is the same as the live prefix
191
  if ($this->wpdb->prefix == $this->clone->prefix) {
192
+ return true;
 
193
  }
194
 
195
  // Else
196
+ return false;
197
  }
198
 
199
  /**
257
  return;
258
  }
259
 
260
+ // Skip deletion of tables and generate JOB to delete directories
261
+ if ($this->isInvalidStagingPrefix()) {
262
+ $this->log('Invalid staging prefix. Skip deleting tables');
263
+ // Generate JOB and delete tables
264
+ $this->job = (object) array(
265
+ "current" => "directory",
266
+ "nextDirectoryToDelete" => $this->clone->path,
267
+ "name" => $this->clone->name
268
+ );
269
+ } else {
270
+ // Generate JOB and delete tables
271
+ $this->job = (object) array(
272
+ "current" => "tables",
273
+ "nextDirectoryToDelete" => $this->clone->path,
274
+ "name" => $this->clone->name
275
+ );
276
+ }
277
 
278
  $this->cache->save("delete_job_{$this->clone->name}", $this->job);
279
  }
316
  return;
317
  }
318
 
 
319
 
320
  foreach ($this->getTablesToRemove() as $table) {
321
  // PROTECTION: Never delete any table that beginns with wp prefix of live site
322
  if ($this->startsWith($table, $this->wpdb->prefix)) {
323
+ $this->log("Fatal Error: Trying to delete table {$table} of main WP installation! Contact support[at]wp-staging.com", Logger::TYPE_CRITICAL);
324
  return false;
325
  } else {
326
  $this->wpdb->query("DROP TABLE {$table}");
380
  return;
381
  }
382
  }
383
+
384
+ if (@rmdir($this->clone->path)) {
 
 
 
 
 
385
  return $this->returnFinish();
386
  }
387
  return;
 
 
 
388
  }
389
 
 
 
 
 
 
 
 
 
 
 
 
 
390
 
 
 
391
 
392
  /**
393
  * @return bool
486
  wp_die(json_encode($response));
487
  }
488
 
489
+
 
 
 
 
 
 
 
 
 
 
 
490
  /**
491
  * Get json response
492
  * return json
apps/Backend/Modules/Jobs/Files.php CHANGED
@@ -1,11 +1,11 @@
1
  <?php
 
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  // No Direct Access
5
  use WPStaging\Utils\Logger;
6
 
7
- if (!defined("WPINC"))
8
- {
9
  die;
10
  }
11
 
@@ -13,8 +13,7 @@ if (!defined("WPINC"))
13
  * Class Files
14
  * @package WPStaging\Backend\Modules\Jobs
15
  */
16
- class Files extends JobExecutable
17
- {
18
 
19
  /**
20
  * @var \SplFileObject
@@ -24,7 +23,13 @@ class Files extends JobExecutable
24
  /**
25
  * @var int
26
  */
 
27
  private $maxFilesPerRun;
 
 
 
 
 
28
 
29
  /**
30
  * @var string
@@ -34,34 +39,35 @@ class Files extends JobExecutable
34
  /**
35
  * Initialization
36
  */
37
- public function initialize()
38
- {
 
39
  $this->destination = ABSPATH . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR;
40
 
41
  $filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
42
 
43
- if (is_file($filePath))
44
- {
45
  $this->file = new \SplFileObject($filePath, 'r');
46
  }
47
 
48
  // Informational logs
49
- if (0 == $this->options->currentStep)
50
- {
51
  $this->log("Copying files...");
52
  }
53
 
54
  $this->settings->batchSize = $this->settings->batchSize * 1000000;
55
  $this->maxFilesPerRun = $this->settings->fileLimit;
 
 
56
  }
57
 
58
  /**
59
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
60
  * @return void
61
  */
62
- protected function calculateTotalSteps()
63
- {
64
  $this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
 
65
  }
66
 
67
  /**
@@ -69,19 +75,16 @@ class Files extends JobExecutable
69
  * Returns false when over threshold limits are hit or when the job is done, true otherwise
70
  * @return bool
71
  */
72
- protected function execute()
73
- {
74
  // Finished
75
- if ($this->isFinished())
76
- {
77
  $this->log("Copying files finished");
78
  $this->prepareResponse(true, false);
79
  return false;
80
  }
81
 
82
  // Get files and copy'em
83
- if (!$this->getFilesAndCopy())
84
- {
85
  $this->prepareResponse(false, false);
86
  return false;
87
  }
@@ -97,39 +100,52 @@ class Files extends JobExecutable
97
  * Get files and copy
98
  * @return bool
99
  */
100
- private function getFilesAndCopy()
101
- {
102
  // Over limits threshold
103
- if ($this->isOverThreshold())
104
- {
105
  // Prepare response and save current progress
106
  $this->prepareResponse(false, false);
107
  $this->saveOptions();
108
  return false;
109
  }
110
 
111
- // Skip processed ones
112
- if ($this->options->copiedFiles != 0)
113
- {
114
  $this->file->seek($this->options->copiedFiles);
115
  }
116
 
117
  $this->file->setFlags(\SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD);
118
 
119
- // One thousand files at a time
120
- for ($i = 0; $i <= $this->maxFilesPerRun; $i++)
121
- {
 
 
 
 
 
 
 
 
 
 
 
 
122
  // End of file
123
- if ($this->file->eof())
124
- {
125
  break;
126
  }
 
 
 
 
127
 
128
- $this->copyFile($this->file->fgets());
129
  }
130
 
131
  $totalFiles = $this->maxFilesPerRun + $this->options->copiedFiles;
 
132
  $this->log("Total {$totalFiles} files processed");
 
133
 
134
  return true;
135
  }
@@ -138,36 +154,28 @@ class Files extends JobExecutable
138
  * Checks Whether There is Any Job to Execute or Not
139
  * @return bool
140
  */
141
- private function isFinished()
142
- {
143
  return (
144
- $this->options->currentStep > $this->options->totalSteps ||
145
- $this->options->copiedFiles >= $this->options->totalFiles
146
- );
147
  }
148
 
149
  /**
150
  * @param string $file
151
  * @return bool
152
  */
153
- private function copyFile($file)
154
- {
155
  $file = trim($file);
156
 
157
- // Increment copied files whatever the result is
158
- // This way we don't get stuck in the same step / files
159
- $this->options->copiedFiles++;
160
-
161
  // Invalid file, skipping it as if succeeded
162
- if (!is_file($file) || !is_readable($file))
163
- {
164
  $this->log("Can't read file or file doesn't exist {$file}");
165
  return true;
166
  }
167
 
168
  // Failed to get destination
169
- if (false === ($destination = $this->getDestination($file)))
170
- {
171
  $this->log("Can't get the destination of {$file}");
172
  return false;
173
  }
@@ -182,14 +190,12 @@ class Files extends JobExecutable
182
  * @param string $file
183
  * @return bool|string
184
  */
185
- private function getDestination($file)
186
- {
187
- $relativePath = str_replace(ABSPATH, null, $file);
188
- $destinationPath = $this->destination . $relativePath;
189
- $destinationDirectory = dirname($destinationPath);
190
-
191
- if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory, 0775, true))
192
- {
193
  $this->log("Destination directory doesn't exist; {$destinationDirectory}", Logger::TYPE_ERROR);
194
  return false;
195
  }
@@ -203,21 +209,18 @@ class Files extends JobExecutable
203
  * @param string $destination
204
  * @return bool
205
  */
206
- private function copy($file, $destination)
207
- {
208
  // Get file size
209
  $fileSize = filesize($file);
210
 
211
  // File is over batch size
212
- if ($fileSize >= $this->settings->batchSize)
213
- {
214
  $this->log("Trying to copy big file {$file} -> {$destination}", Logger::TYPE_INFO);
215
  return $this->copyBig($file, $destination, $this->settings->batchSize);
216
  }
217
 
218
  // Attempt to copy
219
- if (!@copy($file, $destination))
220
- {
221
  $this->log("Failed to copy file to destination: {$file} -> {$destination}", Logger::TYPE_ERROR);
222
  return false;
223
  }
@@ -251,7 +254,7 @@ class Files extends JobExecutable
251
  //
252
  // return ($bytes > 0);
253
  // }
254
-
255
  /**
256
  * Copy bigger files than $this->settings->batchSize
257
  * @param string $src
@@ -260,19 +263,19 @@ class Files extends JobExecutable
260
  * @return boolean
261
  */
262
  private function copyBig($src, $dst, $buffersize) {
263
- $src = fopen($src, 'r');
264
- $dest = fopen($dst, 'w');
265
-
266
  // Try first method:
267
- while (! feof($src)){
268
- if (false === fwrite($dest, fread($src, $buffersize))){
269
- $error = true;
270
- }
271
  }
272
  // Try second method if first one failed
273
- if (isset($error) && ($error === true)){
274
- while(!feof($src)){
275
- if (false === stream_copy_to_stream($src, $dest, 1024 )) {
276
  $this->log("Can not copy big file; {$src} -> {$dest}");
277
  fclose($src);
278
  fclose($dest);
@@ -284,5 +287,32 @@ class Files extends JobExecutable
284
  fclose($src);
285
  fclose($dest);
286
  return true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
287
  }
288
- }
1
  <?php
2
+
3
  namespace WPStaging\Backend\Modules\Jobs;
4
 
5
  // No Direct Access
6
  use WPStaging\Utils\Logger;
7
 
8
+ if (!defined("WPINC")) {
 
9
  die;
10
  }
11
 
13
  * Class Files
14
  * @package WPStaging\Backend\Modules\Jobs
15
  */
16
+ class Files extends JobExecutable {
 
17
 
18
  /**
19
  * @var \SplFileObject
23
  /**
24
  * @var int
25
  */
26
+ //private $maxFilesPerRun = 500;
27
  private $maxFilesPerRun;
28
+
29
+ /**
30
+ * File Object
31
+ */
32
+ //private $verifyFiles = array();
33
 
34
  /**
35
  * @var string
39
  /**
40
  * Initialization
41
  */
42
+ public function initialize() {
43
+ //$this->getVerifyFiles();
44
+
45
  $this->destination = ABSPATH . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR;
46
 
47
  $filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
48
 
49
+ if (is_file($filePath)) {
 
50
  $this->file = new \SplFileObject($filePath, 'r');
51
  }
52
 
53
  // Informational logs
54
+ if (0 == $this->options->currentStep) {
 
55
  $this->log("Copying files...");
56
  }
57
 
58
  $this->settings->batchSize = $this->settings->batchSize * 1000000;
59
  $this->maxFilesPerRun = $this->settings->fileLimit;
60
+ //$this->maxFilesPerRun = 1;
61
+ //$this->options->copiedFiles = 0;
62
  }
63
 
64
  /**
65
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
66
  * @return void
67
  */
68
+ protected function calculateTotalSteps() {
 
69
  $this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
70
+ //$this->options->totalSteps = $this->options->totalFiles;
71
  }
72
 
73
  /**
75
  * Returns false when over threshold limits are hit or when the job is done, true otherwise
76
  * @return bool
77
  */
78
+ protected function execute() {
 
79
  // Finished
80
+ if ($this->isFinished()) {
 
81
  $this->log("Copying files finished");
82
  $this->prepareResponse(true, false);
83
  return false;
84
  }
85
 
86
  // Get files and copy'em
87
+ if (!$this->getFilesAndCopy()) {
 
88
  $this->prepareResponse(false, false);
89
  return false;
90
  }
100
  * Get files and copy
101
  * @return bool
102
  */
103
+ private function getFilesAndCopy() {
 
104
  // Over limits threshold
105
+ if ($this->isOverThreshold()) {
 
106
  // Prepare response and save current progress
107
  $this->prepareResponse(false, false);
108
  $this->saveOptions();
109
  return false;
110
  }
111
 
112
+ // Go to last copied line and than to next one
113
+ if ($this->options->copiedFiles != 0) {
 
114
  $this->file->seek($this->options->copiedFiles);
115
  }
116
 
117
  $this->file->setFlags(\SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD);
118
 
119
+ // End of file
120
+ // if ($this->file->eof())
121
+ // {
122
+ // // Increment copied files when end of file is reached
123
+ // $this->options->copiedFiles++;
124
+ // return;
125
+ // }
126
+ // Loop x files at a time
127
+ for ($i = 0; $i < $this->maxFilesPerRun; $i++) {
128
+
129
+
130
+ // Increment copied files
131
+ // Do this anytime to make sure to not stuck in the same step / files
132
+ $this->options->copiedFiles++;
133
+
134
  // End of file
135
+ if ($this->file->eof()) {
 
136
  break;
137
  }
138
+ $file = $this->file->fgets();
139
+ $this->debugLog('copy file ' . $file, Logger::TYPE_DEBUG);
140
+ $this->copyFile($file);
141
+ //$this->verifyFiles[] = $file;
142
 
 
143
  }
144
 
145
  $totalFiles = $this->maxFilesPerRun + $this->options->copiedFiles;
146
+ //$totalFiles = $this->options->copiedFiles;
147
  $this->log("Total {$totalFiles} files processed");
148
+ //$this->saveCopiedFiles();
149
 
150
  return true;
151
  }
154
  * Checks Whether There is Any Job to Execute or Not
155
  * @return bool
156
  */
157
+ private function isFinished() {
 
158
  return (
159
+ $this->options->currentStep > $this->options->totalSteps ||
160
+ $this->options->copiedFiles >= $this->options->totalFiles
161
+ );
162
  }
163
 
164
  /**
165
  * @param string $file
166
  * @return bool
167
  */
168
+ private function copyFile($file) {
 
169
  $file = trim($file);
170
 
 
 
 
 
171
  // Invalid file, skipping it as if succeeded
172
+ if (!is_file($file) || !is_readable($file)) {
 
173
  $this->log("Can't read file or file doesn't exist {$file}");
174
  return true;
175
  }
176
 
177
  // Failed to get destination
178
+ if (false === ($destination = $this->getDestination($file))) {
 
179
  $this->log("Can't get the destination of {$file}");
180
  return false;
181
  }
190
  * @param string $file
191
  * @return bool|string
192
  */
193
+ private function getDestination($file) {
194
+ $relativePath = str_replace(ABSPATH, null, $file);
195
+ $destinationPath = $this->destination . $relativePath;
196
+ $destinationDirectory = dirname($destinationPath);
197
+
198
+ if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory, 0775, true)) {
 
 
199
  $this->log("Destination directory doesn't exist; {$destinationDirectory}", Logger::TYPE_ERROR);
200
  return false;
201
  }
209
  * @param string $destination
210
  * @return bool
211
  */
212
+ private function copy($file, $destination) {
 
213
  // Get file size
214
  $fileSize = filesize($file);
215
 
216
  // File is over batch size
217
+ if ($fileSize >= $this->settings->batchSize) {
 
218
  $this->log("Trying to copy big file {$file} -> {$destination}", Logger::TYPE_INFO);
219
  return $this->copyBig($file, $destination, $this->settings->batchSize);
220
  }
221
 
222
  // Attempt to copy
223
+ if (!@copy($file, $destination)) {
 
224
  $this->log("Failed to copy file to destination: {$file} -> {$destination}", Logger::TYPE_ERROR);
225
  return false;
226
  }
254
  //
255
  // return ($bytes > 0);
256
  // }
257
+
258
  /**
259
  * Copy bigger files than $this->settings->batchSize
260
  * @param string $src
263
  * @return boolean
264
  */
265
  private function copyBig($src, $dst, $buffersize) {
266
+ $src = fopen($src, 'r');
267
+ $dest = fopen($dst, 'w');
268
+
269
  // Try first method:
270
+ while (!feof($src)) {
271
+ if (false === fwrite($dest, fread($src, $buffersize))) {
272
+ $error = true;
273
+ }
274
  }
275
  // Try second method if first one failed
276
+ if (isset($error) && ($error === true)) {
277
+ while (!feof($src)) {
278
+ if (false === stream_copy_to_stream($src, $dest, 1024)) {
279
  $this->log("Can not copy big file; {$src} -> {$dest}");
280
  fclose($src);
281
  fclose($dest);
287
  fclose($src);
288
  fclose($dest);
289
  return true;
290
+ }
291
+
292
+ /**
293
+ * Save verified Files
294
+ * @return bool
295
+ */
296
+ // private function saveCopiedFiles(){
297
+ // $fileName = $this->cache->getCacheDir() . "files_to_verify." . $this->cache->getCacheExtension();
298
+ // $files = implode( PHP_EOL, $this->verifyFiles );
299
+ //
300
+ // return (false !== @file_put_contents( $fileName, $files ));
301
+ // }
302
+
303
+ /**
304
+ * Get files
305
+ * @return void
306
+ */
307
+ // protected function getVerifyFiles() {
308
+ // $fileName = $this->cache->getCacheDir() . "files_to_verify." . $this->cache->getCacheExtension();
309
+ //
310
+ // if( false === ($this->verifyFiles = @file_get_contents( $fileName )) ) {
311
+ // $this->verifyFiles = array();
312
+ // return;
313
+ // }
314
+ //
315
+ // $this->verifyFiles = explode( PHP_EOL, $this->verifyFiles );
316
+ // }
317
+
318
  }
 
apps/Backend/Modules/Jobs/Job.php CHANGED
@@ -97,16 +97,10 @@ abstract class Job implements JobInterface
97
  //$this->maxExecutionTime = (int) ini_get("max_execution_time");
98
  $this->maxExecutionTime = (int) 30;
99
 
100
- // if ($this->maxExecutionTime > 30)
101
  // {
102
  // $this->maxExecutionTime = 30;
103
  // }
104
- //
105
- // if ($this->maxExecutionTime < 1)
106
- // {
107
- // $this->maxExecutionTime = 30;
108
- // }
109
-
110
 
111
  // Services
112
  $this->cache = new Cache(-1, \WPStaging\WPStaging::getContentDir());
@@ -115,12 +109,9 @@ abstract class Job implements JobInterface
115
  // Settings and Options
116
  $this->options = $this->cache->get("clone_options");
117
  //$this->settings = json_decode(json_encode(get_option("wpstg_settings", array())));
118
- $this->settings = (object)get_option("wpstg_settings", array());
119
-
120
-
121
 
122
- // check default options
123
- if (!$this->settings)
124
  {
125
  $this->options = new \stdClass();
126
  }
@@ -130,7 +121,14 @@ abstract class Job implements JobInterface
130
  $this->options->existingClones = json_decode(json_encode($this->options->existingClones), true);
131
  }
132
 
133
- if (!isset($this->settings) || !isset($this->settings->queryLimit) || !isset($this->settings->batchSize) || !isset($this->settings->cpuLoad))
 
 
 
 
 
 
 
134
  {
135
  $this->settings = new \stdClass();
136
  $this->setDefaultSettings();
@@ -176,7 +174,7 @@ abstract class Job implements JobInterface
176
  */
177
  protected function setDefaultSettings(){
178
  $this->settings->queryLimit = "1000";
179
- $this->settings->fileCopyLimit = "10";
180
  $this->settings->batchSize = "2";
181
  $this->settings->cpuLoad = 'medium';
182
  update_option('wpstg_settings', $this->settings);
@@ -231,7 +229,6 @@ abstract class Job implements JobInterface
231
 
232
  // Ensure that it is an object
233
  $options = json_decode(json_encode($options));
234
-
235
  return $this->cache->save("clone_options", $options);
236
  }
237
 
@@ -320,8 +317,8 @@ abstract class Job implements JobInterface
320
 
321
  if ($usedMemory >= $this->memoryLimit)
322
  {
323
- $this->log('Used Memory: ' . $this->formatBytes($usedMemory) . ' Memory Limit: ' . $this->formatBytes($this->maxMemoryLimit) . ' Max Script memory limit: ' . $this->formatBytes( $this->memoryLimit ) );
324
- $this->resetMemory();
325
  return true;
326
  }
327
 
@@ -334,7 +331,7 @@ abstract class Job implements JobInterface
334
  // Check if execution time is over threshold
335
  ///$time = round($this->start + $this->time(), 4);
336
  $time = round($this->time() - $this->start, 4);
337
- $this->debugLog( 'Execution time: ' . $time . ' Execution Limit' . $this->executionLimit );
338
  if ($time >= $this->executionLimit)
339
  {
340
  //$this->log('RESET TIME');
@@ -471,4 +468,17 @@ abstract class Job implements JobInterface
471
  }
472
 
473
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
474
  }
97
  //$this->maxExecutionTime = (int) ini_get("max_execution_time");
98
  $this->maxExecutionTime = (int) 30;
99
 
100
+ // if ($this->maxExecutionTime < 1 || $this->maxExecutionTime > 30)
101
  // {
102
  // $this->maxExecutionTime = 30;
103
  // }
 
 
 
 
 
 
104
 
105
  // Services
106
  $this->cache = new Cache(-1, \WPStaging\WPStaging::getContentDir());
109
  // Settings and Options
110
  $this->options = $this->cache->get("clone_options");
111
  //$this->settings = json_decode(json_encode(get_option("wpstg_settings", array())));
112
+ $this->settings = (object) get_option("wpstg_settings", array());
 
 
113
 
114
+ if (!$this->options)
 
115
  {
116
  $this->options = new \stdClass();
117
  }
121
  $this->options->existingClones = json_decode(json_encode($this->options->existingClones), true);
122
  }
123
 
124
+ // check default options
125
+ if ( !isset($this->settings) ||
126
+ !isset($this->settings->queryLimit) ||
127
+ !isset($this->settings->batchSize) ||
128
+ !isset($this->settings->cpuLoad) ||
129
+ !isset($this->settings->fileLimit)
130
+ )
131
+
132
  {
133
  $this->settings = new \stdClass();
134
  $this->setDefaultSettings();
174
  */
175
  protected function setDefaultSettings(){
176
  $this->settings->queryLimit = "1000";
177
+ $this->settings->fileLimit = "10";
178
  $this->settings->batchSize = "2";
179
  $this->settings->cpuLoad = 'medium';
180
  update_option('wpstg_settings', $this->settings);
229
 
230
  // Ensure that it is an object
231
  $options = json_decode(json_encode($options));
 
232
  return $this->cache->save("clone_options", $options);
233
  }
234
 
317
 
318
  if ($usedMemory >= $this->memoryLimit)
319
  {
320
+ $this->log('Used Memory: ' . $this->formatBytes($usedMemory) . ' Memory Limit: ' . $this->formatBytes($this->maxMemoryLimit) . ' Max Script memory limit: ' . $this->formatBytes( $this->memoryLimit ), Logger::TYPE_ERROR );
321
+ //$this->resetMemory();
322
  return true;
323
  }
324
 
331
  // Check if execution time is over threshold
332
  ///$time = round($this->start + $this->time(), 4);
333
  $time = round($this->time() - $this->start, 4);
334
+
335
  if ($time >= $this->executionLimit)
336
  {
337
  //$this->log('RESET TIME');
468
  }
469
 
470
  }
471
+
472
+ /**
473
+ * Throw a errror message via json and stop further execution
474
+ * @param string $message
475
+ */
476
+ protected function returnException($message = ''){
477
+ wp_die( json_encode(array(
478
+ 'job' => $this->options->currentJob,
479
+ 'status' => false,
480
+ 'message' => $message,
481
+ 'error' => true
482
+ )));
483
+ }
484
  }
apps/Backend/Modules/Jobs/JobExecutable.php CHANGED
@@ -1,109 +1,112 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
- }
9
-
10
- /**
11
- * Class JobExecutable
12
- * I'm sorry for such mess, we need to support PHP 5.3
13
- * @package WPStaging\Backend\Modules\Jobs
14
- */
15
- abstract class JobExecutable extends Job
16
- {
17
-
18
- /**
19
- * @var array
20
- */
21
- protected $response = array(
22
- "status" => false,
23
- "percentage" => 0,
24
- "total" => 0,
25
- "step" => 0,
26
- "last_msg" => ''
27
- );
28
-
29
- /**
30
- * JobExecutable constructor.
31
- */
32
- public function __construct()
33
- {
34
- parent::__construct();
35
-
36
- // Calculate total steps
37
- $this->calculateTotalSteps();
38
- }
39
-
40
- /**
41
- * Prepare Response Array
42
- * @param bool $status false when the job is not done
43
- * @param bool $incrementCurrentStep
44
- * @return array
45
- */
46
- protected function prepareResponse($status = false, $incrementCurrentStep = true)
47
- {
48
- if ($incrementCurrentStep)
49
- {
50
- $this->options->currentStep++;
51
- }
52
-
53
- $percentage = round(($this->options->currentStep / $this->options->totalSteps) * 100);
54
- $percentage = (100 < $percentage) ? 100 : $percentage;
55
-
56
- return $this->response = array(
57
- "status" => $status,
58
- "percentage" => $percentage,
59
- "total" => $this->options->totalSteps,
60
- "step" => $this->options->currentStep,
61
- "last_msg" => $this->logger->getLastLogMsg(),
62
- "running_time" => $this->time() - time()
63
- );
64
- }
65
-
66
- /**
67
- * Run Steps
68
- */
69
- protected function run()
70
- {
71
- // Execute steps
72
- for ($i = 0; $i < $this->options->totalSteps; $i++)
73
- {
74
- // Job is finished or over threshold limits was hit
75
- if (!$this->execute())
76
- {
77
- break;
78
- }
79
- }
80
- }
81
-
82
- /**
83
- * Start Module
84
- * @return object
85
- */
86
- public function start()
87
- {
88
- // Execute steps
89
- $this->run();
90
-
91
- // Save option, progress
92
- $this->saveOptions();
93
-
94
- return (object) $this->response;
95
- }
96
-
97
- /**
98
- * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
99
- * @return void
100
- */
101
- abstract protected function calculateTotalSteps();
102
-
103
- /**
104
- * Execute the Current Step
105
- * Returns false when over threshold limits are hit or when the job is done, true otherwise
106
- * @return bool
107
- */
108
- abstract protected function execute();
 
 
 
109
  }
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ // No Direct Access
5
+ if (!defined("WPINC"))
6
+ {
7
+ die;
8
+ }
9
+
10
+
11
+ /**
12
+ * Class JobExecutable
13
+ * I'm sorry for such mess, we need to support PHP 5.3
14
+ * @package WPStaging\Backend\Modules\Jobs
15
+ */
16
+ abstract class JobExecutable extends Job
17
+ {
18
+
19
+ /**
20
+ * @var array
21
+ */
22
+ protected $response = array(
23
+ "status" => false,
24
+ "percentage" => 0,
25
+ "total" => 0,
26
+ "step" => 0,
27
+ "last_msg" => '',
28
+ );
29
+
30
+ /**
31
+ * JobExecutable constructor.
32
+ */
33
+ public function __construct()
34
+ {
35
+ parent::__construct();
36
+
37
+ // Calculate total steps
38
+ $this->calculateTotalSteps();
39
+ }
40
+
41
+ /**
42
+ * Prepare Response Array
43
+ * @param bool $status
44
+ * @param bool $incrementCurrentStep
45
+ * @return array
46
+ */
47
+ protected function prepareResponse($status = false, $incrementCurrentStep = true)
48
+ {
49
+ if ($incrementCurrentStep)
50
+ {
51
+ $this->options->currentStep++;
52
+ }
53
+
54
+ $percentage = round(($this->options->currentStep / $this->options->totalSteps) * 100);
55
+ $percentage = (100 < $percentage) ? 100 : $percentage;
56
+
57
+ return $this->response = array(
58
+ "status" => $status,
59
+ "percentage" => $percentage,
60
+ "total" => $this->options->totalSteps,
61
+ "step" => $this->options->currentStep,
62
+ "job" => $this->options->currentJob,
63
+ "last_msg" => $this->logger->getLastLogMsg(),
64
+ "running_time" => $this->time() - time(),
65
+ "job_done" => $status
66
+ );
67
+ }
68
+
69
+ /**
70
+ * Start Module
71
+ * @return object
72
+ */
73
+ public function start()
74
+ {
75
+ // Execute steps
76
+ $this->run();
77
+
78
+ // Save option, progress
79
+ $this->saveOptions();
80
+
81
+ return (object) $this->response;
82
+ }
83
+
84
+ /**
85
+ * Run Steps
86
+ */
87
+ protected function run()
88
+ {
89
+ // Execute steps
90
+ for ($i = 0; $i < $this->options->totalSteps; $i++)
91
+ {
92
+ // Job is finished or over threshold limits was hit
93
+ if (!$this->execute())
94
+ {
95
+ break;
96
+ }
97
+ }
98
+ }
99
+
100
+ /**
101
+ * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
102
+ * @return void
103
+ */
104
+ abstract protected function calculateTotalSteps();
105
+
106
+ /**
107
+ * Execute the Current Step
108
+ * Returns false when over threshold limits are hit or when the job is done, true otherwise
109
+ * @return bool
110
+ */
111
+ abstract protected function execute();
112
  }
apps/Backend/Modules/Jobs/Scan.php CHANGED
@@ -1,377 +1,400 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules\Jobs;
3
-
4
- // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
- }
9
-
10
- use WPStaging\Utils\Directories;
11
- use WPStaging\WPStaging;
12
-
13
- /**
14
- * Class Scan
15
- * @package WPStaging\Backend\Modules\Jobs
16
- */
17
- class Scan extends Job
18
- {
19
-
20
- /**
21
- * @var array
22
- */
23
- private $directories = array();
24
-
25
- /**
26
- * @var Directories
27
- */
28
- private $objDirectories;
29
-
30
- /**
31
- * Upon class initialization
32
- */
33
- protected function initialize()
34
- {
35
- $this->objDirectories = new Directories();
36
-
37
- // Database Tables
38
- $this->getTables();
39
-
40
- // Get directories
41
- $this->directories();
42
- }
43
-
44
- /**
45
- * Start Module
46
- * @return $this
47
- */
48
- public function start()
49
- {
50
- // Basic Options
51
- $this->options->root = str_replace(array("\\", '/'), DIRECTORY_SEPARATOR, ABSPATH);
52
- $this->options->existingClones = get_option("wpstg_existing_clones_beta", array());
53
- $this->options->current = null;
54
-
55
- if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $this->options->existingClones))
56
- {
57
- $this->options->current = $_POST["clone"];
58
- }
59
-
60
- // Tables
61
- $this->options->excludedTables = array();
62
- $this->options->clonedTables = array();
63
-
64
- // Files
65
- $this->options->totalFiles = 0;
66
- $this->options->copiedFiles = 0;
67
-
68
- // Directories
69
- $this->options->includedDirectories = array();
70
- $this->options->excludedDirectories = array();
71
- $this->options->extraDirectories = array();
72
- $this->options->directoriesToCopy = array();
73
- $this->options->scannedDirectories = array();
74
- //$this->options->lastScannedDirectory = array();
75
-
76
- // Job
77
- $this->options->currentJob = "database";
78
- $this->options->currentStep = 0;
79
- $this->options->totalSteps = 0;
80
-
81
- // Save options
82
- $this->saveOptions();
83
-
84
- return $this;
85
- }
86
-
87
- /**
88
- * Format bytes into human readable form
89
- * @param int $bytes
90
- * @param int $precision
91
- * @return string
92
- */
93
- public function formatSize($bytes, $precision = 2)
94
- {
95
- if ((double) $bytes < 1)
96
- {
97
- return '';
98
- }
99
-
100
- $units = array('B', "KB", "MB", "GB", "TB");
101
-
102
- $bytes = (double) $bytes;
103
- $base = log($bytes) / log(1000); // 1024 would be for MiB KiB etc
104
- $pow = pow(1000, $base - floor($base)); // Same rule for 1000
105
-
106
- return round($pow, $precision) . ' ' . $units[(int) floor($base)];
107
- }
108
-
109
- /**
110
- * @param null|string $directories
111
- * @param bool $forceDisabled
112
- * @return string
113
- */
114
- public function directoryListing($directories = null, $forceDisabled = false)
115
- {
116
- if (null == $directories)
117
- {
118
- $directories = $this->directories;
119
- }
120
-
121
- $output = '';
122
- foreach ($directories as $name => $directory)
123
- {
124
- // Need to preserve keys so no array_shift()
125
- $data = reset($directory);
126
- unset($directory[key($directory)]);
127
-
128
- $isChecked = (
129
- empty($this->options->includedDirectories) ||
130
- in_array($data["path"], $this->options->includedDirectories)
131
- );
132
-
133
- $isDisabled = ($this->options->existingClones && isset($this->options->existingClones[$name]));
134
-
135
- $output .= "<div class='wpstg-dir'>";
136
- $output .= "<input type='checkbox' class='wpstg-check-dir'";
137
-
138
- if ($isChecked && !$isDisabled && !$forceDisabled) $output .= " checked";
139
- if ($forceDisabled || $isDisabled) $output .= " disabled";
140
-
141
- $output .= " name='selectedDirectories[]' value='{$data["path"]}'>";
142
-
143
- $output .= "<a href='#' class='wpstg-expand-dirs";
144
- if (!$isChecked || $isDisabled) $output .= " disabled";
145
- $output .= "'>{$name}";
146
- $output .= "</a>";
147
-
148
- $output .= "<span class='wpstg-size-info'>{$this->formatSize($data["size"])}</span>";
149
-
150
- if (!empty($directory))
151
- {
152
- $output .= "<div class='wpstg-dir wpstg-subdir'>";
153
- $output .= $this->directoryListing($directory, $isDisabled);
154
- $output .= "</div>";
155
- }
156
-
157
- $output .= "</div>";
158
- }
159
-
160
- return $output;
161
- }
162
-
163
- /**
164
- * Checks if there is enough free disk space to create staging site
165
- * Returns null when can't run disk_free_space function one way or another
166
- * @return bool|null
167
- */
168
- public function hasFreeDiskSpace() {
169
- if( !function_exists( "disk_free_space" ) ) {
170
- return null;
171
- }
172
-
173
- $freeSpace = @disk_free_space( ABSPATH );
174
-
175
- if( false === $freeSpace ) {
176
- $data = array(
177
- 'freespace' => false,
178
- 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
179
- );
180
- echo json_encode($data);
181
- die();
182
- }
183
-
184
-
185
- $data = array(
186
- 'freespace' => $this->formatSize($freeSpace),
187
- 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
188
- );
189
-
190
- echo json_encode( $data );
191
- die();
192
- }
193
-
194
- /**
195
- * Get Database Tables
196
- */
197
- protected function getTables()
198
- {
199
- $wpDB = WPStaging::getInstance()->get("wpdb");
200
-
201
- if (strlen($wpDB->prefix) > 0)
202
- {
203
- $sql = "SHOW TABLE STATUS LIKE '{$wpDB->prefix}%'";
204
- }
205
- else
206
- {
207
- $sql = "SHOW TABLE STATUS";
208
- }
209
-
210
- $tables = $wpDB->get_results($sql);
211
-
212
- $currentTables = array();
213
-
214
- foreach ($tables as $table)
215
- {
216
- // Exclude WP Staging Tables
217
- if (0 === strpos($table->Name, "wpstg"))
218
- {
219
- continue;
220
- }
221
-
222
- $currentTables[] = array(
223
- "name" => $table->Name,
224
- "size" => ($table->Data_length + $table->Index_length)
225
- );
226
- }
227
-
228
- $this->options->tables = json_decode(json_encode($currentTables));
229
- }
230
-
231
- /**
232
- * Get directories and main meta data about'em recursively
233
- */
234
- protected function directories()
235
- {
236
- $directories = new \DirectoryIterator(ABSPATH);
237
-
238
- foreach($directories as $directory)
239
- {
240
- // Not a valid directory
241
- if (false === ($path = $this->getPath($directory)))
242
- {
243
- continue;
244
- }
245
-
246
- $this->handleDirectory($path);
247
-
248
- // Get Sub-directories
249
- $this->getSubDirectories($directory->getRealPath());
250
- }
251
-
252
- // Gather Plugins
253
- $this->getSubDirectories(WP_PLUGIN_DIR);
254
-
255
- // Gather Themes
256
- $this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "themes");
257
-
258
- // Gather Uploads
259
- $this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "uploads");
260
- }
261
-
262
- /**
263
- * @param string $path
264
- */
265
- protected function getSubDirectories($path)
266
- {
267
- $directories = new \DirectoryIterator($path);
268
-
269
- foreach($directories as $directory)
270
- {
271
- // Not a valid directory
272
- if (false === ($path = $this->getPath($directory)))
273
- {
274
- continue;
275
- }
276
-
277
- $this->handleDirectory($path);
278
- }
279
- }
280
-
281
- /**
282
- * Get Path from $directory
283
- * @param \SplFileInfo $directory
284
- * @return string|false
285
- */
286
- protected function getPath($directory)
287
- {
288
- /*
289
- * Do not follow root path like src/web/..
290
- * This must be done before \SplFileInfo->isDir() is used!
291
- * Prevents open base dir restriction fatal errors
292
- */
293
- if (strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
294
- return false;
295
- }
296
- $path = str_replace(ABSPATH, null, $directory->getRealPath());
297
-
298
- // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
299
- if (!$directory->isDir() || strlen($path) < 1)
300
- {
301
- return false;
302
- }
303
-
304
- return $path;
305
- }
306
-
307
- /**
308
- * Organizes $this->directories
309
- * @param string $path
310
- */
311
- protected function handleDirectory($path)
312
- {
313
- $directoryArray = explode(DIRECTORY_SEPARATOR, $path);
314
- $total = count($directoryArray);
315
-
316
- if (count($total) < 1)
317
- {
318
- return;
319
- }
320
-
321
- $total = $total - 1;
322
- $currentArray = &$this->directories;
323
-
324
- for ($i = 0; $i <= $total; $i++)
325
- {
326
- if (!isset($currentArray[$directoryArray[$i]]))
327
- {
328
- $currentArray[$directoryArray[$i]] = array();
329
- }
330
-
331
- $currentArray = &$currentArray[$directoryArray[$i]];
332
-
333
- // Attach meta data to the end
334
- if ($i < $total)
335
- {
336
- continue;
337
- }
338
-
339
- $fullPath = ABSPATH . $path;
340
- $size = $this->getDirectorySize($fullPath);
341
-
342
- $currentArray["metaData"] = array(
343
- "size" => $size,
344
- "path" => ABSPATH . $path,
345
- );
346
- }
347
- }
348
-
349
- /**
350
- * Gets size of given directory
351
- * @param string $path
352
- * @return int|null
353
- */
354
- protected function getDirectorySize($path)
355
- {
356
- if (!isset($this->settings->checkDirectorySize) || '1' !== $this->settings->checkDirectorySize)
357
- {
358
- return null;
359
- }
360
-
361
- return $this->objDirectories->size($path);
362
- }
363
-
364
- /**
365
- * Get total size of a directory including all its subdirectories
366
- * @param string $dir
367
- * @return int
368
- */
369
- function getDirectorySizeInclSubdirs( $dir ) {
370
- $size = 0;
371
- foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
372
- $size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
373
- }
374
- return $size;
375
- }
376
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  }
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ // No Direct Access
5
+ if (!defined("WPINC"))
6
+ {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\Utils\Directories;
11
+ use WPStaging\WPStaging;
12
+
13
+ /**
14
+ * Class Scan
15
+ * @package WPStaging\Backend\Modules\Jobs
16
+ */
17
+ class Scan extends Job
18
+ {
19
+
20
+ /**
21
+ * @var array
22
+ */
23
+ private $directories = array();
24
+
25
+ /**
26
+ * @var Directories
27
+ */
28
+ private $objDirectories;
29
+
30
+
31
+ /**
32
+ * Upon class initialization
33
+ */
34
+ protected function initialize()
35
+ {
36
+ $this->objDirectories = new Directories();
37
+
38
+ // Database Tables
39
+ $this->getTables();
40
+
41
+ // Get directories
42
+ $this->directories();
43
+
44
+ $this->db = WPStaging::getInstance()->get('wpdb');
45
+ $this->prefix = $this->db->prefix;
46
+
47
+
48
+ }
49
+
50
+ /**
51
+ * Start Module
52
+ * @return $this
53
+ */
54
+ public function start()
55
+ {
56
+ // Basic Options
57
+ $this->options->root = str_replace(array("\\", '/'), DIRECTORY_SEPARATOR, ABSPATH);
58
+ $this->options->existingClones = get_option("wpstg_existing_clones_beta", array());
59
+ $this->options->current = null;
60
+
61
+ if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $this->options->existingClones))
62
+ {
63
+ $this->options->current = $_POST["clone"];
64
+ }
65
+
66
+ // Tables
67
+ //$this->options->excludedTables = array();
68
+ $this->options->clonedTables = array();
69
+
70
+ // Files
71
+ $this->options->totalFiles = 0;
72
+ $this->options->copiedFiles = 0;
73
+
74
+ // Directories
75
+ $this->options->includedDirectories = array();
76
+ $this->options->excludedDirectories = array();
77
+ $this->options->extraDirectories = array();
78
+ $this->options->directoriesToCopy = array();
79
+ $this->options->scannedDirectories = array();
80
+
81
+ // Job
82
+ $this->options->currentJob = "database";
83
+ $this->options->currentStep = 0;
84
+ $this->options->totalSteps = 0;
85
+
86
+ // Delete previous cached files
87
+ $this->cache->delete("files_to_copy");
88
+ $this->cache->delete("clone_options");
89
+ //$this->cache->delete("files_to_verify");
90
+ //$this->cache->delete("files_verified");
91
+
92
+ // Save options
93
+ $this->saveOptions();
94
+
95
+ return $this;
96
+ }
97
+
98
+ /**
99
+ * Format bytes into human readable form
100
+ * @param int $bytes
101
+ * @param int $precision
102
+ * @return string
103
+ */
104
+ public function formatSize($bytes, $precision = 2)
105
+ {
106
+ if ((double) $bytes < 1)
107
+ {
108
+ return '';
109
+ }
110
+
111
+ $units = array('B', "KB", "MB", "GB", "TB");
112
+
113
+ $bytes = (double) $bytes;
114
+ $base = log($bytes) / log(1000); // 1024 would be for MiB KiB etc
115
+ $pow = pow(1000, $base - floor($base)); // Same rule for 1000
116
+
117
+ return round($pow, $precision) . ' ' . $units[(int) floor($base)];
118
+ }
119
+
120
+ /**
121
+ * @param null|string $directories
122
+ * @param bool $forceDisabled
123
+ * @return string
124
+ */
125
+ public function directoryListing($directories = null, $forceDisabled = false)
126
+ {
127
+ if (null == $directories)
128
+ {
129
+ $directories = $this->directories;
130
+ }
131
+
132
+ $output = '';
133
+ foreach ($directories as $name => $directory)
134
+ {
135
+ // Need to preserve keys so no array_shift()
136
+ $data = reset($directory);
137
+ unset($directory[key($directory)]);
138
+
139
+ $isChecked = (
140
+ empty($this->options->includedDirectories) ||
141
+ in_array($data["path"], $this->options->includedDirectories)
142
+ );
143
+
144
+ $isDisabled = ($this->options->existingClones && isset($this->options->existingClones[$name]));
145
+
146
+ $output .= "<div class='wpstg-dir'>";
147
+ $output .= "<input type='checkbox' class='wpstg-check-dir'";
148
+
149
+ if ($isChecked && !$isDisabled && !$forceDisabled) $output .= " checked";
150
+ if ($forceDisabled || $isDisabled) $output .= " disabled";
151
+
152
+ $output .= " name='selectedDirectories[]' value='{$data["path"]}'>";
153
+
154
+ $output .= "<a href='#' class='wpstg-expand-dirs";
155
+ if (!$isChecked || $isDisabled) $output .= " disabled";
156
+ $output .= "'>{$name}";
157
+ $output .= "</a>";
158
+
159
+ $output .= "<span class='wpstg-size-info'>{$this->formatSize($data["size"])}</span>";
160
+
161
+ if (!empty($directory))
162
+ {
163
+ $output .= "<div class='wpstg-dir wpstg-subdir'>";
164
+ $output .= $this->directoryListing($directory, $isDisabled);
165
+ $output .= "</div>";
166
+ }
167
+
168
+ $output .= "</div>";
169
+ }
170
+
171
+ return $output;
172
+ }
173
+
174
+ /**
175
+ * Checks if there is enough free disk space to create staging site
176
+ * Returns null when can't run disk_free_space function one way or another
177
+ * @return bool|null
178
+ */
179
+ public function hasFreeDiskSpace() {
180
+ if( !function_exists( "disk_free_space" ) ) {
181
+ return null;
182
+ }
183
+
184
+ $freeSpace = @disk_free_space( ABSPATH );
185
+
186
+ if( false === $freeSpace ) {
187
+ $data = array(
188
+ 'freespace' => false,
189
+ 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
190
+ );
191
+ echo json_encode($data);
192
+ die();
193
+ }
194
+
195
+
196
+ $data = array(
197
+ 'freespace' => $this->formatSize($freeSpace),
198
+ 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
199
+ );
200
+
201
+ echo json_encode( $data );
202
+ die();
203
+ }
204
+
205
+ /**
206
+ * Get Database Tables
207
+ */
208
+ protected function getTables()
209
+ {
210
+ $wpDB = WPStaging::getInstance()->get("wpdb");
211
+
212
+ if (strlen($wpDB->prefix) > 0)
213
+ {
214
+ $prefix = str_replace('_', '', $wpDB->prefix);
215
+ //$sql = "SHOW TABLE STATUS LIKE '{$prefix}\%'";
216
+ $sql = "SHOW TABLE STATUS LIKE '{$wpDB->prefix}%'";
217
+ }
218
+ else
219
+ {
220
+ $sql = "SHOW TABLE STATUS";
221
+ }
222
+
223
+ $tables = $wpDB->get_results($sql);
224
+
225
+ $currentTables = array();
226
+
227
+ // Reset excluded Tables than loop through all tables
228
+ $this->options->excludedTables = array();
229
+ foreach ($tables as $table)
230
+ {
231
+
232
+ // Exclude WP Staging Tables
233
+ // if (0 === strpos($table->Name, "wpstg"))
234
+ // {
235
+ // continue;
236
+ // }
237
+ // Create array of unchecked tables
238
+ if (0 !== strpos($table->Name, $wpDB->prefix))
239
+ {
240
+ $this->options->excludedTables[] = $table->Name;
241
+ }
242
+
243
+
244
+ $currentTables[] = array(
245
+ "name" => $table->Name,
246
+ "size" => ($table->Data_length + $table->Index_length)
247
+ );
248
+ }
249
+
250
+ $this->options->tables = json_decode(json_encode($currentTables));
251
+ }
252
+
253
+ /**
254
+ * Get directories and main meta data about'em recursively
255
+ */
256
+ protected function directories()
257
+ {
258
+ $directories = new \DirectoryIterator(ABSPATH);
259
+
260
+ foreach($directories as $directory)
261
+ {
262
+ // Not a valid directory
263
+ if (false === ($path = $this->getPath($directory)))
264
+ {
265
+ continue;
266
+ }
267
+
268
+ $this->handleDirectory($path);
269
+
270
+ // Get Sub-directories
271
+ $this->getSubDirectories($directory->getRealPath());
272
+ }
273
+
274
+ // Gather Plugins
275
+ $this->getSubDirectories(WP_PLUGIN_DIR);
276
+
277
+ // Gather Themes
278
+ $this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "themes");
279
+
280
+ // Gather Uploads
281
+ $this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "uploads");
282
+ }
283
+
284
+ /**
285
+ * @param string $path
286
+ */
287
+ protected function getSubDirectories($path)
288
+ {
289
+ $directories = new \DirectoryIterator($path);
290
+
291
+ foreach($directories as $directory)
292
+ {
293
+ // Not a valid directory
294
+ if (false === ($path = $this->getPath($directory)))
295
+ {
296
+ continue;
297
+ }
298
+
299
+ $this->handleDirectory($path);
300
+ }
301
+ }
302
+
303
+ /**
304
+ * Get Path from $directory
305
+ * @param \SplFileInfo $directory
306
+ * @return string|false
307
+ */
308
+ protected function getPath($directory)
309
+ {
310
+
311
+ /*
312
+ * Do not follow root path like src/web/..
313
+ * This must be done before \SplFileInfo->isDir() is used!
314
+ * Prevents open base dir restriction fatal errors
315
+ */
316
+ if (strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
317
+ return false;
318
+ }
319
+ $path = str_replace(ABSPATH, null, $directory->getRealPath());
320
+
321
+ // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
322
+ if (!$directory->isDir() || strlen($path) < 1)
323
+ {
324
+ return false;
325
+ }
326
+
327
+ return $path;
328
+ }
329
+
330
+ /**
331
+ * Organizes $this->directories
332
+ * @param string $path
333
+ */
334
+ protected function handleDirectory($path)
335
+ {
336
+ $directoryArray = explode(DIRECTORY_SEPARATOR, $path);
337
+ $total = count($directoryArray);
338
+
339
+ if (count($total) < 1)
340
+ {
341
+ return;
342
+ }
343
+
344
+ $total = $total - 1;
345
+ $currentArray = &$this->directories;
346
+
347
+ for ($i = 0; $i <= $total; $i++)
348
+ {
349
+ if (!isset($currentArray[$directoryArray[$i]]))
350
+ {
351
+ $currentArray[$directoryArray[$i]] = array();
352
+ }
353
+
354
+ $currentArray = &$currentArray[$directoryArray[$i]];
355
+
356
+ // Attach meta data to the end
357
+ if ($i < $total)
358
+ {
359
+ continue;
360
+ }
361
+
362
+ $fullPath = ABSPATH . $path;
363
+ $size = $this->getDirectorySize($fullPath);
364
+
365
+ $currentArray["metaData"] = array(
366
+ "size" => $size,
367
+ "path" => ABSPATH . $path,
368
+ );
369
+ }
370
+ }
371
+
372
+ /**
373
+ * Gets size of given directory
374
+ * @param string $path
375
+ * @return int|null
376
+ */
377
+ protected function getDirectorySize($path)
378
+ {
379
+ if (!isset($this->settings->checkDirectorySize) || '1' !== $this->settings->checkDirectorySize)
380
+ {
381
+ return null;
382
+ }
383
+
384
+ return $this->objDirectories->size($path);
385
+ }
386
+
387
+ /**
388
+ * Get total size of a directory including all its subdirectories
389
+ * @param string $dir
390
+ * @return int
391
+ */
392
+ function getDirectorySizeInclSubdirs( $dir ) {
393
+ $size = 0;
394
+ foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
395
+ $size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
396
+ }
397
+ return $size;
398
+ }
399
+
400
  }
apps/Backend/Modules/Jobs/Updating.php ADDED
@@ -0,0 +1,262 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
+ use WPStaging\WPStaging;
6
+
7
+ /**
8
+ * Class Cloning
9
+ * @package WPStaging\Backend\Modules\Jobs
10
+ */
11
+ class Updating extends Job
12
+ {
13
+ /**
14
+ * Initialize is called in \Job
15
+ */
16
+ public function initialize(){
17
+ $this->db = WPStaging::getInstance()->get("wpdb");
18
+ }
19
+
20
+ /**
21
+ * Save Chosen Cloning Settings
22
+ * @return bool
23
+ */
24
+ public function save()
25
+ {
26
+ if (!isset($_POST) || !isset($_POST["cloneID"]))
27
+ {
28
+ return false;
29
+ }
30
+
31
+ // Generate Options
32
+ // Clone
33
+ $this->options->clone = $_POST["cloneID"];
34
+ $this->options->cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($this->options->clone));
35
+ $this->options->cloneNumber = 1;
36
+ $this->options->includedDirectories = array();
37
+ $this->options->excludedDirectories = array();
38
+ $this->options->extraDirectories = array();
39
+ $this->options->excludedFiles = array('.htaccess', '.DS_Store', '.git', '.svn', '.tmp', 'desktop.ini', '.gitignore', '.log');
40
+
41
+ // Job
42
+ $this->options->job = new \stdClass();
43
+
44
+ // Check if clone data already exists and use that one
45
+ if (isset($this->options->existingClones[$this->options->clone]) )
46
+ {
47
+ $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]['number'];
48
+ $this->options->prefix = $this->getStagingPrefix();
49
+ } else {
50
+ wp_die('Fatal Error: Can not update clone because there is no clone data.');
51
+ }
52
+
53
+
54
+ // Excluded Tables
55
+ if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
56
+ {
57
+ $this->options->excludedTables = $_POST["excludedTables"];
58
+ }
59
+
60
+ // Excluded Directories
61
+ if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"]))
62
+ {
63
+ $this->options->excludedDirectories = $_POST["excludedDirectories"];
64
+ }
65
+
66
+ // Excluded Directories TOTAL
67
+ // Do not copy these folders and plugins
68
+ $excludedDirectories = array(
69
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
70
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login'
71
+ );
72
+
73
+ $this->options->excludedDirectories = array_merge($excludedDirectories, $this->options->excludedDirectories);
74
+
75
+ // Included Directories
76
+ if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"]))
77
+ {
78
+ $this->options->includedDirectories = $_POST["includedDirectories"];
79
+ }
80
+
81
+ // Extra Directories
82
+ if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"]) )
83
+ {
84
+ $this->options->extraDirectories = $_POST["extraDirectories"];
85
+ }
86
+
87
+ // Directories to Copy
88
+ $this->options->directoriesToCopy = array_merge(
89
+ $this->options->includedDirectories,
90
+ $this->options->extraDirectories
91
+ );
92
+
93
+ array_unshift($this->options->directoriesToCopy, ABSPATH);
94
+
95
+ // Delete files to copy listing
96
+ $this->cache->delete("files_to_copy");
97
+
98
+ return $this->saveOptions();
99
+ }
100
+
101
+ /**
102
+ * Check and return prefix of the staging site
103
+ */
104
+
105
+
106
+ // public function getStagingPrefix_old(){
107
+ // $prefix = !empty($this->options->existingClones[$this->options->clone]['prefix']) ?
108
+ // $this->options->existingClones[$this->options->clone]['prefix'] :
109
+ // false;
110
+ //
111
+ // if(!$prefix){
112
+ // $this->returnException("Fatal Error: Can not update staging site. Can not find Prefix. '{$prefix}'. Stopping for security reasons. Creating a new staging site will likely resolve this the next time. Contact support@wp-staging.com");
113
+ // wp_die("Fatal Error: Can not update staging site. Can not find Prefix. '{$prefix}'. Stopping for security reasons. Creating a new staging site will likely resolve this the next time. Contact support@wp-staging.com");
114
+ // }
115
+ //
116
+ // if ($this->options->existingClones[$this->options->clone]['prefix'] == $this->db->prefix){
117
+ // $this->returnException("Fatal Error: Can not update staging site. Prefix. '{$prefix}' is used for the live site. Creating a new staging site will likely resolve this the next time. Stopping for security reasons. Contact support@wp-staging.com");
118
+ // wp_die("Fatal Error: Can not update staging site. Prefix. '{$prefix}' is used for the live site. Creating a new staging site will likely resolve this the next time. Stopping for security reasons. Contact support@wp-staging.com");
119
+ // }
120
+ //
121
+ // return $prefix;
122
+ // }
123
+
124
+ /**
125
+ * Check and return prefix of the staging site
126
+ */
127
+ public function getStagingPrefix() {
128
+ // prefix not defined! Happens if staging site has ben generated with older version of wpstg
129
+ // Try to get staging prefix from wp-config.php of staging site
130
+ $this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
131
+ //wp_die($this->options->prefix);
132
+ if (empty($this->options->prefix)) {
133
+ // Throw error if wp-config.php is not readable
134
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
135
+ //wp_die($path);
136
+ if (false === ($content = @file_get_contents($path))) {
137
+ $this->log("Can not open {$path}. Can't read contents", Logger::TYPE_ERROR);
138
+ $this->returnException("Fatal Error: Can not read {$path} to get correct table prefix. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
139
+ wp_die("Fatal Error: Can not read {$path} to get correct table prefix. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
140
+ } else {
141
+ // Get prefix from wp-config.php
142
+ preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
143
+ //wp_die(var_dump($matches));
144
+
145
+ if (!empty($matches[1])) {
146
+ $this->options->prefix = $matches[1];
147
+ } else {
148
+ $this->returnException("Fatal Error: Can not detect prefix from {$path}. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
149
+ wp_die("Fatal Error: Can not detect prefix from {$path}. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
150
+ }
151
+ }
152
+ }
153
+
154
+ // Die() if staging prefix is the same as the live prefix
155
+ if ($this->db->prefix == $this->options->prefix) {
156
+ $this->log("Fatal Error: Can not updatte staging site. Prefix. '{$this->options->prefix}' is used for the live site. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
157
+ wp_die("Fatal Error: Can not update staging site. Prefix. '{$this->options->prefix}' is used for the live site. Stopping for security reasons. Deleting this staging site and creating a new one could fix this issue. Otherwise contact us support@wp-staging.com");
158
+ }
159
+
160
+ // Else
161
+ //$this->returnException($this->options->prefix);
162
+ //wp_die($this->options->prefix);
163
+ return $this->options->prefix;
164
+ }
165
+
166
+ /**
167
+ * Start the cloning job
168
+ */
169
+ public function start()
170
+ {
171
+ if (null === $this->options->currentJob)
172
+ {
173
+ $this->log("Cloning job for {$this->options->clone} finished");
174
+ return true;
175
+ }
176
+
177
+ $methodName = "job" . ucwords($this->options->currentJob);
178
+
179
+ if (!method_exists($this, $methodName))
180
+ {
181
+ $this->log("Can't execute job; Job's method {$methodName} is not found");
182
+ throw new JobNotFoundException($methodName);
183
+ }
184
+
185
+ // Call the job
186
+ //$this->log("execute job: Job's method {$methodName}");
187
+ return $this->{$methodName}();
188
+ }
189
+
190
+ /**
191
+ * @param object $response
192
+ * @param string $nextJob
193
+ * @return object
194
+ */
195
+ private function handleJobResponse($response, $nextJob)
196
+ {
197
+ // Job is not done
198
+ if (true !== $response->status)
199
+ {
200
+ return $response;
201
+ }
202
+
203
+ $this->options->currentJob = $nextJob;
204
+ $this->options->currentStep = 0;
205
+ $this->options->totalSteps = 0;
206
+
207
+ // Save options
208
+ $this->saveOptions();
209
+
210
+ return $response;
211
+ }
212
+
213
+ /**
214
+ * Clone Database
215
+ * @return object
216
+ */
217
+ public function jobDatabase()
218
+ {
219
+ $database = new Database();
220
+ return $this->handleJobResponse($database->start(), "directories");
221
+ }
222
+
223
+ /**
224
+ * Get All Files From Selected Directories Recursively Into a File
225
+ * @return object
226
+ */
227
+ public function jobDirectories()
228
+ {
229
+ $directories = new Directories();
230
+ return $this->handleJobResponse($directories->start(), "files");
231
+ }
232
+
233
+ /**
234
+ * Copy Files
235
+ * @return object
236
+ */
237
+ public function jobFiles()
238
+ {
239
+ $files = new Files();
240
+ return $this->handleJobResponse($files->start(), "data");
241
+ }
242
+
243
+ /**
244
+ * Replace Data
245
+ * @return object
246
+ */
247
+ public function jobData()
248
+ {
249
+ $data = new Data();
250
+ return $this->handleJobResponse($data->start(), "finish");
251
+ }
252
+
253
+ /**
254
+ * Save Clone Data
255
+ * @return object
256
+ */
257
+ public function jobFinish()
258
+ {
259
+ $finish = new Finish();
260
+ return $this->handleJobResponse($finish->start(), '');
261
+ }
262
+ }
apps/Backend/Modules/SystemInfo.php CHANGED
@@ -1,481 +1,513 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules;
3
-
4
- use WPStaging\DI\InjectionAware;
5
- use WPStaging\Library\Browser;
6
- use WPStaging\WPStaging;
7
-
8
- // No Direct Access
9
- if (!defined("WPINC"))
10
- {
11
- die;
12
- }
13
-
14
- /**
15
- * Class SystemInfo
16
- * @package WPStaging\Backend\Modules
17
- */
18
- class SystemInfo extends InjectionAware
19
- {
20
-
21
- /**
22
- * @var bool
23
- */
24
- private $isMultiSite;
25
-
26
-
27
- /**
28
- * Initialize class
29
- */
30
- public function initialize()
31
- {
32
- $this->isMultiSite = is_multisite();
33
- }
34
-
35
- /**
36
- * Magic method
37
- * @return string
38
- */
39
- public function __toString()
40
- {
41
- return $this->get();
42
- }
43
-
44
- /**
45
- * Get System Information as text
46
- * @return string
47
- */
48
- public function get()
49
- {
50
- $output = "### Begin System Info ###" . PHP_EOL . PHP_EOL;
51
-
52
- $output .= $this->wpstaging();
53
-
54
- $output .= $this->site();
55
-
56
- $output .= $this->browser();
57
-
58
- $output .= $this->wp();
59
-
60
- $output .= $this->plugins();
61
-
62
- $output .= $this->multiSitePlugins();
63
-
64
- $output .= $this->server();
65
-
66
- $output .= $this->php();
67
-
68
- $output .= $this->phpExtensions();
69
-
70
- $output .= PHP_EOL . "### End System Info ###";
71
-
72
- return $output;
73
- }
74
-
75
-
76
-
77
- /**
78
- * @param string $string
79
- * @return string
80
- */
81
- public function header($string)
82
- {
83
- return PHP_EOL . "-- {$string}" . PHP_EOL . PHP_EOL;
84
- }
85
-
86
- /**
87
- * Formating title and the value
88
- * @param string $title
89
- * @param string $value
90
- * @return string
91
- */
92
- public function info($title, $value)
93
- {
94
- return str_pad($title, 56, ' ', STR_PAD_RIGHT) . $value . PHP_EOL;
95
- }
96
-
97
- /**
98
- * Theme Information
99
- * @return string
100
- */
101
- public function theme()
102
- {
103
- // Versions earlier than 3.4
104
- if (get_bloginfo("version") < "3.4" )
105
- {
106
- $themeData = get_theme_data(get_stylesheet_directory() . "/style.css");
107
- return "{$themeData["Name"]} {$themeData["Version"]}";
108
- }
109
-
110
- $themeData = wp_get_theme();
111
- return "{$themeData->Name} {$themeData->Version}";
112
- }
113
-
114
- /**
115
- * Site Information
116
- * @return string
117
- */
118
- public function site()
119
- {
120
- $output = "-- Site Info" . PHP_EOL . PHP_EOL;
121
- $output .= $this->info("Site URL:", site_url());
122
- $output .= $this->info("Home URL:", home_url());
123
- $output .= $this->info("Home Path:", get_home_path());
124
- $output .= $this->info("Installed in subdir:", ( $this->isSubDir() ? 'Yes' : 'No' )) ;
125
- $output .= $this->info("Multisite:", ($this->isMultiSite ? "Yes" : "No" ));
126
-
127
- return apply_filters("wpstg_sysinfo_after_site_info", $output);
128
- }
129
-
130
- /**
131
- * Wp Staging plugin Information
132
- * @return string
133
- */
134
- public function wpstaging() {
135
- // Get wpstg settings
136
- $settings = ( object ) get_option( 'wpstg_settings', array() );
137
-
138
- // Clones data < 1.6.x
139
- $clones = ( object ) get_option( 'wpstg_existing_clones', array() );
140
- // Clones data version > 2.x
141
- $clonesBeta = get_option( 'wpstg_existing_clones_beta' );
142
-
143
-
144
- $output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
145
- $output .= $this->info( "Query Limit:", isset( $settings->queryLimit ) ? $settings->queryLimit : 'undefined' );
146
- $output .= $this->info( "File Copy Limit:", isset( $settings->fileLimit ) ? $settings->fileLimit : 'undefined' );
147
- $output .= $this->info( "Batch Size:", isset( $settings->batchSize ) ? $settings->batchSize : 'undefined' );
148
- $output .= $this->info( "CPU Load:", isset( $settings->cpuLoad ) ? $settings->cpuLoad : 'undefined' );
149
- $output .= $this->info( "WP in Subdir:", isset( $settings->wpSubDirectory ) ? $settings->wpSubDirectory : 'false' );
150
-
151
- $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.6.x" . PHP_EOL . PHP_EOL;
152
-
153
- $i = 1;
154
- foreach ( $clones as $key => $value ) {
155
- $output .= $this->info( "Site name & subfolder :", $value );
156
- }
157
- $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version > 2.0.x" . PHP_EOL . PHP_EOL;
158
-
159
- foreach ( $clonesBeta as $key => $clone ) {
160
- $output .= $this->info( "Number:", isset( $clone['number'] ) ? $clone['number'] : 'undefined' );
161
- $output .= $this->info( "directoryName:", isset( $clone['directoryName'] ) ? $clone['directoryName'] : 'undefined' );
162
- $output .= $this->info( "Path:", isset( $clone['path'] ) ? $clone['path'] : 'undefined' );
163
- $output .= $this->info( "URL:", isset( $clone['url'] ) ? $clone['url'] : 'undefined' );
164
- $output .= $this->info( "Version:", isset( $clone['version'] ) ? $clone['version'] : 'undefined' ) . PHP_EOL . PHP_EOL;
165
- }
166
-
167
- //$output .= PHP_EOL . PHP_EOL;
168
-
169
- $output .= $this->info( "Plugin Version:", get_option('wpstg_version', 'undefined') );
170
- $output .= $this->info( "Install Date:", get_option('wpstg_installDate', 'undefined') );
171
- $output .= $this->info( "Upgraded from:", get_option('wpstg_version_upgraded_from', 'undefined') );
172
- $output .= $this->info( "Is Staging Site:", get_option('wpstg_is_staging_site', 'undefined') ) . PHP_EOL . PHP_EOL;
173
-
174
-
175
- return apply_filters( "wpstg_sysinfo_after_wpstaging_info", $output );
176
- }
177
-
178
- /**
179
- * Browser Information
180
- * @return string
181
- */
182
- public function browser()
183
- {
184
- $output = $this->header("User Browser");
185
- $output .= (new Browser);
186
-
187
- return apply_filters("wpstg_sysinfo_after_user_browser", $output);
188
- }
189
-
190
- /**
191
- * Frontpage Information when frontpage is set to "page"
192
- * @return string
193
- */
194
- public function frontPage()
195
- {
196
- if (get_option("show_on_front") !== "page")
197
- {
198
- return '';
199
- }
200
-
201
- $frontPageID = get_option("page_on_front");
202
- $blogPageID = get_option("page_for_posts");
203
-
204
- // Front Page
205
- $pageFront = ($frontPageID != 0) ? get_the_title($frontPageID) . " (#{$frontPageID})" : "Unset";
206
- // Blog Page ID
207
- $pageBlog = ($blogPageID != 0) ? get_the_title($blogPageID) . " (#{$blogPageID})" : "Unset";
208
-
209
- $output = $this->info("Page On Front:", $pageFront);
210
- $output .= $this->info("Page For Posts:", $pageBlog);
211
-
212
- return $output;
213
- }
214
-
215
- /**
216
- * Check wp_remote_post() functionality
217
- * @return string
218
- */
219
- public function wpRemotePost()
220
- {
221
- // Make sure wp_remote_post() is working
222
- $wpRemotePost = "wp_remote_post() does not work";
223
-
224
- // Send request
225
- $response = wp_remote_post(
226
- "https://www.paypal.com/cgi-bin/webscr",
227
- array(
228
- "sslverify" => false,
229
- "timeout" => 60,
230
- "user-agent" => "WPSTG/" . WPStaging::VERSION,
231
- "body" => array("cmd" => "_notify-validate")
232
- )
233
- );
234
-
235
- // Validate it worked
236
- if (!is_wp_error($response) && 200 <= $response["response"]["code"] && 300> $response["response"]["code"])
237
- {
238
- $wpRemotePost = "wp_remote_post() works";
239
- }
240
-
241
- return $this->info("Remote Post:", $wpRemotePost);
242
- }
243
-
244
- /**
245
- * WordPress Configuration
246
- * @return string
247
- */
248
- public function wp()
249
- {
250
- $output = $this->header("WordPress Configuration");
251
- $output .= $this->info("Version:", get_bloginfo("version"));
252
- $output .= $this->info("Language:", (defined("WPLANG") && WPLANG) ? WPLANG : "en_US");
253
-
254
- $permalinkStructure = get_option("permalink_structure");;
255
- $output .= $this->info("Permalink Structure:", ($permalinkStructure) ? $permalinkStructure : "Default");
256
-
257
- $output .= $this->info("Active Theme:", $this->theme());
258
- $output .= $this->info("Show On Front:", get_option("show_on_front"));
259
-
260
- // Frontpage information
261
- $output .= $this->frontPage();
262
-
263
- // WP Remote Post
264
- $output .= $this->wpRemotePost();
265
-
266
- // Table Prefix
267
- $wpDB = $this->di->get("wpdb");
268
- $tablePrefix = "Length: " . strlen($wpDB->prefix) . " Status: ";
269
- $tablePrefix .= (strlen($wpDB->prefix) > 16) ? "ERROR: Too long" : "Acceptable";
270
-
271
- $output .= $this->info("Table Prefix:", $tablePrefix);
272
-
273
- // WP Debug
274
- $output .= $this->info("WP_DEBUG:", (defined("WP_DEBUG")) ? WP_DEBUG ? "Enabled" : "Disabled" : "Not set");
275
- $output .= $this->info("Memory Limit:", WP_MEMORY_LIMIT);
276
- $output .= $this->info("Registered Post Stati:", implode(", ", \get_post_stati()));
277
-
278
- return apply_filters("wpstg_sysinfo_after_wpstg_config", $output);
279
- }
280
-
281
- /**
282
- * List of Active Plugins
283
- * @param array $plugins
284
- * @param array $activePlugins
285
- * @return string
286
- */
287
- public function activePlugins($plugins, $activePlugins)
288
- {
289
- $output = $this->header("WordPress Active Plugins");
290
-
291
- foreach ($plugins as $path => $plugin)
292
- {
293
- if (!in_array($path, $activePlugins))
294
- {
295
- continue;
296
- }
297
-
298
- $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
299
- }
300
-
301
- return apply_filters("wpstg_sysinfo_after_wordpress_plugins", $output);
302
- }
303
-
304
- /**
305
- * List of Inactive Plugins
306
- * @param array $plugins
307
- * @param array $activePlugins
308
- * @return string
309
- */
310
- public function inactivePlugins($plugins, $activePlugins)
311
- {
312
- $output = $this->header("WordPress Inactive Plugins");
313
-
314
- foreach ($plugins as $path => $plugin)
315
- {
316
- if (in_array($path, $activePlugins))
317
- {
318
- continue;
319
- }
320
-
321
- $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
322
- }
323
-
324
- return apply_filters("wpstg_sysinfo_after_wordpress_plugins_inactive", $output);
325
- }
326
-
327
- /**
328
- * Get list of active and inactive plugins
329
- * @return string
330
- */
331
- public function plugins()
332
- {
333
- // Get plugins and active plugins
334
- $plugins = get_plugins();
335
- $activePlugins = get_option("active_plugins", array());
336
-
337
- // Active plugins
338
- $output = $this->activePlugins($plugins, $activePlugins);
339
- $output .= $this->inactivePlugins($plugins, $activePlugins);
340
-
341
- return $output;
342
- }
343
-
344
- /**
345
- * Multisite Plugins
346
- * @return string
347
- */
348
- public function multiSitePlugins()
349
- {
350
- if (!$this->isMultiSite)
351
- {
352
- return '';
353
- }
354
-
355
- $output = $this->header("Network Active Plugins");
356
-
357
- $plugins = wp_get_active_network_plugins();
358
- $activePlugins = get_site_option("active_sitewide_plugins", array());
359
-
360
- foreach ($plugins as $pluginPath)
361
- {
362
- $pluginBase = plugin_basename($pluginPath);
363
-
364
- if (!array_key_exists($pluginBase, $activePlugins))
365
- {
366
- continue;
367
- }
368
-
369
- $plugin = get_plugin_data($pluginPath);
370
-
371
- $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
372
- }
373
- unset($plugins, $activePlugins);
374
-
375
- return $output;
376
- }
377
-
378
- /**
379
- * Server Information
380
- * @return string
381
- */
382
- public function server()
383
- {
384
- // Server Configuration
385
- $output = $this->header("Webserver Configuration");
386
-
387
- $output .= $this->info("PHP Version:", PHP_VERSION);
388
- $output .= $this->info("MySQL Version:", $this->di->get("wpdb")->db_version());
389
- $output .= $this->info("Webserver Info:", $_SERVER["SERVER_SOFTWARE"]);
390
-
391
- return apply_filters("wpstg_sysinfo_after_webserver_config", $output);
392
- }
393
-
394
- /**
395
- * PHP Configuration
396
- * @return string
397
- */
398
- public function php()
399
- {
400
- $output = $this->header("PHP Configuration");
401
- $output .= $this->info("Safe Mode:", ($this->isSafeModeEnabled() ? "Enabled" : "Disabled"));
402
- $output .= $this->info("Memory Limit:", ini_get("memory_limit"));
403
- $output .= $this->info("Upload Max Size:", ini_get("upload_max_filesize"));
404
- $output .= $this->info("Post Max Size:", ini_get("post_max_size"));
405
- $output .= $this->info("Upload Max Filesize:", ini_get("upload_max_filesize"));
406
- $output .= $this->info("Time Limit:", ini_get("max_execution_time"));
407
- $output .= $this->info("Max Input Vars:", ini_get("max_input_vars"));
408
-
409
- $displayErrors = ini_get("display_errors");
410
- $output .= $this->info("Display Errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A");
411
-
412
- return apply_filters("wpstg_sysinfo_after_php_config", $output);
413
- }
414
-
415
- /**
416
- * Check if PHP is on Safe Mode
417
- * @return bool
418
- */
419
- public function isSafeModeEnabled()
420
- {
421
- return (
422
- version_compare(PHP_VERSION, "5.4.0", '<') &&
423
- @ini_get("safe_mode")
424
- );
425
- }
426
-
427
- /**
428
- * Checks if function exists or not
429
- * @param string $functionName
430
- * @return string
431
- */
432
- public function isSupported($functionName)
433
- {
434
- return (function_exists($functionName)) ? "Supported" : "Not Supported";
435
- }
436
-
437
- /**
438
- * Checks if class or extension is loaded / exists to determine if it is installed or not
439
- * @param string $name
440
- * @param bool $isClass
441
- * @return string
442
- */
443
- public function isInstalled($name, $isClass = true)
444
- {
445
- if (true === $isClass)
446
- {
447
- return (class_exists($name)) ? "Installed" : "Not Installed";
448
- }
449
- else
450
- {
451
- return (extension_loaded($name)) ? "Installed" : "Not Installed";
452
- }
453
- }
454
-
455
- /**
456
- * Gets Installed Important PHP Extensions
457
- * @return string
458
- */
459
- public function phpExtensions()
460
- {
461
- // Important PHP Extensions
462
- $output = $this->header("PHP Extensions");
463
- $output .= $this->info("cURL:", $this->isSupported("curl_init"));
464
- $output .= $this->info("fsockopen:", $this->isSupported("fsockopen"));
465
- $output .= $this->info("SOAP Client:", $this->isInstalled("SoapClient"));
466
- $output .= $this->info("Suhosin:", $this->isInstalled("suhosin", false));
467
-
468
- return apply_filters("wpstg_sysinfo_after_php_ext", $output);
469
- }
470
-
471
- /**
472
- * Check if WP is installed in subdir
473
- * @return boolean
474
- */
475
- private function isSubDir(){
476
- if ( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
477
- return true;
478
- }
479
- return false;
480
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
481
  }
1
+ <?php
2
+ namespace WPStaging\Backend\Modules;
3
+
4
+ use WPStaging\DI\InjectionAware;
5
+ use WPStaging\Library\Browser;
6
+ use WPStaging\WPStaging;
7
+
8
+ // No Direct Access
9
+ if (!defined("WPINC"))
10
+ {
11
+ die;
12
+ }
13
+
14
+ /**
15
+ * Class SystemInfo
16
+ * @package WPStaging\Backend\Modules
17
+ */
18
+ class SystemInfo extends InjectionAware
19
+ {
20
+
21
+ /**
22
+ * @var bool
23
+ */
24
+ private $isMultiSite;
25
+
26
+
27
+ /**
28
+ * Initialize class
29
+ */
30
+ public function initialize()
31
+ {
32
+ $this->isMultiSite = is_multisite();
33
+ }
34
+
35
+ /**
36
+ * Magic method
37
+ * @return string
38
+ */
39
+ public function __toString()
40
+ {
41
+ return $this->get();
42
+ }
43
+
44
+ /**
45
+ * Get System Information as text
46
+ * @return string
47
+ */
48
+ public function get()
49
+ {
50
+ $output = "### Begin System Info ###" . PHP_EOL . PHP_EOL;
51
+
52
+ $output .= $this->wpstaging();
53
+
54
+ $output .= $this->site();
55
+
56
+ $output .= $this->browser();
57
+
58
+ $output .= $this->wp();
59
+
60
+ $output .= $this->plugins();
61
+
62
+ $output .= $this->multiSitePlugins();
63
+
64
+ $output .= $this->server();
65
+
66
+ $output .= $this->php();
67
+
68
+ $output .= $this->phpExtensions();
69
+
70
+ $output .= PHP_EOL . "### End System Info ###";
71
+
72
+ return $output;
73
+ }
74
+
75
+
76
+
77
+ /**
78
+ * @param string $string
79
+ * @return string
80
+ */
81
+ public function header($string)
82
+ {
83
+ return PHP_EOL . "-- {$string}" . PHP_EOL . PHP_EOL;
84
+ }
85
+
86
+ /**
87
+ * Formating title and the value
88
+ * @param string $title
89
+ * @param string $value
90
+ * @return string
91
+ */
92
+ public function info($title, $value)
93
+ {
94
+ return str_pad($title, 56, ' ', STR_PAD_RIGHT) . $value . PHP_EOL;
95
+ }
96
+
97
+ /**
98
+ * Theme Information
99
+ * @return string
100
+ */
101
+ public function theme()
102
+ {
103
+ // Versions earlier than 3.4
104
+ if (get_bloginfo("version") < "3.4" )
105
+ {
106
+ $themeData = get_theme_data(get_stylesheet_directory() . "/style.css");
107
+ return "{$themeData["Name"]} {$themeData["Version"]}";
108
+ }
109
+
110
+ $themeData = wp_get_theme();
111
+ return "{$themeData->Name} {$themeData->Version}";
112
+ }
113
+
114
+ /**
115
+ * Site Information
116
+ * @return string
117
+ */
118
+ public function site()
119
+ {
120
+ $output = "-- Site Info" . PHP_EOL . PHP_EOL;
121
+ $output .= $this->info("Site URL:", site_url());
122
+ $output .= $this->info("Home URL:", home_url());
123
+ $output .= $this->info("Home Path:", get_home_path());
124
+ $output .= $this->info("Installed in subdir:", ( $this->isSubDir() ? 'Yes' : 'No' )) ;
125
+ $output .= $this->info("Multisite:", ($this->isMultiSite ? "Yes" : "No" ));
126
+
127
+ return apply_filters("wpstg_sysinfo_after_site_info", $output);
128
+ }
129
+
130
+ /**
131
+ * Wp Staging plugin Information
132
+ * @return string
133
+ */
134
+ public function wpstaging() {
135
+ // Get wpstg settings
136
+ $settings = ( object ) get_option( 'wpstg_settings', array() );
137
+
138
+ // Clones data < 1.6.x
139
+ $clones = ( object ) get_option( 'wpstg_existing_clones', array() );
140
+ // Clones data version > 2.x
141
+ $clonesBeta = get_option( 'wpstg_existing_clones_beta' );
142
+
143
+
144
+ $output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
145
+ $output .= $this->info( "Query Limit:", isset( $settings->queryLimit ) ? $settings->queryLimit : 'undefined' );
146
+ $output .= $this->info( "File Copy Limit:", isset( $settings->fileLimit ) ? $settings->fileLimit : 'undefined' );
147
+ $output .= $this->info( "Batch Size:", isset( $settings->batchSize ) ? $settings->batchSize : 'undefined' );
148
+ $output .= $this->info( "CPU Load:", isset( $settings->cpuLoad ) ? $settings->cpuLoad : 'undefined' );
149
+ $output .= $this->info( "WP in Subdir:", isset( $settings->wpSubDirectory ) ? $settings->wpSubDirectory : 'false' );
150
+
151
+ $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.6.x" . PHP_EOL . PHP_EOL;
152
+
153
+ $i = 1;
154
+ foreach ( $clones as $key => $value ) {
155
+ $output .= $this->info( "Site name & subfolder :", $value );
156
+ }
157
+ $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version > 2.0.x" . PHP_EOL . PHP_EOL;
158
+
159
+ foreach ( $clonesBeta as $key => $clone ) {
160
+ $output .= $this->info( "Number:", isset( $clone['number'] ) ? $clone['number'] : 'undefined' );
161
+ $output .= $this->info( "directoryName:", isset( $clone['directoryName'] ) ? $clone['directoryName'] : 'undefined' );
162
+ $output .= $this->info( "Path:", isset( $clone['path'] ) ? $clone['path'] : 'undefined' );
163
+ $output .= $this->info( "URL:", isset( $clone['url'] ) ? $clone['url'] : 'undefined' );
164
+ $output .= $this->info( "DB Prefix:", isset( $clone['prefix'] ) ? $clone['prefix'] : 'undefined' );
165
+ $output .= $this->info( "DB Prefix wp-config.php:", $this->getStagingPrefix($clone));
166
+ $output .= $this->info( "Version:", isset( $clone['version'] ) ? $clone['version'] : 'undefined' ) . PHP_EOL . PHP_EOL;
167
+ }
168
+
169
+ //$output .= PHP_EOL . PHP_EOL;
170
+
171
+ $output .= $this->info( "Plugin Version:", get_option('wpstg_version', 'undefined') );
172
+ $output .= $this->info( "Install Date:", get_option('wpstg_installDate', 'undefined') );
173
+ $output .= $this->info( "Upgraded from:", get_option('wpstg_version_upgraded_from', 'undefined') );
174
+ $output .= $this->info( "Is Staging Site:", get_option('wpstg_is_staging_site', 'undefined') ) . PHP_EOL . PHP_EOL;
175
+
176
+
177
+ return apply_filters( "wpstg_sysinfo_after_wpstaging_info", $output );
178
+ }
179
+
180
+ /**
181
+ * Browser Information
182
+ * @return string
183
+ */
184
+ public function browser()
185
+ {
186
+ $output = $this->header("User Browser");
187
+ $output .= (new Browser);
188
+
189
+ return apply_filters("wpstg_sysinfo_after_user_browser", $output);
190
+ }
191
+
192
+ /**
193
+ * Frontpage Information when frontpage is set to "page"
194
+ * @return string
195
+ */
196
+ public function frontPage()
197
+ {
198
+ if (get_option("show_on_front") !== "page")
199
+ {
200
+ return '';
201
+ }
202
+
203
+ $frontPageID = get_option("page_on_front");
204
+ $blogPageID = get_option("page_for_posts");
205
+
206
+ // Front Page
207
+ $pageFront = ($frontPageID != 0) ? get_the_title($frontPageID) . " (#{$frontPageID})" : "Unset";
208
+ // Blog Page ID
209
+ $pageBlog = ($blogPageID != 0) ? get_the_title($blogPageID) . " (#{$blogPageID})" : "Unset";
210
+
211
+ $output = $this->info("Page On Front:", $pageFront);
212
+ $output .= $this->info("Page For Posts:", $pageBlog);
213
+
214
+ return $output;
215
+ }
216
+
217
+ /**
218
+ * Check wp_remote_post() functionality
219
+ * @return string
220
+ */
221
+ public function wpRemotePost()
222
+ {
223
+ // Make sure wp_remote_post() is working
224
+ $wpRemotePost = "wp_remote_post() does not work";
225
+
226
+ // Send request
227
+ $response = wp_remote_post(
228
+ "https://www.paypal.com/cgi-bin/webscr",
229
+ array(
230
+ "sslverify" => false,
231
+ "timeout" => 60,
232
+ "user-agent" => "WPSTG/" . WPStaging::VERSION,
233
+ "body" => array("cmd" => "_notify-validate")
234
+ )
235
+ );
236
+
237
+ // Validate it worked
238
+ if (!is_wp_error($response) && 200 <= $response["response"]["code"] && 300> $response["response"]["code"])
239
+ {
240
+ $wpRemotePost = "wp_remote_post() works";
241
+ }
242
+
243
+ return $this->info("Remote Post:", $wpRemotePost);
244
+ }
245
+
246
+ /**
247
+ * WordPress Configuration
248
+ * @return string
249
+ */
250
+ public function wp()
251
+ {
252
+ $output = $this->header("WordPress Configuration");
253
+ $output .= $this->info("Version:", get_bloginfo("version"));
254
+ $output .= $this->info("Language:", (defined("WPLANG") && WPLANG) ? WPLANG : "en_US");
255
+
256
+ $permalinkStructure = get_option("permalink_structure");;
257
+ $output .= $this->info("Permalink Structure:", ($permalinkStructure) ? $permalinkStructure : "Default");
258
+
259
+ $output .= $this->info("Active Theme:", $this->theme());
260
+ $output .= $this->info("Show On Front:", get_option("show_on_front"));
261
+
262
+ // Frontpage information
263
+ $output .= $this->frontPage();
264
+
265
+ // WP Remote Post
266
+ $output .= $this->wpRemotePost();
267
+
268
+ // Table Prefix
269
+ $wpDB = $this->di->get("wpdb");
270
+ $tablePrefix = "DB Prefix: " . $wpDB->prefix . ' ';
271
+ $tablePrefix .= "Length: " . strlen($wpDB->prefix) . " Status: ";
272
+ $tablePrefix .= (strlen($wpDB->prefix) > 16) ? " ERROR: Too long" : " Acceptable";
273
+
274
+ $output .= $this->info("Table Prefix:", $tablePrefix);
275
+
276
+ // WP Debug
277
+ $output .= $this->info("WP_DEBUG:", (defined("WP_DEBUG")) ? WP_DEBUG ? "Enabled" : "Disabled" : "Not set");
278
+ $output .= $this->info("Memory Limit:", WP_MEMORY_LIMIT);
279
+ $output .= $this->info("Registered Post Stati:", implode(", ", \get_post_stati()));
280
+
281
+ return apply_filters("wpstg_sysinfo_after_wpstg_config", $output);
282
+ }
283
+
284
+ /**
285
+ * List of Active Plugins
286
+ * @param array $plugins
287
+ * @param array $activePlugins
288
+ * @return string
289
+ */
290
+ public function activePlugins($plugins, $activePlugins)
291
+ {
292
+ $output = $this->header("WordPress Active Plugins");
293
+
294
+ foreach ($plugins as $path => $plugin)
295
+ {
296
+ if (!in_array($path, $activePlugins))
297
+ {
298
+ continue;
299
+ }
300
+
301
+ $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
302
+ }
303
+
304
+ return apply_filters("wpstg_sysinfo_after_wordpress_plugins", $output);
305
+ }
306
+
307
+ /**
308
+ * List of Inactive Plugins
309
+ * @param array $plugins
310
+ * @param array $activePlugins
311
+ * @return string
312
+ */
313
+ public function inactivePlugins($plugins, $activePlugins)
314
+ {
315
+ $output = $this->header("WordPress Inactive Plugins");
316
+
317
+ foreach ($plugins as $path => $plugin)
318
+ {
319
+ if (in_array($path, $activePlugins))
320
+ {
321
+ continue;
322
+ }
323
+
324
+ $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
325
+ }
326
+
327
+ return apply_filters("wpstg_sysinfo_after_wordpress_plugins_inactive", $output);
328
+ }
329
+
330
+ /**
331
+ * Get list of active and inactive plugins
332
+ * @return string
333
+ */
334
+ public function plugins()
335
+ {
336
+ // Get plugins and active plugins
337
+ $plugins = get_plugins();
338
+ $activePlugins = get_option("active_plugins", array());
339
+
340
+ // Active plugins
341
+ $output = $this->activePlugins($plugins, $activePlugins);
342
+ $output .= $this->inactivePlugins($plugins, $activePlugins);
343
+
344
+ return $output;
345
+ }
346
+
347
+ /**
348
+ * Multisite Plugins
349
+ * @return string
350
+ */
351
+ public function multiSitePlugins()
352
+ {
353
+ if (!$this->isMultiSite)
354
+ {
355
+ return '';
356
+ }
357
+
358
+ $output = $this->header("Network Active Plugins");
359
+
360
+ $plugins = wp_get_active_network_plugins();
361
+ $activePlugins = get_site_option("active_sitewide_plugins", array());
362
+
363
+ foreach ($plugins as $pluginPath)
364
+ {
365
+ $pluginBase = plugin_basename($pluginPath);
366
+
367
+ if (!array_key_exists($pluginBase, $activePlugins))
368
+ {
369
+ continue;
370
+ }
371
+
372
+ $plugin = get_plugin_data($pluginPath);
373
+
374
+ $output .= "{$plugin["Name"]}: {$plugin["Version"]}" . PHP_EOL;
375
+ }
376
+ unset($plugins, $activePlugins);
377
+
378
+ return $output;
379
+ }
380
+
381
+ /**
382
+ * Server Information
383
+ * @return string
384
+ */
385
+ public function server()
386
+ {
387
+ // Server Configuration
388
+ $output = $this->header("Webserver Configuration");
389
+
390
+ $output .= $this->info("PHP Version:", PHP_VERSION);
391
+ $output .= $this->info("MySQL Version:", $this->di->get("wpdb")->db_version());
392
+ $output .= $this->info("Webserver Info:", $_SERVER["SERVER_SOFTWARE"]);
393
+
394
+ return apply_filters("wpstg_sysinfo_after_webserver_config", $output);
395
+ }
396
+
397
+ /**
398
+ * PHP Configuration
399
+ * @return string
400
+ */
401
+ public function php()
402
+ {
403
+ $output = $this->header("PHP Configuration");
404
+ $output .= $this->info("Safe Mode:", ($this->isSafeModeEnabled() ? "Enabled" : "Disabled"));
405
+ $output .= $this->info("Memory Limit:", ini_get("memory_limit"));
406
+ $output .= $this->info("Upload Max Size:", ini_get("upload_max_filesize"));
407
+ $output .= $this->info("Post Max Size:", ini_get("post_max_size"));
408
+ $output .= $this->info("Upload Max Filesize:", ini_get("upload_max_filesize"));
409
+ $output .= $this->info("Time Limit:", ini_get("max_execution_time"));
410
+ $output .= $this->info("Max Input Vars:", ini_get("max_input_vars"));
411
+
412
+ $displayErrors = ini_get("display_errors");
413
+ $output .= $this->info("Display Errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A");
414
+
415
+ return apply_filters("wpstg_sysinfo_after_php_config", $output);
416
+ }
417
+
418
+ /**
419
+ * Check if PHP is on Safe Mode
420
+ * @return bool
421
+ */
422
+ public function isSafeModeEnabled()
423
+ {
424
+ return (
425
+ version_compare(PHP_VERSION, "5.4.0", '<') &&
426
+ @ini_get("safe_mode")
427
+ );
428
+ }
429
+
430
+ /**
431
+ * Checks if function exists or not
432
+ * @param string $functionName
433
+ * @return string
434
+ */
435
+ public function isSupported($functionName)
436
+ {
437
+ return (function_exists($functionName)) ? "Supported" : "Not Supported";
438
+ }
439
+
440
+ /**
441
+ * Checks if class or extension is loaded / exists to determine if it is installed or not
442
+ * @param string $name
443
+ * @param bool $isClass
444
+ * @return string
445
+ */
446
+ public function isInstalled($name, $isClass = true)
447
+ {
448
+ if (true === $isClass)
449
+ {
450
+ return (class_exists($name)) ? "Installed" : "Not Installed";
451
+ }
452
+ else
453
+ {
454
+ return (extension_loaded($name)) ? "Installed" : "Not Installed";
455
+ }
456
+ }
457
+
458
+ /**
459
+ * Gets Installed Important PHP Extensions
460
+ * @return string
461
+ */
462
+ public function phpExtensions()
463
+ {
464
+ // Important PHP Extensions
465
+ $output = $this->header("PHP Extensions");
466
+ $output .= $this->info("cURL:", $this->isSupported("curl_init"));
467
+ $output .= $this->info("fsockopen:", $this->isSupported("fsockopen"));
468
+ $output .= $this->info("SOAP Client:", $this->isInstalled("SoapClient"));
469
+ $output .= $this->info("Suhosin:", $this->isInstalled("suhosin", false));
470
+
471
+ return apply_filters("wpstg_sysinfo_after_php_ext", $output);
472
+ }
473
+
474
+ /**
475
+ * Check if WP is installed in subdir
476
+ * @return boolean
477
+ */
478
+ private function isSubDir(){
479
+ if ( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
480
+ return true;
481
+ }
482
+ return false;
483
+ }
484
+
485
+ /**
486
+ * Check and return prefix of the staging site
487
+ */
488
+ /**
489
+ * Try to get the staging prefix from wp-config.php of staging site
490
+ * @param array $clone
491
+ * @return sting
492
+ */
493
+ private function getStagingPrefix($clone=array()) {
494
+ // Throw error
495
+ $path = ABSPATH . $clone['directoryName'] . "/wp-config.php";
496
+ if (false === ($content = @file_get_contents($path))) {
497
+ return 'Can\'t find staging wp-config.php';
498
+ } else {
499
+
500
+ // Get prefix from wp-config.php
501
+ //preg_match_all("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
502
+ preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
503
+ //wp_die(var_dump($matches));
504
+
505
+ if (!empty($matches[1])) {
506
+ return $matches[1];
507
+ } else {
508
+ return 'No table_prefix in wp-config.php';
509
+ }
510
+ }
511
+
512
+ }
513
  }
apps/Backend/public/css/wpstg-admin.css CHANGED
@@ -1,772 +1,783 @@
1
- /**
2
- * WPSTG Admin CSS
3
- *
4
- * @package WPSTG
5
- * @subpackage Admin CSS
6
- * @copyright Copyright (c) 2015, René Hermenau
7
- * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8
- */
9
-
10
-
11
- /* CSS for Tabs */
12
-
13
- #tab_container ul {
14
- /*height: 200px;*/
15
- list-style: none;
16
- margin: 0;
17
- padding: 0;
18
- background: #f1f1f1;
19
- float: left;
20
- /*list-style-type: square;*/
21
- }
22
-
23
- #tab_container ul li:first-child.selected-tab {
24
- border-top: none;
25
- }
26
-
27
- #tab_container ul li a.selected-tab {
28
- font-weight: bold;
29
- text-decoration: none;
30
- }
31
-
32
-
33
-
34
- #tab_container .row{
35
- padding-top:10px;
36
- padding-bottom:12px;
37
- }
38
-
39
- #wpstg-tools .nav-tab-wrapper{
40
- padding:0;
41
- }
42
-
43
-
44
- #tab_container .row label strong, #tab_container .row strong {
45
- font-weight: bold;
46
- }
47
-
48
- .wpstg-tabs a {
49
- padding:5px;
50
- }
51
-
52
- #tab_container > ul > li.wpstg-tabs.active {
53
- background-color:white;
54
- }
55
-
56
-
57
-
58
- #wpstg_settingsgeneral_header .row:nth-child(3), #wpstg_settingsgeneral_header .row:nth-child(4){
59
- display:none;
60
- }
61
-
62
- /* Layout of admin table and rows
63
- */
64
-
65
- #tab_container .panel-container {
66
- background: #FFF;
67
- padding:0 20px 20px 20px;
68
- overflow:auto;
69
- }
70
-
71
- #tab_container .form-table th {
72
- vertical-align: top;
73
- text-align: left;
74
- padding: 20px 10px 20px 0;
75
- line-height: 1.3;
76
- font-weight: bold;
77
- font-size: 14px;
78
- color:#484848;
79
- width: 30%;
80
- }
81
-
82
- #tab_container .form-table tr {
83
- border-bottom: 1px solid #E7E7E7;
84
- }
85
-
86
- #tab_container span.description{
87
- display: block;
88
- font-weight: 400;
89
- font-style: normal;
90
- font-size: 13px;
91
- margin-top: 7px;
92
- color:#484848;
93
- }
94
-
95
- #tab_container .col-title{
96
- color:#484848;
97
- }
98
-
99
- @media only screen and (max-width:680px) {
100
- #tab_container ul {
101
- float:none;
102
- }
103
- #tab_container .form-table tr > th {
104
- width:100%;
105
- }
106
- #tab_container span.description{
107
- font-size: 14px;
108
- }
109
- #tab_container .form-table tr > th, #tab_container .form-table tr > td {
110
- padding:10px;
111
- }
112
- }
113
-
114
- #tab_container ul li {
115
- margin-bottom:0;
116
- }
117
-
118
- #tab_container ul li a {
119
- display: block;
120
- padding:10px 4px 10px 14px;
121
- border-width: 1px 0;
122
- border-style: solid;
123
- border-top-color:white;
124
- border-bottom-color:#e7e7e7;
125
- text-decoration: none;
126
- color: #0097DF;
127
- font-weight: bold;
128
- }
129
- #tab_container ul li a:hover {
130
- background-color: #e5e5e5;
131
- color:#777777;
132
- }
133
-
134
-
135
- .wp-staginglogo{
136
- display: block;
137
- font-size:16px;
138
- padding-top:20px;
139
- width:220px;
140
- float:left;
141
- }
142
-
143
- .wpstg-version{
144
- display: block;
145
- padding-top:29px
146
- }
147
-
148
-
149
- .wpstg_admin .nav-tab {
150
- color: #3C3C3C;
151
- }
152
-
153
-
154
- #tab_container table tbody tr:nth-child(1) > th > div {
155
- font-size: 20px;
156
- }
157
-
158
- .wpstg_hidden{
159
- display: none;
160
- }
161
-
162
- /* End layout of admin table and rows
163
- */
164
- #mashtabcontainer > .mashtabs {
165
- background-color: #ffffff;
166
- }
167
-
168
- #mashtabcontainer ul .active {
169
- background-color: #00adef;
170
- color: white;
171
- border-bottom-color: #0098D2;
172
- }
173
-
174
- #mashtabcontainer ul .active:hover {
175
- background-color: #00A4E2;
176
- color: white;
177
- border-bottom-color: #0098D2;
178
- }
179
-
180
- #mashtabcontainer ul li a {
181
- padding: 10px 14px 10px 14px;
182
- background-color: #f3f3f3
183
-
184
- }
185
-
186
- #mashtabcontainer .mashtab-container {
187
- border: 0 solid #ececec;
188
- }
189
-
190
- /* Cloning workflow */
191
- #wpstg-clonepage-wrapper {
192
- margin-bottom: 20px;
193
- /*width: 690px; */
194
- }
195
-
196
- @media screen and (min-width:1090px){
197
- #wpstg-clonepage-wrapper {
198
- float: left;
199
- margin-bottom: 20px;
200
- /*width: 690px;*/
201
- }
202
- .wpstg-sidebar{
203
- display: none;
204
- margin-left: 700px;
205
- margin-top: 138px;
206
- }
207
- }
208
-
209
- .wpstg-sidebar{
210
- display: none;
211
- padding: 10px;
212
- border: 1px solid #DFDFDF;
213
- max-width: 250px;
214
- height: 250px;
215
- }
216
-
217
- #wpstg-steps {
218
- margin-top:30px;
219
- }
220
-
221
- #wpstg-steps li {
222
- color: #444;
223
- line-height: 20px;
224
- padding-right:10px;
225
- float:left;
226
- }
227
-
228
-
229
- .wpstg-step-num {
230
- border: 1px solid #444;
231
- border-radius: 3px;
232
- display: inline-block;
233
- width: 20px;
234
- height: 20px;
235
- text-align: center;
236
- margin-right: 5px;
237
- }
238
-
239
- .wpstg-current-step {
240
- font-weight: bold;
241
- }
242
-
243
- .wpstg-current-step .wpstg-step-num {
244
- background: #444;
245
- color: #eee;
246
- }
247
-
248
- .wpstg-clone {
249
- border: 3px solid #ffffff;
250
- margin-bottom: 5px;
251
- padding: 5px 10px;
252
- width: 300px;
253
- position: relative;
254
- overflow: hidden;
255
- transition: border-color .2s ease-in-out;
256
- background-color: #DDDDDD;
257
- }
258
-
259
- .wpstg-clone.active {
260
- border-color: #1d94cf;;
261
- }
262
-
263
- .wpstg-clone-title {
264
- display: inline-block;
265
- font-size: 15px;
266
- max-width: 130px;
267
- text-decoration: none;
268
- font-weight: bold;
269
- color:#0285AE;
270
- }
271
-
272
- .wpstg-clone-action {
273
- background: #ffffff;
274
- border-left: 1px solid #ccc;
275
- color: #bbb;
276
- padding: 0 5px;
277
- float: right;
278
- text-decoration: none;
279
- position: relative;
280
- transition: color .2s ease-in-out;
281
- }
282
-
283
- .wpstg-remove-clone:hover {
284
- color: #ef6d6d;
285
- }
286
-
287
- .wpstg-clone-action:last-child {
288
- border: none;
289
- }
290
-
291
- .wpstg-clone:hover .wpstg-clone-action {
292
- display: inline-block;
293
- }
294
-
295
- #wpstg-show-error-details:focus,
296
- #wpstg-workflow .wpstg-clone-action {
297
- outline: none;
298
- box-shadow: none;
299
- }
300
-
301
- .wpstg-link-btn {
302
- background: #45a1c9;
303
- color: #fff;
304
- display: inline-block;
305
- padding: 5px 10px;
306
- text-decoration: none;
307
- vertical-align: baseline;
308
- transition: all .2s ease-in-out;
309
- }
310
-
311
- .wpstg-link-btn:hover,
312
- .wpstg-link-btn:focus {
313
- color: #fff;
314
- outline: none;
315
- box-shadow: none;
316
- }
317
-
318
- #wpstg-workflow .wpstg-link-btn:active {
319
- vertical-align: baseline;
320
- }
321
-
322
- .wpstg-link-btn[disabled] {
323
- background: #777 !important;
324
- pointer-events: none;
325
- }
326
-
327
- #wpstg-cancel-cloning {
328
- background: #ff3428;
329
- border-color: #e72f24;
330
- margin-top: 5px;
331
- }
332
-
333
- #wpstg-cancel-cloning.success {
334
- background: #64dd58;
335
- border-color: #54bd4a;
336
- }
337
-
338
- #wpstg-error-wrapper,
339
- #wpstg-error-details {
340
- display: none;
341
- margin-top: 10px;
342
- font-size: 13px;
343
- }
344
-
345
- #wpstg-show-error-details {
346
- display: inline-block;
347
- margin-left: 5px;
348
- color: #555;
349
- text-decoration: none;
350
- transition: color .2s ease-in-out;
351
- }
352
-
353
- #wpstg-show-error-details:hover {
354
- color: #1d94cf;
355
- }
356
-
357
- #wpstg-error-details {
358
- border-left: 5px solid #ef6d6d;
359
- padding: 10px;
360
- width: 500px;
361
- }
362
-
363
- #wpstg-home-link,
364
- #wpstg-try-again {
365
- display: none;
366
- }
367
-
368
-
369
- #wpstg-loader {
370
- content: url('../img/loading.gif');
371
- margin-top:-5px;
372
- }
373
-
374
- #wpstg-loader.wpstg-finished {
375
- content:"Finished";
376
- background-color:#00c89a;
377
- color:white;
378
- padding:2px;
379
- margin-top:6px;
380
- }
381
-
382
- #wpstg-workflow {
383
- position: relative;
384
- clear:both;
385
- padding-top:20px;
386
- margin-right:20px;
387
- float:left;
388
- min-width: 500px;
389
- border-right: 1px solid #DFDFDF;
390
- min-height: 380px;
391
- padding-right: 20px;
392
- }
393
-
394
- #wpstg-sidebar {
395
- float: left;
396
- max-width: 400px;
397
- display: block;
398
- }
399
-
400
- @media screen and (max-width:1150px){
401
- #wpstg-sidebar img{
402
- margin-top: 30px;
403
- }
404
- }
405
-
406
- #wpstg-workflow.loading::after,
407
- #wpstg-removing-clone.loading::after {
408
- background: rgba(255, 255, 255, .7);
409
- content: 'Loading... may take a while for huge websites';
410
- display: block;
411
- width: 100%;
412
- height: 100%;
413
- font-size: 20px;
414
- padding-top: 100px;
415
- text-align: center;
416
- position: absolute;
417
- top: 0;
418
- left: 0;
419
- z-index: 99;
420
- }
421
-
422
- #wpstg-removing-clone.loading::after {
423
- content: 'REMOVING' !important;
424
- }
425
-
426
- #wpstg-existing-clones,
427
- #wpstg-removing-clone {
428
- position: relative;
429
- }
430
-
431
- .wpstg-progress-bar {
432
- max-width: 900px;
433
- height: 27px;
434
- padding: 0;
435
- background-color: #d6d8d7;
436
- }
437
-
438
- .wpstg-progress {
439
- background: #1d94cf;
440
- width: 0;
441
- height: 100%;
442
- transition: width 1s;
443
- color:white;
444
- line-height:25px;
445
- text-align:center;
446
- }
447
-
448
- #wpstg-new-clone-id.wpstg-error-input,
449
- #wpstg-clone-path.wpstg-error-input {
450
- border: 1px solid #ff4235;
451
- box-shadow: 0 0 2px rgba(255, 66, 53, .8);
452
- }
453
-
454
- #wpstg-clone-path {
455
- margin-left: 10px;
456
- width: 350px;
457
- }
458
-
459
- .wpstg-error-msg {
460
- color: #ff4235;
461
- }
462
-
463
- #wpstg-clone-id-error {
464
- display: block;
465
- text-align: right;
466
- margin-right: 90px;
467
- }
468
-
469
- #wpstg-start-cloning + .wpstg-error-msg {
470
- display: block;
471
- margin-top: 5px;
472
- }
473
-
474
- .wpstg-size-info {
475
- color: #999;
476
- font-weight: normal;
477
- position: relative;
478
- left: 2px;
479
- }
480
-
481
- .wpstg-db-table .wpstg-size-info {
482
- top: 2px;
483
- }
484
-
485
- #wpstg-workflow #wpstg-start-cloning {
486
- display: inline-block;
487
- margin-left: 5px;
488
- font-size: 14px;
489
- vertical-align: baseline;
490
- }
491
-
492
- /* Tabs */
493
- .wpstg-tabs-wrapper {
494
- max-width: 640px;
495
- margin: 10px 0;
496
- }
497
-
498
- #wpstg-path-wrapper {
499
- border-bottom: 2px dashed #ccc;
500
- padding-bottom: 10px;
501
- margin-bottom: 10px;
502
- }
503
-
504
- .wpstg-tabs-wrapper {
505
- border: 1px solid #ddd;
506
- border-right: none;
507
- border-left: none;
508
- }
509
-
510
- .wpstg-tab-section {
511
- border: 1px solid #ddd;
512
- border-right: none;
513
- border-left: none;
514
- display: none;
515
- padding: 20px;
516
- }
517
-
518
- .wpstg-tab-section::after {
519
- display: block;
520
- content: '';
521
- clear: both;
522
- }
523
-
524
- .wpstg-tab-header {
525
- border: 1px solid #ddd;
526
- border-right: none;
527
- border-left: none;
528
- color: #444;
529
- font-size: 16px;
530
- font-weight: bolder;
531
- display: block;
532
- padding: 10px;;
533
- text-decoration: none;
534
- }
535
-
536
- .wpstg-tab-triangle {
537
- font-family: arial;
538
- display: inline-block;
539
- margin-right: 10px;
540
- }
541
-
542
- .wpstg-tab-header:focus {
543
- color: #444;
544
- outline: none;
545
- box-shadow: none;
546
- }
547
-
548
- #wpstg-large-files {
549
- display:none;
550
- border: 1px dashed #ccc;
551
- /*float: right;*/
552
- padding: 10px 10px 10px;
553
- margin-top:20px;
554
- position: relative;
555
- font-size:12px;
556
- }
557
-
558
- #wpstg-large-files h3 {
559
- background: #fff;
560
- margin: 0;
561
- padding: 0 5px;
562
- position: absolute;
563
- top: -10px;
564
- left: 5px;
565
- }
566
-
567
- /* tmp */
568
- .wpstg-subdir {
569
- display: none;
570
- margin-left: 20px;
571
- }
572
-
573
- .wpstg-dir a.disabled {
574
- color: #888;
575
- cursor: default;
576
- text-decoration: none;
577
- }
578
-
579
- .wpstg-check-subdirs {
580
- display: inline-block;
581
- margin-left: 10px;
582
- }
583
-
584
- .wpstg-notice-alert{
585
- display:block;
586
- background-color:#FFD0D0;
587
- padding:20px;
588
- border: 1px solid #fff;
589
- max-width: 600px;
590
- }
591
-
592
- .wpstg-header{
593
- font-weight: 400;
594
- line-height: 1.6em;
595
- font-size: 19px;
596
- border-bottom: 1px solid #DFDFDF;
597
- clear:both;
598
- }
599
-
600
-
601
- #wpstg-clone-label{
602
- font-size: 14px;
603
- font-weight: bold;
604
- }
605
-
606
- #wpstg-log-details{
607
- height: 300px;
608
- max-width: 700px;
609
- overflow: scroll;
610
- /*max-width: 650px;*/
611
- font-family: monospace;
612
- font-size: 12px;
613
- line-height: 15px;
614
- border: 1px solid #FFF;
615
- background-color: black;
616
- color: #c0c0c0;
617
- padding:3px;
618
- white-space: nowrap;
619
- margin-top: 15px;
620
- }
621
-
622
- #wpstg-finished-result {
623
- display:none;
624
- }
625
-
626
- #wpstg-remove-cloning {
627
- background: #ff3428;
628
- border-color: #e72f24;
629
- margin-top: 5px;
630
- }
631
-
632
- #wpstg-success-notice{
633
- padding: 10px;
634
- background-color: white;
635
- max-width: 900px;
636
- border: 1px solid #ccc;
637
- margin-top: 20px;
638
- }
639
-
640
- .wpstg_beta_notice {
641
- margin-bottom:20px;
642
- }
643
-
644
- .wpstg-sysinfo {
645
- width:700px;
646
- height: 500px;
647
- }
648
-
649
- .form-table .col-title label {
650
- font-weight: 600;
651
- }
652
-
653
- .form-table td:first-child {
654
- width:30%;
655
- }
656
-
657
-
658
- .wpstg-share-button-container{
659
- margin: 5px 0;
660
- }
661
-
662
- .wpstg-share-button-container p{
663
- margin:0px 0 10px 0;
664
- }
665
-
666
- .wpstg-share-button {
667
- display: inline-block;
668
- }
669
-
670
- .wpstg-share-button a{
671
- text-decoration:none;
672
- }
673
-
674
- .wpstg-share-button .wpstg-share {
675
- font-family:sans-serif;
676
- font-weight:bold;
677
- text-decoration:none;
678
- text-align:center;
679
- }
680
-
681
-
682
- .wpstg-share-button .wpstg-share {
683
- -webkit-border-radius:2px;
684
- -moz-border-radius:2px;
685
- border-radius:2px;
686
- color:#FFF;
687
- display:inline;
688
- font-size:16px;
689
- width:40px;
690
- padding:4px 8px;
691
- }
692
-
693
- .wpstg-share-button-twitter .wpstg-share {
694
- background-color:#00ABF0;
695
- }
696
-
697
- .wpstg-share-button-facebook .wpstg-share {
698
- background-color:#3b5998;
699
- }
700
-
701
- .wpstg-share-button-googleplus .wpstg-share {
702
- background-color:#F53424;
703
- }
704
-
705
- .wpstg-share-button-twitter .share:active,.wpstg-share-button-facebook .share:active,.wpstg-share-button-googleplus .share:active {
706
- background-color:#353535;
707
- }
708
-
709
- #wpstg-check-space {
710
- margin-left:8px;
711
- }
712
-
713
- /* welcome screen */
714
- .wpstg-button.green {
715
- display: inline-block;
716
- background-color: #83c11f;
717
- padding: 10px;
718
- min-width: 170px;
719
- color: white;
720
- font-size: 16px;
721
- text-decoration: none;
722
- text-align: center;
723
- margin-top: 20px;
724
- }
725
- #wpstg-welcome li {
726
- font-size: 18px;
727
- line-height: 29px;
728
- position: relative;
729
- padding-left: 23px;
730
- list-style: none!important;
731
- }
732
- #wpstg-welcome {
733
- margin-top:20px;
734
- margin-right: 20px;
735
- background-color: white;
736
- }
737
- .wpstg-heading-pro {
738
- color: #0080ff;
739
- font-weight: bold;
740
- }
741
- .wpstg-h2 {
742
- margin-top: 0px;
743
- margin-bottom: 1.2rem;
744
- font-size: 30px;
745
- line-height: 2.5rem;
746
- }
747
- #wpstg-welcome li:before {
748
- width: 1em;
749
- height: 100%;
750
- background: url(data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%221792%22%20height%3D%221792%22%20viewBox%3D%220%200%201792%201792%22%20xmlns%3D%22http%3A%2F%2Fwww%2Ew3%2Eorg%2F2000%2Fsvg%22%3E%3Cpath%20fill%3D%22%2377B227%22%20d%3D%22M1671%20566q0%2040%2D28%2068l%2D724%20724%2D136%20136q%2D28%2028%2D68%2028t%2D68%2D28l%2D136%2D136%2D362%2D362q%2D28%2D28%2D28%2D68t28%2D68l136%2D136q28%2D28%2068%2D28t68%2028l294%20295%20656%2D657q28%2D28%2068%2D28t68%2028l136%20136q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) left .4em no-repeat;
751
- background-size: contain;
752
- content: "";
753
- position: absolute;
754
- top: 0;
755
- left: 0;
756
- color: #77b227;
757
- }
758
- .wpstg-h1 {
759
- font-size: 2.75em;
760
- margin-bottom: 1.35rem;
761
- font-size: 2.5em;
762
- line-height: 3.68rem;
763
- letter-spacing: normal;
764
- }
765
- #wpstg-welcome h2 {
766
- margin: 0 0 15px;
767
- }
768
- #wpstg-welcome .wpstg-footer {
769
- clear: both;
770
- margin-top: 20px;
771
- font-style: italic;
 
 
 
 
 
 
 
 
 
 
 
772
  }
1
+ /**
2
+ * WPSTG Admin CSS
3
+ *
4
+ * @package WPSTG
5
+ * @subpackage Admin CSS
6
+ * @copyright Copyright (c) 2015, René Hermenau
7
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
8
+ */
9
+
10
+
11
+ /* CSS for Tabs */
12
+
13
+ #tab_container ul {
14
+ /*height: 200px;*/
15
+ list-style: none;
16
+ margin: 0;
17
+ padding: 0;
18
+ background: #f1f1f1;
19
+ float: left;
20
+ /*list-style-type: square;*/
21
+ }
22
+
23
+ #tab_container ul li:first-child.selected-tab {
24
+ border-top: none;
25
+ }
26
+
27
+ #tab_container ul li a.selected-tab {
28
+ font-weight: bold;
29
+ text-decoration: none;
30
+ }
31
+
32
+
33
+
34
+ #tab_container .row{
35
+ padding-top:10px;
36
+ padding-bottom:12px;
37
+ }
38
+
39
+ #wpstg-tools .nav-tab-wrapper{
40
+ padding:0;
41
+ }
42
+
43
+
44
+ #tab_container .row label strong, #tab_container .row strong {
45
+ font-weight: bold;
46
+ }
47
+
48
+ .wpstg-tabs a {
49
+ padding:5px;
50
+ }
51
+
52
+ #tab_container > ul > li.wpstg-tabs.active {
53
+ background-color:white;
54
+ }
55
+
56
+
57
+
58
+ #wpstg_settingsgeneral_header .row:nth-child(3), #wpstg_settingsgeneral_header .row:nth-child(4){
59
+ display:none;
60
+ }
61
+
62
+ /* Layout of admin table and rows
63
+ */
64
+
65
+ #tab_container .panel-container {
66
+ background: #FFF;
67
+ padding:0 20px 20px 20px;
68
+ overflow:auto;
69
+ }
70
+
71
+ #tab_container .form-table th {
72
+ vertical-align: top;
73
+ text-align: left;
74
+ padding: 20px 10px 20px 0;
75
+ line-height: 1.3;
76
+ font-weight: bold;
77
+ font-size: 14px;
78
+ color:#484848;
79
+ width: 30%;
80
+ }
81
+
82
+ #tab_container .form-table tr {
83
+ border-bottom: 1px solid #E7E7E7;
84
+ }
85
+
86
+ #tab_container span.description{
87
+ display: block;
88
+ font-weight: 400;
89
+ font-style: normal;
90
+ font-size: 13px;
91
+ margin-top: 7px;
92
+ color:#484848;
93
+ }
94
+
95
+ #tab_container .col-title{
96
+ color:#484848;
97
+ }
98
+
99
+ @media only screen and (max-width:680px) {
100
+ #tab_container ul {
101
+ float:none;
102
+ }
103
+ #tab_container .form-table tr > th {
104
+ width:100%;
105
+ }
106
+ #tab_container span.description{
107
+ font-size: 14px;
108
+ }
109
+ #tab_container .form-table tr > th, #tab_container .form-table tr > td {
110
+ padding:10px;
111
+ }
112
+ }
113
+
114
+ #tab_container ul li {
115
+ margin-bottom:0;
116
+ }
117
+
118
+ #tab_container ul li a {
119
+ display: block;
120
+ padding:10px 4px 10px 14px;
121
+ border-width: 1px 0;
122
+ border-style: solid;
123
+ border-top-color:white;
124
+ border-bottom-color:#e7e7e7;
125
+ text-decoration: none;
126
+ color: #0097DF;
127
+ font-weight: bold;
128
+ }
129
+ #tab_container ul li a:hover {
130
+ background-color: #e5e5e5;
131
+ color:#777777;
132
+ }
133
+
134
+
135
+ .wp-staginglogo{
136
+ display: block;
137
+ font-size:16px;
138
+ padding-top:20px;
139
+ width:220px;
140
+ float:left;
141
+ }
142
+
143
+ .wpstg-version{
144
+ display: block;
145
+ padding-top:29px
146
+ }
147
+
148
+
149
+ .wpstg_admin .nav-tab {
150
+ color: #3C3C3C;
151
+ }
152
+
153
+
154
+ #tab_container table tbody tr:nth-child(1) > th > div {
155
+ font-size: 20px;
156
+ }
157
+
158
+ .wpstg_hidden{
159
+ display: none;
160
+ }
161
+
162
+ /* End layout of admin table and rows
163
+ */
164
+ #mashtabcontainer > .mashtabs {
165
+ background-color: #ffffff;
166
+ }
167
+
168
+ #mashtabcontainer ul .active {
169
+ background-color: #00adef;
170
+ color: white;
171
+ border-bottom-color: #0098D2;
172
+ }
173
+
174
+ #mashtabcontainer ul .active:hover {
175
+ background-color: #00A4E2;
176
+ color: white;
177
+ border-bottom-color: #0098D2;
178
+ }
179
+
180
+ #mashtabcontainer ul li a {
181
+ padding: 10px 14px 10px 14px;
182
+ background-color: #f3f3f3
183
+
184
+ }
185
+
186
+ #mashtabcontainer .mashtab-container {
187
+ border: 0 solid #ececec;
188
+ }
189
+
190
+ /* Cloning workflow */
191
+ #wpstg-clonepage-wrapper {
192
+ margin-bottom: 20px;
193
+ /*width: 690px; */
194
+ }
195
+
196
+ @media screen and (min-width:1090px){
197
+ #wpstg-clonepage-wrapper {
198
+ float: left;
199
+ margin-bottom: 20px;
200
+ /*width: 690px;*/
201
+ }
202
+ .wpstg-sidebar{
203
+ display: none;
204
+ margin-left: 700px;
205
+ margin-top: 138px;
206
+ }
207
+ }
208
+
209
+ .wpstg-sidebar{
210
+ display: none;
211
+ padding: 10px;
212
+ border: 1px solid #DFDFDF;
213
+ max-width: 250px;
214
+ height: 250px;
215
+ }
216
+
217
+ #wpstg-steps {
218
+ margin-top:30px;
219
+ }
220
+
221
+ #wpstg-steps li {
222
+ color: #444;
223
+ line-height: 20px;
224
+ padding-right:10px;
225
+ float:left;
226
+ }
227
+
228
+
229
+ .wpstg-step-num {
230
+ border: 1px solid #444;
231
+ border-radius: 3px;
232
+ display: inline-block;
233
+ width: 20px;
234
+ height: 20px;
235
+ text-align: center;
236
+ margin-right: 5px;
237
+ }
238
+
239
+ .wpstg-current-step {
240
+ font-weight: bold;
241
+ }
242
+
243
+ .wpstg-current-step .wpstg-step-num {
244
+ background: #444;
245
+ color: #eee;
246
+ }
247
+
248
+ .wpstg-clone {
249
+ border: 3px solid #ffffff;
250
+ margin-bottom: 5px;
251
+ padding: 5px 10px;
252
+ width: 300px;
253
+ position: relative;
254
+ overflow: hidden;
255
+ transition: border-color .2s ease-in-out;
256
+ background-color: #DDDDDD;
257
+ }
258
+
259
+ .wpstg-clone.active {
260
+ border-color: #1d94cf;;
261
+ }
262
+
263
+ .wpstg-clone-title {
264
+ display: inline-block;
265
+ font-size: 15px;
266
+ max-width: 130px;
267
+ text-decoration: none;
268
+ font-weight: bold;
269
+ color:#0285AE;
270
+ }
271
+
272
+ .wpstg-clone-action {
273
+ background: #ffffff;
274
+ border-left: 1px solid #ccc;
275
+ color: #bbb;
276
+ padding: 0 5px;
277
+ float: right;
278
+ text-decoration: none;
279
+ position: relative;
280
+ transition: color .2s ease-in-out;
281
+ }
282
+
283
+ .wpstg-remove-clone:hover {
284
+ color: #ef6d6d;
285
+ }
286
+
287
+ .wpstg-clone-action:last-child {
288
+ border: none;
289
+ }
290
+
291
+ .wpstg-clone:hover .wpstg-clone-action {
292
+ display: inline-block;
293
+ }
294
+
295
+ #wpstg-show-error-details:focus,
296
+ #wpstg-workflow .wpstg-clone-action {
297
+ outline: none;
298
+ box-shadow: none;
299
+ }
300
+
301
+ .wpstg-link-btn {
302
+ background: #45a1c9;
303
+ color: #fff;
304
+ display: inline-block;
305
+ padding: 5px 10px;
306
+ text-decoration: none;
307
+ vertical-align: baseline;
308
+ transition: all .2s ease-in-out;
309
+ }
310
+
311
+ .wpstg-link-btn:hover,
312
+ .wpstg-link-btn:focus {
313
+ color: #fff;
314
+ outline: none;
315
+ box-shadow: none;
316
+ }
317
+
318
+ #wpstg-workflow .wpstg-link-btn:active {
319
+ vertical-align: baseline;
320
+ }
321
+
322
+ .wpstg-link-btn[disabled] {
323
+ background: #777 !important;
324
+ pointer-events: none;
325
+ }
326
+
327
+ #wpstg-cancel-cloning {
328
+ background: #ff3428;
329
+ border-color: #e72f24;
330
+ margin-top: 5px;
331
+ }
332
+
333
+ #wpstg-cancel-cloning.success {
334
+ background: #64dd58;
335
+ border-color: #54bd4a;
336
+ }
337
+
338
+ #wpstg-error-wrapper,
339
+ #wpstg-error-details {
340
+ display: none;
341
+ margin-top: 10px;
342
+ font-size: 13px;
343
+ }
344
+
345
+ #wpstg-show-error-details {
346
+ display: inline-block;
347
+ margin-left: 5px;
348
+ color: #555;
349
+ text-decoration: none;
350
+ transition: color .2s ease-in-out;
351
+ }
352
+
353
+ #wpstg-show-error-details:hover {
354
+ color: #1d94cf;
355
+ }
356
+
357
+ #wpstg-error-details {
358
+ border-left: 5px solid #ef6d6d;
359
+ padding: 10px;
360
+ width: 500px;
361
+ }
362
+
363
+ #wpstg-home-link,
364
+ #wpstg-try-again {
365
+ display: none;
366
+ }
367
+
368
+
369
+ #wpstg-loader {
370
+ content: url('../img/loading.gif');
371
+ margin-top:-5px;
372
+ }
373
+
374
+ #wpstg-loader.wpstg-finished {
375
+ content:"Finished";
376
+ background-color:#00c89a;
377
+ color:white;
378
+ padding:2px;
379
+ margin-top:6px;
380
+ }
381
+
382
+ #wpstg-workflow {
383
+ position: relative;
384
+ clear:both;
385
+ padding-top:20px;
386
+ margin-right:20px;
387
+ float:left;
388
+ min-width: 500px;
389
+ border-right: 1px solid #DFDFDF;
390
+ min-height: 380px;
391
+ padding-right: 20px;
392
+ }
393
+
394
+ #wpstg-sidebar {
395
+ float: left;
396
+ max-width: 400px;
397
+ display: block;
398
+ }
399
+
400
+ @media screen and (max-width:1150px){
401
+ #wpstg-sidebar img{
402
+ margin-top: 30px;
403
+ }
404
+ }
405
+
406
+ #wpstg-workflow.loading::after,
407
+ #wpstg-removing-clone.loading::after {
408
+ background: rgba(255, 255, 255, .7);
409
+ content: 'Loading... may take a while for huge websites';
410
+ display: block;
411
+ width: 100%;
412
+ height: 100%;
413
+ font-size: 20px;
414
+ padding-top: 100px;
415
+ text-align: center;
416
+ position: absolute;
417
+ top: 0;
418
+ left: 0;
419
+ z-index: 99;
420
+ }
421
+
422
+ #wpstg-removing-clone.loading::after {
423
+ content: 'REMOVING' !important;
424
+ }
425
+
426
+ #wpstg-existing-clones,
427
+ #wpstg-removing-clone {
428
+ position: relative;
429
+ }
430
+
431
+ .wpstg-progress-bar {
432
+ max-width: 900px;
433
+ height: 27px;
434
+ padding: 0;
435
+ background-color: #d6d8d7;
436
+ }
437
+
438
+ .wpstg-progress {
439
+ background: #1d94cf;
440
+ width: 0;
441
+ height: 100%;
442
+ transition: width 1s;
443
+ color:white;
444
+ line-height:25px;
445
+ text-align:center;
446
+ }
447
+
448
+ #wpstg-new-clone-id.wpstg-error-input,
449
+ #wpstg-clone-path.wpstg-error-input {
450
+ border: 1px solid #ff4235;
451
+ box-shadow: 0 0 2px rgba(255, 66, 53, .8);
452
+ }
453
+
454
+ #wpstg-clone-path {
455
+ margin-left: 10px;
456
+ width: 350px;
457
+ }
458
+
459
+ .wpstg-error-msg {
460
+ color: #ff4235;
461
+ }
462
+
463
+ #wpstg-clone-id-error {
464
+ display: block;
465
+ text-align: right;
466
+ margin-right: 90px;
467
+ }
468
+
469
+ #wpstg-start-cloning + .wpstg-error-msg {
470
+ display: block;
471
+ margin-top: 5px;
472
+ }
473
+
474
+ .wpstg-size-info {
475
+ color: #999;
476
+ font-weight: normal;
477
+ position: relative;
478
+ left: 2px;
479
+ }
480
+
481
+ .wpstg-db-table .wpstg-size-info {
482
+ top: 2px;
483
+ }
484
+
485
+ #wpstg-workflow #wpstg-start-cloning {
486
+ display: inline-block;
487
+ margin-left: 5px;
488
+ font-size: 14px;
489
+ vertical-align: baseline;
490
+ }
491
+
492
+ /* Tabs */
493
+ .wpstg-tabs-wrapper {
494
+ max-width: 640px;
495
+ margin: 10px 0;
496
+ }
497
+
498
+ #wpstg-path-wrapper {
499
+ border-bottom: 2px dashed #ccc;
500
+ padding-bottom: 10px;
501
+ margin-bottom: 10px;
502
+ }
503
+
504
+ .wpstg-tabs-wrapper {
505
+ border: 1px solid #ddd;
506
+ border-right: none;
507
+ border-left: none;
508
+ }
509
+
510
+ .wpstg-tab-section {
511
+ border: 1px solid #ddd;
512
+ border-right: none;
513
+ border-left: none;
514
+ display: none;
515
+ padding: 20px;
516
+ }
517
+
518
+ .wpstg-tab-section::after {
519
+ display: block;
520
+ content: '';
521
+ clear: both;
522
+ }
523
+
524
+ .wpstg-tab-header {
525
+ border: 1px solid #ddd;
526
+ border-right: none;
527
+ border-left: none;
528
+ color: #444;
529
+ font-size: 16px;
530
+ font-weight: bolder;
531
+ display: block;
532
+ padding: 10px;;
533
+ text-decoration: none;
534
+ }
535
+
536
+ .wpstg-tab-triangle {
537
+ font-family: arial;
538
+ display: inline-block;
539
+ margin-right: 10px;
540
+ }
541
+
542
+ .wpstg-tab-header:focus {
543
+ color: #444;
544
+ outline: none;
545
+ box-shadow: none;
546
+ }
547
+
548
+ #wpstg-large-files {
549
+ display:none;
550
+ border: 1px dashed #ccc;
551
+ /*float: right;*/
552
+ padding: 10px 10px 10px;
553
+ margin-top:20px;
554
+ position: relative;
555
+ font-size:12px;
556
+ }
557
+
558
+ #wpstg-large-files h3 {
559
+ background: #fff;
560
+ margin: 0;
561
+ padding: 0 5px;
562
+ position: absolute;
563
+ top: -10px;
564
+ left: 5px;
565
+ }
566
+
567
+ /* tmp */
568
+ .wpstg-subdir {
569
+ display: none;
570
+ margin-left: 20px;
571
+ }
572
+
573
+ .wpstg-dir a.disabled {
574
+ color: #888;
575
+ cursor: default;
576
+ text-decoration: none;
577
+ }
578
+
579
+ .wpstg-check-subdirs {
580
+ display: inline-block;
581
+ margin-left: 10px;
582
+ }
583
+
584
+ .wpstg-notice-alert{
585
+ display:block;
586
+ background-color:#FFD0D0;
587
+ padding:20px;
588
+ border: 1px solid #fff;
589
+ max-width: 600px;
590
+ }
591
+
592
+ .wpstg-header{
593
+ font-weight: 400;
594
+ line-height: 1.6em;
595
+ font-size: 19px;
596
+ border-bottom: 1px solid #DFDFDF;
597
+ clear:both;
598
+ }
599
+
600
+
601
+ #wpstg-clone-label{
602
+ font-size: 14px;
603
+ font-weight: bold;
604
+ }
605
+
606
+ #wpstg-log-details{
607
+ height: 300px;
608
+ max-width: 700px;
609
+ overflow: scroll;
610
+ /*max-width: 650px;*/
611
+ font-family: monospace;
612
+ font-size: 12px;
613
+ line-height: 15px;
614
+ border: 1px solid #FFF;
615
+ background-color: black;
616
+ color: #c0c0c0;
617
+ padding:3px;
618
+ white-space: nowrap;
619
+ margin-top: 15px;
620
+ }
621
+
622
+ #wpstg-finished-result {
623
+ display:none;
624
+ }
625
+
626
+ #wpstg-remove-cloning {
627
+ background: #ff3428;
628
+ border-color: #e72f24;
629
+ margin-top: 5px;
630
+ }
631
+
632
+ #wpstg-success-notice{
633
+ padding: 10px;
634
+ background-color: white;
635
+ max-width: 900px;
636
+ border: 1px solid #ccc;
637
+ margin-top: 20px;
638
+ }
639
+
640
+ .wpstg_beta_notice {
641
+ margin-bottom:20px;
642
+ }
643
+
644
+ .wpstg-sysinfo {
645
+ width:700px;
646
+ height: 500px;
647
+ }
648
+
649
+ .form-table .col-title label {
650
+ font-weight: 600;
651
+ }
652
+
653
+ .form-table td:first-child {
654
+ width:30%;
655
+ }
656
+
657
+
658
+ .wpstg-share-button-container{
659
+ margin: 5px 0;
660
+ }
661
+
662
+ .wpstg-share-button-container p{
663
+ margin:0px 0 10px 0;
664
+ }
665
+
666
+ .wpstg-share-button {
667
+ display: inline-block;
668
+ }
669
+
670
+ .wpstg-share-button a{
671
+ text-decoration:none;
672
+ }
673
+
674
+ .wpstg-share-button .wpstg-share {
675
+ font-family:sans-serif;
676
+ font-weight:bold;
677
+ text-decoration:none;
678
+ text-align:center;
679
+ }
680
+
681
+
682
+ .wpstg-share-button .wpstg-share {
683
+ -webkit-border-radius:2px;
684
+ -moz-border-radius:2px;
685
+ border-radius:2px;
686
+ color:#FFF;
687
+ display:inline;
688
+ font-size:16px;
689
+ width:40px;
690
+ padding:4px 8px;
691
+ }
692
+
693
+ .wpstg-share-button-twitter .wpstg-share {
694
+ background-color:#00ABF0;
695
+ }
696
+
697
+ .wpstg-share-button-facebook .wpstg-share {
698
+ background-color:#3b5998;
699
+ }
700
+
701
+ .wpstg-share-button-googleplus .wpstg-share {
702
+ background-color:#F53424;
703
+ }
704
+
705
+ .wpstg-share-button-twitter .share:active,.wpstg-share-button-facebook .share:active,.wpstg-share-button-googleplus .share:active {
706
+ background-color:#353535;
707
+ }
708
+
709
+ #wpstg-check-space {
710
+ margin-left:8px;
711
+ }
712
+
713
+ /* welcome screen */
714
+ .wpstg-button.green {
715
+ display: inline-block;
716
+ background-color: #83c11f;
717
+ padding: 10px;
718
+ min-width: 170px;
719
+ color: white;
720
+ font-size: 16px;
721
+ text-decoration: none;
722
+ text-align: center;
723
+ margin-top: 20px;
724
+ }
725
+ #wpstg-welcome li {
726
+ font-size: 18px;
727
+ line-height: 29px;
728
+ position: relative;
729
+ padding-left: 23px;
730
+ list-style: none!important;
731
+ }
732
+ #wpstg-welcome {
733
+ margin-top:20px;
734
+ margin-right: 20px;
735
+ background-color: white;
736
+ }
737
+ .wpstg-heading-pro {
738
+ color: #0080ff;
739
+ font-weight: bold;
740
+ }
741
+ .wpstg-h2 {
742
+ margin-top: 0px;
743
+ margin-bottom: 1.2rem;
744
+ font-size: 30px;
745
+ line-height: 2.5rem;
746
+ }
747
+ #wpstg-welcome li:before {
748
+ width: 1em;
749
+ height: 100%;
750
+ background: url(data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%221792%22%20height%3D%221792%22%20viewBox%3D%220%200%201792%201792%22%20xmlns%3D%22http%3A%2F%2Fwww%2Ew3%2Eorg%2F2000%2Fsvg%22%3E%3Cpath%20fill%3D%22%2377B227%22%20d%3D%22M1671%20566q0%2040%2D28%2068l%2D724%20724%2D136%20136q%2D28%2028%2D68%2028t%2D68%2D28l%2D136%2D136%2D362%2D362q%2D28%2D28%2D28%2D68t28%2D68l136%2D136q28%2D28%2068%2D28t68%2028l294%20295%20656%2D657q28%2D28%2068%2D28t68%2028l136%20136q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) left .4em no-repeat;
751
+ background-size: contain;
752
+ content: "";
753
+ position: absolute;
754
+ top: 0;
755
+ left: 0;
756
+ color: #77b227;
757
+ }
758
+ .wpstg-h1 {
759
+ font-size: 2.75em;
760
+ margin-bottom: 1.35rem;
761
+ font-size: 2.5em;
762
+ line-height: 3.68rem;
763
+ letter-spacing: normal;
764
+ }
765
+ #wpstg-welcome h2 {
766
+ margin: 0 0 15px;
767
+ }
768
+ #wpstg-welcome .wpstg-footer {
769
+ clear: both;
770
+ margin-top: 20px;
771
+ font-style: italic;
772
+ }
773
+
774
+ .wpstg-staging-info {
775
+ clear:both;
776
+ float: right;
777
+ color:grey;
778
+ font-size: 12px;
779
+ }
780
+
781
+ .wpstg-bold{
782
+ font-weight: 600;
783
  }
apps/Backend/public/js/wpstg-admin.js CHANGED
@@ -1,1086 +1,1252 @@
1
- "use strict";
2
-
3
- var WPStaging = (function ($)
4
- {
5
- var that = {
6
- isCancelled: false,
7
- isFinished: false,
8
- getLogs: false
9
- },
10
- cache = {elements: []},
11
- timeout, ajaxSpinner;
12
- ajaxurl = ("undefined" !== typeof wpstg.ajaxurl) ? wpstg.ajaxurl : ajaxurl;
13
-
14
- /**
15
- * Get / Set Cache for Selector
16
- * @param {String} selector
17
- * @returns {*}
18
- */
19
- cache.get = function (selector)
20
- {
21
- // It is already cached!
22
- if ($.inArray(selector, cache.elements) !== -1)
23
- {
24
- return cache.elements[selector];
25
- }
26
-
27
- // Create cache and return
28
- cache.elements[selector] = jQuery(selector);
29
-
30
- return cache.elements[selector];
31
- };
32
-
33
- /**
34
- * Refreshes given cache
35
- * @param {String} selector
36
- */
37
- cache.refresh = function (selector)
38
- {
39
- selector.elements[selector] = jQuery(selector);
40
- };
41
-
42
- /**
43
- * Show and Log Error Message
44
- * @param {String} message
45
- */
46
- var showError = function (message)
47
- {
48
- cache.get("#wpstg-try-again").css("display", "inline-block");
49
- cache.get("#wpstg-cancel-cloning").text("Reset");
50
- cache.get("#wpstg-cloning-result").text("Fail");
51
- cache.get("#wpstg-error-wrapper").show();
52
- cache.get("#wpstg-error-details")
53
- .show()
54
- .html(message);
55
-
56
- cache.get("#wpstg-loader").hide();
57
- };
58
-
59
- /**
60
- * Common Elements
61
- */
62
- var elements = function ()
63
- {
64
- var $workFlow = cache.get("#wpstg-workflow"),
65
- isAllChecked = true,
66
- urlSpinner = ajaxurl.replace("/admin-ajax.php", '') + "/images/spinner",
67
- timer;
68
-
69
- if (2 < window.devicePixelRatio)
70
- {
71
- urlSpinner += "-2x";
72
- }
73
-
74
- urlSpinner += ".gif";
75
-
76
- ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
77
-
78
- $workFlow
79
- // Check / Un-check Database Tables
80
- .on("click", ".wpstg-button-unselect", function (e) {
81
- e.preventDefault();
82
-
83
- if (false === isAllChecked)
84
- {
85
- cache.get(".wpstg-db-table-checkboxes").prop("checked", true);
86
- cache.get(".wpstg-button-unselect").text("Un-check All");
87
- isAllChecked = true;
88
- }
89
- else
90
- {
91
- cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
92
- cache.get(".wpstg-button-unselect").text("Check All");
93
- isAllChecked = false;
94
- }
95
- })
96
- // Expand Directories
97
- .on("click", ".wpstg-expand-dirs", function (e) {
98
- e.preventDefault();
99
-
100
- var $this = $(this);
101
-
102
- if (!$this.hasClass("disabled"))
103
- {
104
- $this.siblings(".wpstg-subdir").slideToggle();
105
- }
106
- })
107
- // When a Directory is Selected
108
- .on("change", ".wpstg-check-dir", function () {
109
- var $directory = $(this).parent(".wpstg-dir");
110
-
111
- if (this.checked)
112
- {
113
- $directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
114
- $directory.find(".wpstg-expand-dirs").removeClass("disabled");
115
- $directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
116
- }
117
- else
118
- {
119
- $directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
120
- $directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
121
- $directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
122
- $directory.children(".wpstg-subdir").slideUp();
123
- }
124
- })
125
- // Check the max length of the clone name and if the clone name already exists
126
- .on("keyup", "#wpstg-new-clone-id", function () {
127
-
128
- // This request was already sent, clear it up!
129
- if ("number" === typeof (timer))
130
- {
131
- clearInterval(timer);
132
- }
133
-
134
- var cloneID = this.value;
135
-
136
- timer = setTimeout(
137
- function () {
138
- ajax(
139
- {
140
- action: "wpstg_check_clone",
141
- cloneID: cloneID
142
- },
143
- function (response)
144
- {
145
- if (response.status === "success")
146
- {
147
- cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
148
- cache.get("#wpstg-start-cloning").removeAttr("disabled");
149
- cache.get("#wpstg-clone-id-error").text('').hide();
150
- }
151
- else
152
- {
153
- cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
154
- cache.get("#wpstg-start-cloning").prop("disabled", true);
155
- cache.get("#wpstg-clone-id-error").text(response.message).show();
156
- }
157
- }
158
- );
159
- },
160
- 500
161
- );
162
- })
163
- // Restart cloning process
164
- .on("click", "#wpstg-start-cloning", function () {
165
- that.isCancelled = false;
166
- that.getLogs = false;
167
- })
168
- // Display logs
169
- .on("click", "#wpstg-show-log-button", function (e) {
170
- e.preventDefault();
171
- var $logDetails = cache.get("#wpstg-log-details");
172
-
173
- $logDetails.toggle();
174
-
175
- logscroll();
176
-
177
- that.getLogs = (false === that.getLogs);
178
- });
179
-
180
- cloneActions();
181
- };
182
-
183
-
184
- /**
185
- * Clone actions
186
- */
187
- var cloneActions = function ()
188
- {
189
- var $workFlow = cache.get("#wpstg-workflow");
190
-
191
- $workFlow
192
- // Cancel cloning
193
- .on("click", "#wpstg-cancel-cloning", function () {
194
- if (!confirm("Are you sure you want to cancel cloning process?"))
195
- {
196
- return false;
197
- }
198
-
199
- var $this = $(this);
200
-
201
- $("#wpstg-try-again, #wpstg-home-link").hide();
202
- $this.prop("disabled", true);
203
-
204
- that.isCancelled = true;
205
-
206
- $("#wpstg-cloning-result").text("Please wait...this can take up a while.");
207
- $("#wpstg-loader, #wpstg-show-log-button").hide();
208
-
209
- $this.parent().append(ajaxSpinner);
210
-
211
- cancelCloning();
212
- })
213
- // Delete clone - confirmation
214
- .on("click", ".wpstg-remove-clone[data-clone]", function (e) {
215
- e.preventDefault();
216
-
217
- var $existingClones = cache.get("#wpstg-existing-clones");
218
-
219
- $workFlow.removeClass('active');
220
-
221
- cache.get("#wpstg-loader").show();
222
-
223
- ajax(
224
- {
225
- action: "wpstg_confirm_delete_clone",
226
- nonce: wpstg.nonce,
227
- clone: $(this).data("clone")
228
- },
229
- function (response)
230
- {
231
- cache.get("#wpstg-removing-clone").html(response);
232
-
233
- $existingClones.children("img").remove();
234
-
235
- cache.get("#wpstg-loader").hide();
236
- },
237
- "HTML"
238
- );
239
- })
240
- // Delete clone - confirmed
241
- .on("click", "#wpstg-remove-clone", function (e) {
242
- e.preventDefault();
243
-
244
- cache.get("#wpstg-removing-clone").addClass("loading");
245
-
246
- cache.get("#wpstg-loader").show();
247
-
248
- deleteClone($(this).data("clone"));
249
- })
250
- // Cancel deleting clone
251
- .on("click", "#wpstg-cancel-removing", function (e) {
252
- e.preventDefault();
253
- $(".wpstg-clone").removeClass("active");
254
- cache.get("#wpstg-removing-clone").html('');
255
- })
256
- // Edit
257
- .on("click", ".wpstg-execute-clone", function (e) {
258
- e.preventDefault();
259
-
260
- var clone = $(this).data("clone");
261
-
262
- $workFlow.addClass("loading");
263
-
264
- ajax(
265
- {
266
- action: "wpstg_scanning",
267
- clone: clone,
268
- nonce: wpstg.nonce
269
- },
270
- function (response)
271
- {
272
- if (response.length < 1)
273
- {
274
- showError("Something went wrong, please try again");
275
- }
276
-
277
- $workFlow.removeClass("loading").html(response);
278
-
279
- cache.get(".wpstg-current-step")
280
- .removeClass("wpstg-current-step")
281
- .next("li")
282
- .addClass("wpstg-current-step");
283
- },
284
- "HTML"
285
- );
286
- });
287
- };
288
-
289
- /**
290
- * Ajax Requests
291
- * @param {Object} data
292
- * @param {Function} callback
293
- * @param {String} dataType
294
- * @param {Boolean} showErrors
295
- */
296
- var ajax = function (data, callback, dataType, showErrors)
297
- {
298
- if ("undefined" === typeof (dataType))
299
- {
300
- dataType = "json";
301
- }
302
-
303
- if (false !== showErrors)
304
- {
305
- showErrors = true;
306
- }
307
-
308
- $.ajax({
309
- url: ajaxurl,
310
- type: "POST",
311
- dataType: dataType,
312
- cache: false,
313
- data: data,
314
- error: function (xhr, textStatus, errorThrown) {
315
- console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
316
- console.log(textStatus);
317
-
318
- if (false === showErrors)
319
- {
320
- return false;
321
- }
322
-
323
- showError(
324
- "Fatal Unknown Error. Go to WP Staging > Settings and lower 'File Copy Limit'" +
325
- "Than try again. If this does not help, " +
326
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
327
- );
328
- },
329
- success: function (data) {
330
- if ("function" === typeof (callback))
331
- {
332
- callback(data);
333
- }
334
- },
335
- statusCode: {
336
- 404: function () {
337
- showError("Something went wrong; can't find ajax request URL!");
338
- },
339
- 500: function () {
340
- showError("Something went wrong; internal server error while processing the request!");
341
- }
342
- }
343
- });
344
- };
345
-
346
- /**
347
- * Next / Previous Step Clicks to Navigate Through Staging Job
348
- */
349
- var stepButtons = function ()
350
- {
351
- var $workFlow = cache.get("#wpstg-workflow");
352
-
353
- $workFlow
354
- // Next Button
355
- .on("click", ".wpstg-next-step-link", function (e) {
356
- e.preventDefault();
357
-
358
- var $this = $(this),
359
- isScan = false;
360
-
361
- // Button is disabled
362
- if ($this.attr("disabled"))
363
- {
364
- return false;
365
- }
366
-
367
- // Add loading overlay
368
- $workFlow.addClass("loading");
369
-
370
- // Prepare data
371
- that.data = {
372
- action: $this.data("action"),
373
- nonce: wpstg.nonce
374
- };
375
-
376
- // Cloning data
377
- getCloningData();
378
-
379
- console.log(that.data);
380
-
381
- isScan = ("wpstg_scanning" === that.action);
382
-
383
- // Send ajax request
384
- ajax(
385
- that.data,
386
- function (response) {
387
-
388
- if (response.length < 1)
389
- {
390
- showError("Something went wrong, please try again");
391
- }
392
-
393
- // Styling of elements
394
- $workFlow.removeClass("loading").html(response);
395
-
396
- cache.get(".wpstg-current-step")
397
- .removeClass("wpstg-current-step")
398
- .next("li")
399
- .addClass("wpstg-current-step");
400
-
401
- // Start cloning
402
- that.startCloning();
403
- },
404
- "HTML"
405
- );
406
- })
407
- // Previous Button
408
- .on("click", ".wpstg-prev-step-link", function (e) {
409
- e.preventDefault();
410
- loadOverview();
411
- });
412
- };
413
-
414
- /**
415
- * Get Excluded (Unchecked) Database Tables
416
- * @returns {Array}
417
- */
418
- var getExcludedTables = function ()
419
- {
420
- var excludedTables = [];
421
-
422
- $(".wpstg-db-table input:not(:checked)").each(function () {
423
- excludedTables.push(this.name);
424
- });
425
-
426
- return excludedTables;
427
- };
428
-
429
- /**
430
- * Get Included Directories
431
- * @returns {Array}
432
- */
433
- var getIncludedDirectories = function ()
434
- {
435
- var includedDirectories = [];
436
-
437
- $(".wpstg-dir input:checked").each(function () {
438
- var $this = $(this);
439
- if (!$this.parent(".wpstg-dir").parents(".wpstg-dir").children(".wpstg-expand-dirs").hasClass("disabled"))
440
- {
441
- includedDirectories.push($this.val());
442
- }
443
- });
444
-
445
- return includedDirectories;
446
- };
447
-
448
- /**
449
- * Get Excluded Directories
450
- * @returns {Array}
451
- */
452
- var getExcludedDirectories = function ()
453
- {
454
- var excludedDirectories = [];
455
-
456
- $(".wpstg-dir input:not(:checked)").each(function () {
457
- var $this = $(this);
458
- if (!$this.parent(".wpstg-dir").parents(".wpstg-dir").children(".wpstg-expand-dirs").hasClass("disabled"))
459
- {
460
- excludedDirectories.push($this.val());
461
- }
462
- });
463
-
464
- return excludedDirectories;
465
- };
466
-
467
- /**
468
- * Get Included Extra Directories
469
- * @returns {Array}
470
- */
471
- var getIncludedExtraDirectories = function ()
472
- {
473
- var extraDirectories = [];
474
-
475
- if (!$("#wpstg_extraDirectories").val()) {
476
- return extraDirectories;
477
- }
478
-
479
- var extraDirectories = $("#wpstg_extraDirectories").val().split(/\r?\n/);
480
- console.log(extraDirectories);
481
-
482
- //excludedDirectories.push($this.val());
483
-
484
- return extraDirectories;
485
- };
486
-
487
-
488
-
489
- /**
490
- * Get Cloning Step Data
491
- */
492
- var getCloningData = function ()
493
- {
494
- if ("wpstg_cloning" !== that.data.action)
495
- {
496
- return;
497
- }
498
-
499
- that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
500
- that.data.excludedTables = getExcludedTables();
501
- that.data.includedDirectories = getIncludedDirectories();
502
- that.data.excludedDirectories = getExcludedDirectories();
503
- //that.data.extraDirectories = $("#wpstg_extraDirectories").val() || null;
504
- that.data.extraDirectories = getIncludedExtraDirectories();
505
- console.log(that.data);
506
-
507
- };
508
-
509
- /**
510
- * Loads Overview (first step) of Staging Job
511
- */
512
- var loadOverview = function ()
513
- {
514
- var $workFlow = cache.get("#wpstg-workflow");
515
-
516
- $workFlow.addClass("loading");
517
-
518
- ajax(
519
- {
520
- action: "wpstg_overview",
521
- nonce: wpstg.nonce
522
- },
523
- function (response) {
524
-
525
- if (response.length < 1)
526
- {
527
- showError("Something went wrong, please try again");
528
- }
529
-
530
- var $currentStep = cache.get(".wpstg-current-step");
531
-
532
- // Styling of elements
533
- $workFlow.removeClass("loading").html(response);
534
-
535
- },
536
- "HTML"
537
- );
538
- };
539
-
540
- /**
541
- * Tabs
542
- */
543
- var tabs = function ()
544
- {
545
- cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function (e) {
546
- e.preventDefault();
547
-
548
- var $this = $(this),
549
- $section = cache.get($this.data("id"));
550
-
551
- $this.toggleClass("expand");
552
-
553
- $section.slideToggle();
554
-
555
- if ($this.hasClass("expand"))
556
- {
557
- $this.find(".wpstg-tab-triangle").html("&#9660;");
558
- }
559
- else
560
- {
561
- $this.find(".wpstg-tab-triangle").html("&#9658;");
562
- }
563
- });
564
- };
565
-
566
- /**
567
- * Delete Clone
568
- * @param {String} clone
569
- */
570
- var deleteClone = function (clone)
571
- {
572
-
573
- ajax(
574
- {
575
- action: "wpstg_delete_clone",
576
- clone: clone,
577
- nonce: wpstg.nonce,
578
- excludedTables: getExcludedTables(),
579
- deleteDir: $("#deleteDirectory:checked").val()
580
- },
581
- function (response)
582
- {
583
- if (response) {
584
- if ("undefined" !== typeof response.delete && response.delete === 'finished') {
585
-
586
- cache.get("#wpstg-removing-clone").removeClass("loading").html('');
587
- $(".wpstg-clone#" + clone).remove();
588
-
589
- if ($(".wpstg-clone").length < 1)
590
- {
591
- cache.get("#wpstg-existing-clones").find("h3").text('');
592
- }
593
-
594
- cache.get("#wpstg-loader").hide();
595
- return;
596
- }
597
- }
598
- // continue
599
- if (true !== response)
600
- {
601
- deleteClone(clone);
602
- return;
603
- }
604
-
605
- }
606
- );
607
- };
608
-
609
- /**
610
- * Cancel Cloning Process
611
- */
612
- var cancelCloning = function ()
613
- {
614
- if (true === that.isFinished)
615
- {
616
- return true;
617
- }
618
-
619
- ajax(
620
- {
621
- action: "wpstg_cancel_clone",
622
- clone: that.data.cloneID,
623
- nonce: wpstg.nonce
624
- },
625
- function (response)
626
- {
627
-
628
-
629
- if( response && "undefined" !== typeof(response.delete) && response.delete === "finished"){
630
- // Load overview
631
- loadOverview();
632
- return;
633
- }
634
-
635
- if (true !== response)
636
- {
637
- // continue
638
- cancelCloning();
639
- return;
640
- }
641
-
642
- // Load overview
643
- loadOverview();
644
- }
645
- );
646
- };
647
-
648
- /**
649
- * Scroll the window log to bottom
650
- * @returns void
651
- */
652
- var logscroll = function () {
653
- var $div = cache.get("#wpstg-log-details");
654
- if ("undefined" !== typeof ($div[0])) {
655
- $div.scrollTop($div[0].scrollHeight);
656
- }
657
- }
658
-
659
- /**
660
- * Append the log to the logging window
661
- * @param string log
662
- * @returns void
663
- */
664
- var getLogs = function (log)
665
- {
666
- if (log != null && "undefined" !== typeof (log)) {
667
- if (log.constructor === Array) {
668
- $.each(log, function (index, value) {
669
- if (value === null){
670
- return;
671
- }
672
- if (value.type === 'ERROR'){
673
- cache.get("#wpstg-log-details").append('<span style="color:red;">[' + value.type + ']</span>-'+ '[' + value.date + '] ' + value.message + '</br>');
674
- } else {
675
- cache.get("#wpstg-log-details").append('[' + value.type + ']-'+ '[' + value.date + '] ' + value.message + '</br>');
676
- }
677
- })
678
- } else {
679
- cache.get("#wpstg-log-details").append('[' + log.type + ']-' + '[' + log.date + '] ' + log.message + '</br>');
680
- }
681
- }
682
- logscroll();
683
-
684
- };
685
-
686
- /**
687
- * Optimizer
688
- */
689
- var optimizer = function ()
690
- {
691
- var $optimizer = cache.get('input[name="wpstg_settings\[optimizer\]"]');
692
-
693
- // On load
694
- optimizerAction($optimizer.is(':checked'));
695
-
696
- // On action
697
- $optimizer.on('change', function () {
698
- optimizerAction(this.checked);
699
- });
700
-
701
- function optimizerAction(isChecked)
702
- {
703
- if (false === isChecked)
704
- {
705
- cache.get('#wpstg_pluginListing').hide();
706
- return false;
707
- }
708
-
709
- cache.get('#wpstg_pluginListing').show();
710
- }
711
- };
712
-
713
- var checkDiskSpace = function () {
714
- cache.get("#wpstg-check-space").on("click", function (e) {
715
- cache.get("#wpstg-loader").show();
716
- console.log("check disk space");
717
- ajax(
718
- {
719
- action: "wpstg_check_disk_space",
720
- nonce: wpstg.nonce
721
- },
722
- function (response)
723
- {
724
- if (false === response)
725
- {
726
- cache.get("#wpstg-clone-id-error").text('Can not detect disk space').show();
727
- cache.get("#wpstg-loader").hide();
728
- return;
729
- }
730
-
731
- // Not enough disk space
732
- cache.get("#wpstg-clone-id-error").text('Available free disk space ' + response.freespace + ' | Estimated necessary disk space: ' + response.usedspace).show();
733
- cache.get("#wpstg-loader").hide();
734
- },
735
- "json",
736
- false
737
- );
738
- });
739
-
740
- }
741
-
742
- /**
743
- * Start Cloning Process
744
- * @type {Function}
745
- */
746
- that.startCloning = (function () {
747
-
748
- // Register function for checking disk space
749
- checkDiskSpace();
750
-
751
- if ("wpstg_cloning" !== that.data.action)
752
- {
753
- return;
754
- }
755
-
756
- // Start the process
757
- start();
758
-
759
- // Functions
760
- // Start
761
- function start()
762
- {
763
- console.log("Starting cloning process...");
764
-
765
- cache.get("#wpstg-loader").show();
766
-
767
- // Clone Database
768
- setTimeout(function () {
769
- cloneDatabase();
770
- }, wpstg.cpuLoad);
771
- }
772
-
773
- // Step 1: Clone Database
774
- function cloneDatabase()
775
- {
776
- if (true === that.isCancelled)
777
- {
778
- return false;
779
- }
780
-
781
- if (true === that.getLogs)
782
- {
783
- getLogs();
784
- }
785
-
786
- setTimeout(
787
- function () {
788
- ajax(
789
- {
790
- action: "wpstg_clone_database",
791
- nonce: wpstg.nonce
792
- },
793
- function (response) {
794
- // Add percentage
795
- if ("undefined" !== typeof (response.percentage))
796
- {
797
- cache.get("#wpstg-db-progress").width(response.percentage + '%');
798
- }
799
- // Add Log
800
- if ("undefined" !== typeof (response.last_msg))
801
- {
802
- getLogs(response.last_msg);
803
- }
804
-
805
- // Continue clone DB
806
- if (false === response.status)
807
- {
808
- setTimeout(function () {
809
- cloneDatabase();
810
- }, wpstg.cpuLoad);
811
- }
812
- // Next Step
813
- else if (true === response.status)
814
- {
815
- //console.log('prepareDirectories ' + response.status);
816
- setTimeout(function () {
817
- prepareDirectories();
818
- }, wpstg.cpuLoad);
819
- }
820
- }
821
- );
822
- },
823
- 500
824
- );
825
- }
826
-
827
- // Step 2: Prepare Directories
828
- function prepareDirectories()
829
- {
830
- if (true === that.isCancelled)
831
- {
832
- return false;
833
- }
834
-
835
- if (true === that.getLogs)
836
- {
837
- getLogs();
838
- }
839
-
840
- setTimeout(
841
- function () {
842
- ajax(
843
- {
844
- action: "wpstg_clone_prepare_directories",
845
- nonce: wpstg.nonce
846
- },
847
- function (response) {
848
- // Add percentage
849
- if ("undefined" !== typeof (response.percentage))
850
- {
851
- cache.get("#wpstg-directories-progress").width(response.percentage + '%');
852
- }
853
-
854
- // Add Log
855
- if ("undefined" !== typeof (response.last_msg))
856
- {
857
- getLogs(response.last_msg);
858
- }
859
-
860
- if (false === response.status)
861
- {
862
- setTimeout(function () {
863
- prepareDirectories();
864
- }, wpstg.cpuLoad);
865
- }
866
- else if (true === response.status)
867
- {
868
- console.log('prepareDirectories' + response.status);
869
- cloneFiles();
870
- }
871
- }
872
- );
873
- },
874
- 500
875
- );
876
- }
877
-
878
- // Step 3: Clone Files
879
- function cloneFiles()
880
- {
881
- if (true === that.isCancelled)
882
- {
883
- return false;
884
- }
885
-
886
- if (true === that.getLogs)
887
- {
888
- getLogs();
889
- }
890
-
891
- ajax(
892
- {
893
- action: "wpstg_clone_files",
894
- nonce: wpstg.nonce
895
- },
896
- function (response) {
897
- // Add percentage
898
- if ("undefined" !== typeof (response.percentage))
899
- {
900
- cache.get("#wpstg-files-progress").width(response.percentage + '%');
901
- }
902
-
903
- // Add Log
904
- if ("undefined" !== typeof (response.last_msg))
905
- {
906
- getLogs(response.last_msg);
907
- }
908
-
909
- if (false === response.status)
910
- {
911
- setTimeout(function () {
912
- cloneFiles();
913
- }, wpstg.cpuLoad);
914
- }
915
- else if (true === response.status)
916
- {
917
- setTimeout(function () {
918
- replaceData();
919
- }, wpstg.cpuLoad);
920
- }
921
- }
922
- );
923
- }
924
-
925
- // Step 4: Replace Data
926
- function replaceData()
927
- {
928
- if (true === that.isCancelled)
929
- {
930
- return false;
931
- }
932
-
933
- if (true === that.getLogs)
934
- {
935
- getLogs();
936
- }
937
-
938
- ajax(
939
- {
940
- action: "wpstg_clone_replace_data",
941
- nonce: wpstg.nonce
942
- },
943
- function (response) {
944
- // Add percentage
945
- if ("undefined" !== typeof (response.percentage))
946
- {
947
- cache.get("#wpstg-links-progress").width(response.percentage + '%');
948
- }
949
-
950
- // Add Log
951
- if ("undefined" !== typeof (response.last_msg))
952
- {
953
- getLogs(response.last_msg);
954
- }
955
-
956
- if (false === response.status)
957
- {
958
- setTimeout(function () {
959
- replaceData();
960
- }, wpstg.cpuLoad);
961
- }
962
- else if (true === response.status)
963
- {
964
- finish();
965
- }
966
- }
967
- );
968
- }
969
-
970
- // Finish
971
- function finish()
972
- {
973
- if (true === that.getLogs)
974
- {
975
- getLogs();
976
- }
977
-
978
- if (true === that.isCancelled || true === that.isFinished)
979
- {
980
- cache.get("#wpstg-loader").hide();
981
- return false;
982
- }
983
-
984
- ajax(
985
- {
986
- action: "wpstg_clone_finish",
987
- nonce: wpstg.nonce
988
- },
989
- function (response)
990
- {
991
- // Invalid response
992
- if ("object" !== typeof (response))
993
- {
994
- showError(
995
- "Couldn't finish the cloning process properly. " +
996
- "Your clone has been copied but failed to do clean up and " +
997
- "saving its records to the database." +
998
- "Please contact support and provide your logs."
999
- );
1000
-
1001
- return;
1002
- }
1003
-
1004
- console.log("Cloning process finished");
1005
-
1006
- var $link1 = cache.get("#wpstg-clone-url-1");
1007
- var $link = cache.get("#wpstg-clone-url");
1008
-
1009
- cache.get("#wpstg_staging_name").html(that.data.cloneID);
1010
- cache.get("#wpstg-finished-result").show();
1011
- cache.get("#wpstg-cancel-cloning").prop("disabled", true);
1012
- $link1.attr("href", $link1.attr("href") + '/' + response.directoryName);
1013
- $link1.append('/' + response.directoryName);
1014
- $link.attr("href", $link.attr("href") + '/' + response.directoryName);
1015
- cache.get("#wpstg-remove-clone").data("clone", that.data.cloneID);
1016
-
1017
- // Finished
1018
- that.isFinished = true;
1019
-
1020
- finish();
1021
- }
1022
- );
1023
- }
1024
- });
1025
-
1026
- // that.deleteClone = (function(clone) {
1027
- // if ("undefined" === typeof(clone))
1028
- // {
1029
- // alert("Couldn't detect clone to delete");
1030
- // return false;
1031
- // }
1032
- //
1033
- // ajax(
1034
- // {
1035
- // action : "wpstg_delete_clone",
1036
- // nonce : wpstg.nonce,
1037
- // data : {clone: clone}
1038
- // },
1039
- // function(response) {
1040
- //
1041
- // if (response.length < 1)
1042
- // {
1043
- // showError("Something went wrong, please try again");
1044
- // }
1045
- //
1046
- // var $currentStep = cache.get(".wpstg-current-step");
1047
- //
1048
- // // Styling of elements
1049
- // cache.get("#wpstg-workflow").removeClass("loading").html(response);
1050
- //
1051
- // $currentStep
1052
- // .removeClass("wpstg-current-step")
1053
- // .next("li")
1054
- // .addClass("wpstg-current-step");
1055
- // },
1056
- // "HTML"
1057
- // );
1058
- // });
1059
-
1060
- /**
1061
- * Initiation
1062
- * @type {Function}
1063
- */
1064
- that.init = (function () {
1065
- //console.log("Initiating WPStaging...");
1066
- loadOverview();
1067
- elements();
1068
- stepButtons();
1069
- tabs();
1070
- optimizer();
1071
- });
1072
-
1073
- /**
1074
- * Ajax call
1075
- * @type {ajax}
1076
- */
1077
- that.ajax = ajax;
1078
- that.showError = showError;
1079
- that.getLogs = getLogs;
1080
-
1081
- return that;
1082
- })(jQuery);
1083
-
1084
- jQuery(document).ready(function () {
1085
- WPStaging.init();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1086
  });
1
+ "use strict";
2
+
3
+ var WPStaging = (function ($)
4
+ {
5
+ var that = {
6
+ isCancelled: false,
7
+ isFinished: false,
8
+ getLogs: false
9
+ },
10
+ cache = {elements: []},
11
+ timeout, ajaxSpinner;
12
+
13
+ /**
14
+ * Get / Set Cache for Selector
15
+ * @param {String} selector
16
+ * @returns {*}
17
+ */
18
+ cache.get = function (selector)
19
+ {
20
+ // It is already cached!
21
+ if ($.inArray(selector, cache.elements) !== -1)
22
+ {
23
+ return cache.elements[selector];
24
+ }
25
+
26
+ // Create cache and return
27
+ cache.elements[selector] = jQuery(selector);
28
+
29
+ return cache.elements[selector];
30
+ };
31
+
32
+ /**
33
+ * Refreshes given cache
34
+ * @param {String} selector
35
+ */
36
+ cache.refresh = function (selector)
37
+ {
38
+ selector.elements[selector] = jQuery(selector);
39
+ };
40
+
41
+ /**
42
+ * Show and Log Error Message
43
+ * @param {String} message
44
+ */
45
+ var showError = function (message)
46
+ {
47
+ cache.get("#wpstg-try-again").css("display", "inline-block");
48
+ cache.get("#wpstg-cancel-cloning").text("Reset");
49
+ cache.get("#wpstg-cloning-result").text("Fail");
50
+ cache.get("#wpstg-error-wrapper").show();
51
+ cache.get("#wpstg-error-details")
52
+ .show()
53
+ .html(message);
54
+ cache.get("#wpstg-removing-clone").removeClass("loading");
55
+ cache.get("#wpstg-loader").hide();
56
+ };
57
+
58
+ /**
59
+ * Common Elements
60
+ */
61
+ var elements = function ()
62
+ {
63
+ var $workFlow = cache.get("#wpstg-workflow"),
64
+ isAllChecked = true,
65
+ urlSpinner = ajaxurl.replace("/admin-ajax.php", '') + "/images/spinner",
66
+ timer;
67
+
68
+ if (2 < window.devicePixelRatio)
69
+ {
70
+ urlSpinner += "-2x";
71
+ }
72
+
73
+ urlSpinner += ".gif";
74
+
75
+ ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
76
+
77
+ $workFlow
78
+ // Check / Un-check Database Tables
79
+ .on("click", ".wpstg-button-unselect", function (e) {
80
+ e.preventDefault();
81
+
82
+ if (false === isAllChecked)
83
+ {
84
+ cache.get(".wpstg-db-table-checkboxes").prop("checked", true);
85
+ cache.get(".wpstg-button-unselect").text("Un-check All");
86
+ isAllChecked = true;
87
+ }
88
+ else
89
+ {
90
+ cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
91
+ cache.get(".wpstg-button-unselect").text("Check All");
92
+ isAllChecked = false;
93
+ }
94
+ })
95
+ .on("click", ".wpstg-button-select", function (e) {
96
+ console.log('test1');
97
+
98
+ e.preventDefault();
99
+
100
+ $(".wpstg-db-table input").each(function () {
101
+ if ($(this).attr('name').match("^" + wpstg.tblprefix)) {
102
+ $(this).prop("checked", true);
103
+ } else {
104
+ $(this).prop("checked", false);
105
+
106
+ }
107
+ });
108
+ })
109
+ // Expand Directories
110
+ .on("click", ".wpstg-expand-dirs", function (e) {
111
+ e.preventDefault();
112
+
113
+ var $this = $(this);
114
+
115
+ if (!$this.hasClass("disabled"))
116
+ {
117
+ $this.siblings(".wpstg-subdir").slideToggle();
118
+ }
119
+ })
120
+ // When a Directory is Selected
121
+ .on("change", ".wpstg-check-dir", function () {
122
+ var $directory = $(this).parent(".wpstg-dir");
123
+
124
+ if (this.checked)
125
+ {
126
+ $directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
127
+ $directory.find(".wpstg-expand-dirs").removeClass("disabled");
128
+ $directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
129
+ }
130
+ else
131
+ {
132
+ $directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
133
+ $directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
134
+ $directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
135
+ $directory.children(".wpstg-subdir").slideUp();
136
+ }
137
+ })
138
+ // Check the max length of the clone name and if the clone name already exists
139
+ .on("keyup", "#wpstg-new-clone-id", function () {
140
+
141
+ // This request was already sent, clear it up!
142
+ if ("number" === typeof (timer))
143
+ {
144
+ clearInterval(timer);
145
+ }
146
+
147
+ var cloneID = this.value;
148
+
149
+ timer = setTimeout(
150
+ function () {
151
+ ajax(
152
+ {
153
+ action: "wpstg_check_clone",
154
+ cloneID: cloneID
155
+ },
156
+ function (response)
157
+ {
158
+ if (response.status === "success")
159
+ {
160
+ cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
161
+ cache.get("#wpstg-start-cloning").removeAttr("disabled");
162
+ cache.get("#wpstg-clone-id-error").text('').hide();
163
+ }
164
+ else
165
+ {
166
+ cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
167
+ cache.get("#wpstg-start-cloning").prop("disabled", true);
168
+ cache.get("#wpstg-clone-id-error").text(response.message).show();
169
+ }
170
+ }
171
+ );
172
+ },
173
+ 500
174
+ );
175
+ })
176
+ // Restart cloning process
177
+ .on("click", "#wpstg-start-cloning", function () {
178
+ that.isCancelled = false;
179
+ that.getLogs = false;
180
+ })
181
+ // Display logs
182
+ // .on("click", "#wpstg-show-log-button", function (e) {
183
+ // e.preventDefault();
184
+ // var $logDetails = cache.get("#wpstg-log-details");
185
+ //
186
+ // $logDetails.toggle();
187
+ //
188
+ // logscroll();
189
+ //
190
+ // that.getLogs = (false === that.getLogs);
191
+ // });
192
+
193
+ cloneActions();
194
+ };
195
+
196
+
197
+ /**
198
+ * Clone actions
199
+ */
200
+ var cloneActions = function ()
201
+ {
202
+ var $workFlow = cache.get("#wpstg-workflow");
203
+
204
+ $workFlow
205
+ // Cancel cloning
206
+ .on("click", "#wpstg-cancel-cloning", function () {
207
+ if (!confirm("Are you sure you want to cancel cloning process?"))
208
+ {
209
+ return false;
210
+ }
211
+
212
+ var $this = $(this);
213
+
214
+ $("#wpstg-try-again, #wpstg-home-link").hide();
215
+ $this.prop("disabled", true);
216
+
217
+ that.isCancelled = true;
218
+
219
+ $("#wpstg-cloning-result").text("Please wait...this can take up a while.");
220
+ $("#wpstg-loader, #wpstg-show-log-button").hide();
221
+
222
+ $this.parent().append(ajaxSpinner);
223
+
224
+ cancelCloning();
225
+ })
226
+ // Cancel update cloning
227
+ .on("click", "#wpstg-cancel-cloning-update", function () {
228
+ if (!confirm("Are you sure you want to cancel clone updating process?"))
229
+ {
230
+ return false;
231
+ }
232
+
233
+ var $this = $(this);
234
+
235
+ $("#wpstg-try-again, #wpstg-home-link").hide();
236
+ $this.prop("disabled", true);
237
+
238
+ that.isCancelled = true;
239
+
240
+ $("#wpstg-cloning-result").text("Please wait...this can take up a while.");
241
+ $("#wpstg-loader, #wpstg-show-log-button").hide();
242
+
243
+ $this.parent().append(ajaxSpinner);
244
+
245
+ cancelCloningUpdate();
246
+ })
247
+ // Delete clone - confirmation
248
+ .on("click", ".wpstg-remove-clone[data-clone]", function (e) {
249
+ e.preventDefault();
250
+
251
+ var $existingClones = cache.get("#wpstg-existing-clones");
252
+
253
+ $workFlow.removeClass('active');
254
+
255
+ cache.get("#wpstg-loader").show();
256
+
257
+ ajax(
258
+ {
259
+ action: "wpstg_confirm_delete_clone",
260
+ nonce: wpstg.nonce,
261
+ clone: $(this).data("clone")
262
+ },
263
+ function (response)
264
+ {
265
+ cache.get("#wpstg-removing-clone").html(response);
266
+
267
+ $existingClones.children("img").remove();
268
+
269
+ cache.get("#wpstg-loader").hide();
270
+ },
271
+ "HTML"
272
+ );
273
+ })
274
+ // Delete clone - confirmed
275
+ .on("click", "#wpstg-remove-clone", function (e) {
276
+ e.preventDefault();
277
+
278
+ cache.get("#wpstg-removing-clone").addClass("loading");
279
+
280
+ cache.get("#wpstg-loader").show();
281
+
282
+ deleteClone($(this).data("clone"));
283
+ })
284
+ // Cancel deleting clone
285
+ .on("click", "#wpstg-cancel-removing", function (e) {
286
+ e.preventDefault();
287
+ $(".wpstg-clone").removeClass("active");
288
+ cache.get("#wpstg-removing-clone").html('');
289
+ })
290
+ // Update
291
+ .on("click", ".wpstg-execute-clone", function (e) {
292
+ e.preventDefault();
293
+
294
+ if (!confirm("Are you sure you want to update the staging site? All your staging site modifications will be overwritten with the data from the live site. So make sure that your live site is up to date."))
295
+ {
296
+ return false;
297
+ }
298
+
299
+ var clone = $(this).data("clone");
300
+
301
+ $workFlow.addClass("loading");
302
+
303
+ ajax(
304
+ {
305
+ action: "wpstg_scanning",
306
+ clone: clone,
307
+ nonce: wpstg.nonce
308
+ },
309
+ function (response)
310
+ {
311
+ if (response.length < 1)
312
+ {
313
+ showError("Something went wrong, please try again");
314
+ }
315
+
316
+ $workFlow.removeClass("loading").html(response);
317
+
318
+ cache.get(".wpstg-current-step")
319
+ .removeClass("wpstg-current-step")
320
+ .next("li")
321
+ .addClass("wpstg-current-step");
322
+ },
323
+ "HTML"
324
+ );
325
+ });
326
+ };
327
+
328
+
329
+ /**
330
+ * Ajax Requests
331
+ * @param {Object} data
332
+ * @param {Function} callback
333
+ * @param {String} dataType
334
+ * @param {Boolean} showErrors
335
+ */
336
+ var ajax = function (data, callback, dataType, showErrors)
337
+ {
338
+ if ("undefined" === typeof (dataType))
339
+ {
340
+ dataType = "json";
341
+ }
342
+
343
+ if (false !== showErrors)
344
+ {
345
+ showErrors = true;
346
+ }
347
+
348
+ $.ajax({
349
+ url: ajaxurl,
350
+ type: "POST",
351
+ dataType: dataType,
352
+ cache: false,
353
+ data: data,
354
+ error: function (xhr, textStatus, errorThrown) {
355
+ console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
356
+ console.log(textStatus);
357
+
358
+ if (false === showErrors)
359
+ {
360
+ return false;
361
+ }
362
+
363
+ showError(
364
+ "Fatal Unknown Error. Go to WP Staging > Settings and lower 'File Copy Limit'" +
365
+ "Than try again. If this does not help, " +
366
+ "<a href='https://wpquads.com/support/' target='_blank'>open a support ticket</a> "
367
+ );
368
+ },
369
+ success: function (data) {
370
+ if ("function" === typeof (callback))
371
+ {
372
+ callback(data);
373
+ }
374
+ },
375
+ statusCode: {
376
+ 404: function () {
377
+ showError("Something went wrong; can't find ajax request URL!");
378
+ },
379
+ 500: function () {
380
+ showError("Something went wrong; internal server error while processing the request!");
381
+ }
382
+ }
383
+ });
384
+ };
385
+
386
+ /**
387
+ * Next / Previous Step Clicks to Navigate Through Staging Job
388
+ */
389
+ var stepButtons = function ()
390
+ {
391
+ var $workFlow = cache.get("#wpstg-workflow");
392
+
393
+ $workFlow
394
+ // Next Button
395
+ .on("click", ".wpstg-next-step-link", function (e) {
396
+ e.preventDefault();
397
+
398
+ var $this = $(this),
399
+ isScan = false;
400
+
401
+ // Button is disabled
402
+ if ($this.attr("disabled"))
403
+ {
404
+ return false;
405
+ }
406
+
407
+ // Add loading overlay
408
+ $workFlow.addClass("loading");
409
+
410
+ // Prepare data
411
+ that.data = {
412
+ action: $this.data("action"),
413
+ nonce: wpstg.nonce
414
+ };
415
+
416
+ // Cloning data
417
+ getCloningData();
418
+
419
+ console.log(that.data);
420
+
421
+ isScan = ("wpstg_scanning" === that.action);
422
+
423
+ // Send ajax request
424
+ ajax(
425
+ that.data,
426
+ function (response) {
427
+
428
+ if (response.length < 1)
429
+ {
430
+ showError("Something went wrong, please try again");
431
+ }
432
+
433
+ // Styling of elements
434
+ $workFlow.removeClass("loading").html(response);
435
+
436
+ cache.get(".wpstg-current-step")
437
+ .removeClass("wpstg-current-step")
438
+ .next("li")
439
+ .addClass("wpstg-current-step");
440
+
441
+ // Start cloning
442
+ that.startCloning();
443
+ //processing();
444
+ },
445
+ "HTML"
446
+ );
447
+ })
448
+ // Previous Button
449
+ .on("click", ".wpstg-prev-step-link", function (e) {
450
+ e.preventDefault();
451
+ cache.get("#wpstg-loader").removeClass('wpstg-finished');
452
+ cache.get("#wpstg-loader").hide();
453
+ loadOverview();
454
+ });
455
+ };
456
+
457
+ /**
458
+ * Get Excluded (Unchecked) Database Tables
459
+ * @returns {Array}
460
+ */
461
+ var getExcludedTables = function ()
462
+ {
463
+ var excludedTables = [];
464
+
465
+ $(".wpstg-db-table input:not(:checked)").each(function () {
466
+ excludedTables.push(this.name);
467
+ });
468
+
469
+ return excludedTables;
470
+ };
471
+
472
+ /**
473
+ * Get Included Directories
474
+ * @returns {Array}
475
+ */
476
+ var getIncludedDirectories = function ()
477
+ {
478
+ var includedDirectories = [];
479
+
480
+ $(".wpstg-dir input:checked").each(function () {
481
+ var $this = $(this);
482
+ if (!$this.parent(".wpstg-dir").parents(".wpstg-dir").children(".wpstg-expand-dirs").hasClass("disabled"))
483
+ {
484
+ includedDirectories.push($this.val());
485
+ }
486
+ });
487
+
488
+ return includedDirectories;
489
+ };
490
+
491
+ /**
492
+ * Get Excluded Directories
493
+ * @returns {Array}
494
+ */
495
+ var getExcludedDirectories = function ()
496
+ {
497
+ var excludedDirectories = [];
498
+
499
+ $(".wpstg-dir input:not(:checked)").each(function () {
500
+ var $this = $(this);
501
+ if (!$this.parent(".wpstg-dir").parents(".wpstg-dir").children(".wpstg-expand-dirs").hasClass("disabled"))
502
+ {
503
+ excludedDirectories.push($this.val());
504
+ }
505
+ });
506
+
507
+ return excludedDirectories;
508
+ };
509
+
510
+ /**
511
+ * Get Included Extra Directories
512
+ * @returns {Array}
513
+ */
514
+ var getIncludedExtraDirectories = function ()
515
+ {
516
+ var extraDirectories = [];
517
+
518
+ if (!$("#wpstg_extraDirectories").val()) {
519
+ return extraDirectories;
520
+ }
521
+
522
+ var extraDirectories = $("#wpstg_extraDirectories").val().split(/\r?\n/);
523
+ console.log(extraDirectories);
524
+
525
+ //excludedDirectories.push($this.val());
526
+
527
+ return extraDirectories;
528
+ };
529
+
530
+
531
+
532
+ /**
533
+ * Get Cloning Step Data
534
+ */
535
+ var getCloningData = function ()
536
+ {
537
+ if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action)
538
+ {
539
+ return;
540
+ }
541
+
542
+ that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
543
+ that.data.excludedTables = getExcludedTables();
544
+ that.data.includedDirectories = getIncludedDirectories();
545
+ that.data.excludedDirectories = getExcludedDirectories();
546
+ that.data.extraDirectories = getIncludedExtraDirectories();
547
+ console.log(that.data);
548
+
549
+ };
550
+
551
+ /**
552
+ * Loads Overview (first step) of Staging Job
553
+ */
554
+ var loadOverview = function ()
555
+ {
556
+ var $workFlow = cache.get("#wpstg-workflow");
557
+
558
+ $workFlow.addClass("loading");
559
+
560
+ ajax(
561
+ {
562
+ action: "wpstg_overview",
563
+ nonce: wpstg.nonce
564
+ },
565
+ function (response) {
566
+
567
+ if (response.length < 1)
568
+ {
569
+ showError("Something went wrong, please try again");
570
+ }
571
+
572
+ var $currentStep = cache.get(".wpstg-current-step");
573
+
574
+ // Styling of elements
575
+ $workFlow.removeClass("loading").html(response);
576
+
577
+ },
578
+ "HTML"
579
+ );
580
+ };
581
+
582
+ /**
583
+ * Load Tabs
584
+ */
585
+ var tabs = function ()
586
+ {
587
+ // var $loaded = false;
588
+ //
589
+ // if ($loaded === false) {
590
+ // console.log('select default tables');
591
+ //
592
+ // $(".wpstg-db-table input").each(function () {
593
+ //
594
+ // $loaded = true;
595
+ //
596
+ // if ($(this).attr('name').match("^" + wpstg.tblprefix)) {
597
+ // $(this).prop("checked", true);
598
+ // } else {
599
+ // $(this).prop("checked", false);
600
+ // }
601
+ // });
602
+ // }
603
+
604
+ cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function (e) {
605
+ e.preventDefault();
606
+
607
+ var $this = $(this);
608
+ var $section = cache.get($this.data("id"));
609
+
610
+ $this.toggleClass("expand");
611
+
612
+ $section.slideToggle();
613
+
614
+ if ($this.hasClass("expand"))
615
+ {
616
+ $this.find(".wpstg-tab-triangle").html("&#9660;");
617
+ }
618
+ else
619
+ {
620
+ $this.find(".wpstg-tab-triangle").html("&#9658;");
621
+ }
622
+
623
+
624
+
625
+ });
626
+ };
627
+
628
+ /**
629
+ * Delete Clone
630
+ * @param {String} clone
631
+ */
632
+ var deleteClone = function (clone)
633
+ {
634
+
635
+ ajax(
636
+ {
637
+ action: "wpstg_delete_clone",
638
+ clone: clone,
639
+ nonce: wpstg.nonce,
640
+ excludedTables: getExcludedTables(),
641
+ deleteDir: $("#deleteDirectory:checked").val()
642
+ },
643
+ function (response)
644
+ {
645
+ if (response) {
646
+ // Error
647
+ if ("undefined" !== typeof response.error && "undefined" !== typeof response.message) {
648
+ showError(response.message);
649
+ console.log(response.message);
650
+ }
651
+
652
+ // Finished
653
+ if ("undefined" !== typeof response.delete && response.delete === 'finished') {
654
+
655
+ cache.get("#wpstg-removing-clone").removeClass("loading").html('');
656
+ $(".wpstg-clone#" + clone).remove();
657
+
658
+ if ($(".wpstg-clone").length < 1)
659
+ {
660
+ cache.get("#wpstg-existing-clones").find("h3").text('');
661
+ }
662
+
663
+ cache.get("#wpstg-loader").hide();
664
+ return;
665
+ }
666
+ }
667
+ // continue
668
+ if (true !== response)
669
+ {
670
+ deleteClone(clone);
671
+ return;
672
+ }
673
+
674
+ }
675
+ );
676
+ };
677
+
678
+ /**
679
+ * Cancel Cloning Process
680
+ */
681
+ var cancelCloning = function ()
682
+ {
683
+ if (true === that.isFinished)
684
+ {
685
+ return true;
686
+ }
687
+
688
+ ajax(
689
+ {
690
+ action: "wpstg_cancel_clone",
691
+ clone: that.data.cloneID,
692
+ nonce: wpstg.nonce
693
+ },
694
+ function (response)
695
+ {
696
+
697
+
698
+ if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
699
+ // Load overview
700
+ loadOverview();
701
+ return;
702
+ }
703
+
704
+ if (true !== response)
705
+ {
706
+ // continue
707
+ cancelCloning();
708
+ return;
709
+ }
710
+
711
+ // Load overview
712
+ loadOverview();
713
+ }
714
+ );
715
+ };
716
+ /**
717
+ * Cancel Cloning Process
718
+ */
719
+ var cancelCloningUpdate = function ()
720
+ {
721
+ if (true === that.isFinished)
722
+ {
723
+ return true;
724
+ }
725
+
726
+ //alert(that.data.cloneID);
727
+ ajax(
728
+ {
729
+ action: "wpstg_cancel_update",
730
+ clone: that.data.cloneID,
731
+ nonce: wpstg.nonce
732
+ },
733
+ function (response)
734
+ {
735
+
736
+
737
+ if (response && "undefined" !== typeof (response.delete) && response.delete === "finished") {
738
+ // Load overview
739
+ loadOverview();
740
+ return;
741
+ }
742
+
743
+ if (true !== response)
744
+ {
745
+ // continue
746
+ cancelCloningUpdate();
747
+ return;
748
+ }
749
+
750
+ // Load overview
751
+ loadOverview();
752
+ }
753
+ );
754
+ };
755
+
756
+ /**
757
+ * Scroll the window log to bottom
758
+ * @returns void
759
+ */
760
+ var logscroll = function () {
761
+ var $div = cache.get("#wpstg-log-details");
762
+ if ("undefined" !== typeof ($div[0])) {
763
+ $div.scrollTop($div[0].scrollHeight);
764
+ }
765
+ }
766
+
767
+ /**
768
+ * Append the log to the logging window
769
+ * @param string log
770
+ * @returns void
771
+ */
772
+ var getLogs = function (log)
773
+ {
774
+ if (log != null && "undefined" !== typeof (log)) {
775
+ if (log.constructor === Array) {
776
+ $.each(log, function (index, value) {
777
+ if (value === null) {
778
+ return;
779
+ }
780
+ if (value.type === 'ERROR') {
781
+ cache.get("#wpstg-log-details").append('<span style="color:red;">[' + value.type + ']</span>-' + '[' + value.date + '] ' + value.message + '</br>');
782
+ } else {
783
+ cache.get("#wpstg-log-details").append('[' + value.type + ']-' + '[' + value.date + '] ' + value.message + '</br>');
784
+ }
785
+ })
786
+ } else {
787
+ cache.get("#wpstg-log-details").append('[' + log.type + ']-' + '[' + log.date + '] ' + log.message + '</br>');
788
+ }
789
+ }
790
+ logscroll();
791
+
792
+ };
793
+
794
+ /**
795
+ * Check diskspace
796
+ * @returns string json
797
+ */
798
+ var checkDiskSpace = function () {
799
+ cache.get("#wpstg-check-space").on("click", function (e) {
800
+ cache.get("#wpstg-loader").show();
801
+ console.log("check disk space");
802
+ ajax(
803
+ {
804
+ action: "wpstg_check_disk_space",
805
+ nonce: wpstg.nonce
806
+ },
807
+ function (response)
808
+ {
809
+ if (false === response)
810
+ {
811
+ cache.get("#wpstg-clone-id-error").text('Can not detect disk space').show();
812
+ cache.get("#wpstg-loader").hide();
813
+ return;
814
+ }
815
+
816
+ // Not enough disk space
817
+ cache.get("#wpstg-clone-id-error").text('Available free disk space ' + response.freespace + ' | Estimated necessary disk space: ' + response.usedspace).show();
818
+ cache.get("#wpstg-loader").hide();
819
+ },
820
+ "json",
821
+ false
822
+ );
823
+ });
824
+
825
+ }
826
+
827
+ /**
828
+ * Fire the update cloning process
829
+ * @returns {undefined}
830
+ */
831
+ // var startUpdate = function (){
832
+ // var $workFlow = cache.get("#wpstg-workflow");
833
+ // $workFlow.on("click", "#wpstg-start-updating", function (e) {
834
+ // e.preventDefault();
835
+ //
836
+ // var cloneID = $("#wpstg-new-clone-id").val();
837
+ // updateStruc(cloneID);
838
+ // });
839
+ // };
840
+ //
841
+ // var updateStruc = function (cloneID){
842
+ // ajax(
843
+ // {
844
+ // action: "wpstg_update_struc",
845
+ // nonce: wpstg.nonce,
846
+ // cloneID: cloneID,
847
+ // excludedTables: getExcludedTables(),
848
+ // includedDirectories: getIncludedDirectories(),
849
+ // excludedDirectories: getExcludedDirectories(),
850
+ // extraDirectories: getIncludedExtraDirectories()
851
+ // },
852
+ // function (response) {
853
+ // //console.log(response);
854
+ // updating(cloneID);
855
+ // },
856
+ // "HTML",
857
+ // false
858
+ // );
859
+ // }
860
+
861
+ /**
862
+ * Start ajax updating process
863
+ * @returns string
864
+ */
865
+ // var updating = function (cloneID) {
866
+ //
867
+ // console.log("Start updating");
868
+ //
869
+ // // Show loader gif
870
+ // cache.get("#wpstg-loader").show();
871
+ // cache.get(".wpstg-loader").show();
872
+ //
873
+ // ajax(
874
+ // {
875
+ // action: "wpstg_update",
876
+ // nonce: wpstg.nonce,
877
+ // cloneID: cloneID,
878
+ // excludedTables: getExcludedTables(),
879
+ // includedDirectories: getIncludedDirectories(),
880
+ // excludedDirectories: getExcludedDirectories(),
881
+ // extraDirectories: getIncludedExtraDirectories()
882
+ // },
883
+ // function (response) {
884
+ //
885
+ // // Throw Error
886
+ // if ("undefined" !== typeof(response.error) && response.error){
887
+ // console.log(response.message);
888
+ // showError(response.message);
889
+ // return;
890
+ // }
891
+ //
892
+ // // Add percentage
893
+ // if ("undefined" !== typeof (response.percentage))
894
+ // {
895
+ // cache.get("#wpstg-db-progress").width(response.percentage + '%');
896
+ // }
897
+ // // Add Log
898
+ // if ("undefined" !== typeof (response.last_msg))
899
+ // {
900
+ // getLogs(response.last_msg);
901
+ // }
902
+ //
903
+ // // Continue clone DB
904
+ // if (false === response.status)
905
+ // {
906
+ // setTimeout(function () {
907
+ // updating(cloneID);
908
+ // }, wpstg.cpuLoad);
909
+ // }
910
+ // // Next Step
911
+ // else if (true === response.status)
912
+ // {
913
+ // console.log('startCloning ' + response.status);
914
+ // setTimeout(function () {
915
+ // // Prepare data
916
+ // that.data = {
917
+ // action: 'wpstg_cloning',
918
+ // nonce: wpstg.nonce
919
+ // };
920
+ // that.startCloning();
921
+ // }, wpstg.cpuLoad);
922
+ // }
923
+ // },
924
+ // "json",
925
+ // false
926
+ // );
927
+ // };
928
+
929
+ /**
930
+ * Start Cloning Process
931
+ * @type {Function}
932
+ */
933
+ that.startCloning = (function () {
934
+
935
+ // Register function for checking disk space
936
+ checkDiskSpace();
937
+
938
+ if ("wpstg_cloning" !== that.data.action && "wpstg_update" !== that.data.action)
939
+ {
940
+ return;
941
+ }
942
+
943
+ // Start the process
944
+ start();
945
+
946
+ // Functions
947
+ // Start
948
+ function start()
949
+ {
950
+ console.log("Starting cloning process...");
951
+
952
+ cache.get("#wpstg-loader").show();
953
+
954
+ // Clone Database
955
+ setTimeout(function () {
956
+ cloneDatabase();
957
+ }, wpstg.cpuLoad);
958
+ }
959
+
960
+ // Step 1: Clone Database
961
+ function cloneDatabase()
962
+ {
963
+ if (true === that.isCancelled)
964
+ {
965
+ return false;
966
+ }
967
+
968
+ if (true === that.getLogs)
969
+ {
970
+ getLogs();
971
+ }
972
+
973
+ setTimeout(
974
+ function () {
975
+ ajax(
976
+ {
977
+ action: "wpstg_clone_database",
978
+ nonce: wpstg.nonce
979
+ },
980
+ function (response) {
981
+ // Add percentage
982
+ if ("undefined" !== typeof (response.percentage))
983
+ {
984
+ cache.get("#wpstg-db-progress").width(response.percentage + '%');
985
+ }
986
+ // Add Log
987
+ if ("undefined" !== typeof (response.last_msg))
988
+ {
989
+ getLogs(response.last_msg);
990
+ }
991
+
992
+ // Continue clone DB
993
+ if (false === response.status)
994
+ {
995
+ setTimeout(function () {
996
+ cloneDatabase();
997
+ }, wpstg.cpuLoad);
998
+ }
999
+ // Next Step
1000
+ else if (true === response.status)
1001
+ {
1002
+ //console.log('prepareDirectories ' + response.status);
1003
+ setTimeout(function () {
1004
+ prepareDirectories();
1005
+ }, wpstg.cpuLoad);
1006
+ }
1007
+ }
1008
+ );
1009
+ },
1010
+ 500
1011
+ );
1012
+ }
1013
+
1014
+ // Step 2: Prepare Directories
1015
+ function prepareDirectories()
1016
+ {
1017
+ if (true === that.isCancelled)
1018
+ {
1019
+ return false;
1020
+ }
1021
+
1022
+ if (true === that.getLogs)
1023
+ {
1024
+ getLogs();
1025
+ }
1026
+
1027
+ setTimeout(
1028
+ function () {
1029
+ ajax(
1030
+ {
1031
+ action: "wpstg_clone_prepare_directories",
1032
+ nonce: wpstg.nonce
1033
+ },
1034
+ function (response) {
1035
+ // Add percentage
1036
+ if ("undefined" !== typeof (response.percentage))
1037
+ {
1038
+ cache.get("#wpstg-directories-progress").width(response.percentage + '%');
1039
+ }
1040
+
1041
+ // Add Log
1042
+ if ("undefined" !== typeof (response.last_msg))
1043
+ {
1044
+ getLogs(response.last_msg);
1045
+ }
1046
+
1047
+ if (false === response.status)
1048
+ {
1049
+ setTimeout(function () {
1050
+ prepareDirectories();
1051
+ }, wpstg.cpuLoad);
1052
+ }
1053
+ else if (true === response.status)
1054
+ {
1055
+ console.log('prepareDirectories' + response.status);
1056
+ cloneFiles();
1057
+ }
1058
+ }
1059
+ );
1060
+ },
1061
+ 500
1062
+ );
1063
+ }
1064
+
1065
+ // Step 3: Clone Files
1066
+ function cloneFiles()
1067
+ {
1068
+ if (true === that.isCancelled)
1069
+ {
1070
+ return false;
1071
+ }
1072
+
1073
+ if (true === that.getLogs)
1074
+ {
1075
+ getLogs();
1076
+ }
1077
+
1078
+ ajax(
1079
+ {
1080
+ action: "wpstg_clone_files",
1081
+ nonce: wpstg.nonce
1082
+ },
1083
+ function (response) {
1084
+ // Add percentage
1085
+ if ("undefined" !== typeof (response.percentage))
1086
+ {
1087
+ cache.get("#wpstg-files-progress").width(response.percentage + '%');
1088
+ }
1089
+
1090
+ // Add Log
1091
+ if ("undefined" !== typeof (response.last_msg))
1092
+ {
1093
+ getLogs(response.last_msg);
1094
+ }
1095
+
1096
+ if (false === response.status)
1097
+ {
1098
+ setTimeout(function () {
1099
+ cloneFiles();
1100
+ }, wpstg.cpuLoad);
1101
+ }
1102
+ else if (true === response.status)
1103
+ {
1104
+ setTimeout(function () {
1105
+ replaceData();
1106
+ }, wpstg.cpuLoad);
1107
+ }
1108
+ }
1109
+ );
1110
+ }
1111
+
1112
+ // Step 4: Replace Data
1113
+ function replaceData()
1114
+ {
1115
+ if (true === that.isCancelled)
1116
+ {
1117
+ return false;
1118
+ }
1119
+
1120
+ if (true === that.getLogs)
1121
+ {
1122
+ console.log('getLogs1')
1123
+ getLogs();
1124
+ }
1125
+
1126
+ ajax(
1127
+ {
1128
+ action: "wpstg_clone_replace_data",
1129
+ nonce: wpstg.nonce
1130
+ },
1131
+ function (response) {
1132
+ // Add percentage
1133
+ if ("undefined" !== typeof (response.percentage))
1134
+ {
1135
+ cache.get("#wpstg-links-progress").width(response.percentage + '%');
1136
+ }
1137
+
1138
+ // Add Log
1139
+ if ("undefined" !== typeof (response.last_msg))
1140
+ {
1141
+ console.log('get Logs');
1142
+ getLogs(response.last_msg);
1143
+ }
1144
+
1145
+ if (false === response.status)
1146
+ {
1147
+ setTimeout(function () {
1148
+ console.log('replace data');
1149
+ replaceData();
1150
+ }, wpstg.cpuLoad);
1151
+ }
1152
+ else if (true === response.status)
1153
+ {
1154
+ console.log('finish');
1155
+ finish();
1156
+ }
1157
+ }
1158
+ );
1159
+ }
1160
+
1161
+ // Finish
1162
+ function finish()
1163
+ {
1164
+ if (true === that.getLogs)
1165
+ {
1166
+ getLogs();
1167
+ }
1168
+
1169
+ if (true === that.isCancelled || true === that.isFinished)
1170
+ {
1171
+ cache.get("#wpstg-loader").hide();
1172
+ return false;
1173
+ }
1174
+
1175
+ ajax(
1176
+ {
1177
+ action: "wpstg_clone_finish",
1178
+ nonce: wpstg.nonce
1179
+ },
1180
+ function (response)
1181
+ {
1182
+ // Invalid response
1183
+ if ("object" !== typeof (response))
1184
+ {
1185
+ showError(
1186
+ "Couldn't finish the cloning process properly. " +
1187
+ "Your clone has been copied but failed to do clean up and " +
1188
+ "saving its records to the database." +
1189
+ "Please contact support and provide your logs."
1190
+ );
1191
+
1192
+ return;
1193
+ }
1194
+
1195
+ // Add Log
1196
+ if ("undefined" !== typeof (response.last_msg))
1197
+ {
1198
+ getLogs(response.last_msg);
1199
+ }
1200
+
1201
+ console.log("Cloning process finished");
1202
+
1203
+ var $link1 = cache.get("#wpstg-clone-url-1");
1204
+ var $link = cache.get("#wpstg-clone-url");
1205
+
1206
+ cache.get("#wpstg_staging_name").html(that.data.cloneID);
1207
+ cache.get("#wpstg-finished-result").show();
1208
+ cache.get("#wpstg-cancel-cloning").prop("disabled", true);
1209
+ cache.get("#wpstg-cancel-cloning-update").prop("disabled", true);
1210
+ $link1.attr("href", $link1.attr("href") + '/' + response.directoryName);
1211
+ $link1.append('/' + response.directoryName);
1212
+ $link.attr("href", $link.attr("href") + '/' + response.directoryName);
1213
+ cache.get("#wpstg-remove-clone").data("clone", that.data.cloneID);
1214
+
1215
+ // Finished
1216
+ that.isFinished = true;
1217
+
1218
+ finish();
1219
+ }
1220
+ );
1221
+ }
1222
+ });
1223
+
1224
+
1225
+ /**
1226
+ * Initiation
1227
+ * @type {Function}
1228
+ */
1229
+ that.init = (function () {
1230
+ loadOverview();
1231
+ elements();
1232
+ //startUpdate();
1233
+ stepButtons();
1234
+ tabs();
1235
+ //optimizer();
1236
+ });
1237
+
1238
+ /**
1239
+ * Ajax call
1240
+ * @type {ajax}
1241
+ */
1242
+ that.ajax = ajax;
1243
+ that.showError = showError;
1244
+ that.getLogs = getLogs;
1245
+ that.loadOverview = loadOverview;
1246
+
1247
+ return that;
1248
+ })(jQuery);
1249
+
1250
+ jQuery(document).ready(function () {
1251
+ WPStaging.init();
1252
  });
apps/Backend/views/clone/ajax/scan.php CHANGED
@@ -1,119 +1,129 @@
1
- <label id="wpstg-clone-label" for="wpstg-new-clone">
2
- <?php echo __('Staging Site Name:', 'wpstg')?>
3
- <input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if (null !== $options->current) echo " disabled='disabled'"?>>
4
- </label>
5
-
6
- <span class="wpstg-error-msg" id="wpstg-clone-id-error" style="display:none;">
7
- <?php echo __(
8
- "<br>Probably not enough free disk space to create a staging site. ".
9
- "<br> You can continue but its likely that the copying process will fail.",
10
- "wpstg"
11
- )?>
12
- </span>
13
-
14
- <div class="wpstg-tabs-wrapper">
15
- <a href="#" class="wpstg-tab-header active" data-id="#wpstg-scanning-db">
16
- <span class="wpstg-tab-triangle">&#9658;</span>
17
- <?php echo __("DB Tables", "wpstg")?>
18
- </a>
19
-
20
- <div class="wpstg-tab-section" id="wpstg-scanning-db">
21
- <?php do_action("wpstg_scanning_db")?>
22
- <h4 style="margin:0">
23
- <?php echo __(
24
- "Uncheck the tables you do not want to copy. (If the copy process was previously interrupted, ".
25
- "successfully copied tables are greyed out and copy process will skip these ones)",
26
- "wpstg"
27
- )?>
28
- </h4>
29
- <?php
30
- foreach ($options->tables as $table):
31
- $attributes = in_array($table->name, $options->excludedTables) ? '' : "checked";
32
- $attributes .= in_array($table->name, $options->clonedTables) ? " disabled" : '';
33
- ?>
34
- <div class="wpstg-db-table">
35
- <label>
36
- <input class="wpstg-db-table-checkboxes" type="checkbox" name="<?php echo $table->name?>" <?php echo $attributes?>>
37
- <?php echo $table->name?>
38
- </label>
39
- <span class="wpstg-size-info">
40
- <?php echo $scan->formatSize($table->size)?>
41
- </span>
42
- </div>
43
- <?php endforeach ?>
44
- <div>
45
- <a href="#" class="wpstg-button-unselect">
46
- Un-check All
47
- </a>
48
- </div>
49
- </div>
50
-
51
- <a href="#" class="wpstg-tab-header" data-id="#wpstg-scanning-files">
52
- <span class="wpstg-tab-triangle">&#9658;</span>
53
- <?php echo __("Files", "wpstg")?>
54
- </a>
55
-
56
- <div class="wpstg-tab-section" id="wpstg-scanning-files">
57
- <h4 style="margin:0">
58
- <?php echo __("Uncheck the folders you do not want to copy. Click on them for expanding!", "wpstg")?>
59
- </h4>
60
-
61
- <?php echo $scan->directoryListing()?>
62
-
63
- <h4 style="margin:10px 0 10px 0">
64
- <?php echo __("Extra directories to copy", "wpstg")?>
65
- </h4>
66
-
67
- <textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:250px;"></textarea>
68
- <p>
69
- <span>
70
- <?php
71
- echo __(
72
- "Enter one folder path per line.<br>".
73
- "Folders must start with absolute path: " . $options->root,
74
- "wpstg"
75
- )
76
- ?>
77
- </span>
78
- </p>
79
-
80
- <p>
81
- <span>
82
- <?php
83
- if (isset($options->clone)){
84
- echo __("All files are copied into: ", "wpstg") . $options->root . $options->clone;
85
- }
86
- ?>
87
- </span>
88
- </p>
89
- </div>
90
-
91
- <a href="#" class="wpstg-tab-header" data-id="#wpstg-advanced-settings">
92
- <span class="wpstg-tab-triangle">&#9658;</span>
93
- <?php echo __("Advanced Options", "wpstg")?>
94
- </a>
95
-
96
- <div class="wpstg-tab-section" id="wpstg-advanced-settings">
97
- Coming Soon...
98
- </div>
99
-
100
- </div>
101
-
102
- <button type="button" class="wpstg-prev-step-link wpstg-link-btn button-primary">
103
- <?php _e("Back", "wpstg")?>
104
- </button>
105
-
106
- <button type="button" id="wpstg-start-cloning" class="wpstg-next-step-link wpstg-link-btn button-primary" data-action="wpstg_cloning">
107
- <?php
108
- if (null !== $options->current)
109
- {
110
- echo __("Update Clone", "wpstg");
111
- }
112
- else
113
- {
114
- echo __("Start Cloning", "wpstg");
115
- }
116
- ?>
117
- </button>
118
-
 
 
 
 
 
 
 
 
 
 
119
  <a href="#" id="wpstg-check-space"><?php _e('Check Disk Space', 'wpstg'); ?></a>
1
+ <label id="wpstg-clone-label" for="wpstg-new-clone">
2
+ <?php echo __('Staging Site Name:', 'wpstg')?>
3
+ <input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if (null !== $options->current) echo " disabled='disabled'"?>>
4
+ </label>
5
+
6
+ <span class="wpstg-error-msg" id="wpstg-clone-id-error" style="display:none;">
7
+ <?php echo __(
8
+ "<br>Probably not enough free disk space to create a staging site. ".
9
+ "<br> You can continue but its likely that the copying process will fail.",
10
+ "wpstg"
11
+ )?>
12
+ </span>
13
+
14
+ <div class="wpstg-tabs-wrapper">
15
+ <a href="#" class="wpstg-tab-header active" data-id="#wpstg-scanning-db">
16
+ <span class="wpstg-tab-triangle">&#9658;</span>
17
+ <?php echo __("DB Tables", "wpstg")?>
18
+ </a>
19
+
20
+ <div class="wpstg-tab-section" id="wpstg-scanning-db">
21
+ <?php do_action("wpstg_scanning_db")?>
22
+ <h4 style="margin:0">
23
+ <?php
24
+
25
+ echo __(
26
+ "Uncheck the tables you do not want to copy. Usually you should select tables with prefix '{$scan->prefix}', only.",
27
+ "wpstg"
28
+ )?>
29
+ </h4>
30
+ <div style="margin-top:10px;margin-bottom:10px;">
31
+ <a href="#" class="wpstg-button-unselect button"> None </a>
32
+ <a href="#" class="wpstg-button-select button"> <?php _e(WPStaging\WPStaging::getTablePrefix(), 'wpstg'); ?> </a>
33
+ </div>
34
+ <?php
35
+ //print_r( $options->excludedTables);
36
+ foreach ($options->tables as $table):
37
+ $attributes = in_array($table->name, $options->excludedTables) ? '' : "checked";
38
+ $attributes .= in_array($table->name, $options->clonedTables) ? " disabled" : '';
39
+ ?>
40
+ <div class="wpstg-db-table">
41
+ <label>
42
+ <input class="wpstg-db-table-checkboxes" type="checkbox" name="<?php echo $table->name?>" <?php echo $attributes?>>
43
+ <?php echo $table->name?>
44
+ </label>
45
+ <span class="wpstg-size-info">
46
+ <?php echo $scan->formatSize($table->size)?>
47
+ </span>
48
+ </div>
49
+ <?php endforeach ?>
50
+ <div style="margin-top:10px;">
51
+ <a href="#" class="wpstg-button-unselect button"> None </a>
52
+ <a href="#" class="wpstg-button-select button"> <?php _e(WPStaging\WPStaging::getTablePrefix(), 'wpstg'); ?> </a>
53
+ </div>
54
+ </div>
55
+
56
+ <a href="#" class="wpstg-tab-header" data-id="#wpstg-scanning-files">
57
+ <span class="wpstg-tab-triangle">&#9658;</span>
58
+ <?php echo __("Files", "wpstg")?>
59
+ </a>
60
+
61
+ <div class="wpstg-tab-section" id="wpstg-scanning-files">
62
+ <h4 style="margin:0">
63
+ <?php echo __("Uncheck the folders you do not want to copy. Click on them for expanding!", "wpstg")?>
64
+ </h4>
65
+
66
+ <?php echo $scan->directoryListing()?>
67
+
68
+ <h4 style="margin:10px 0 10px 0">
69
+ <?php echo __("Extra directories to copy", "wpstg")?>
70
+ </h4>
71
+
72
+ <textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:250px;"></textarea>
73
+ <p>
74
+ <span>
75
+ <?php
76
+ echo __(
77
+ "Enter one folder path per line.<br>".
78
+ "Folders must start with absolute path: " . $options->root,
79
+ "wpstg"
80
+ )
81
+ ?>
82
+ </span>
83
+ </p>
84
+
85
+ <p>
86
+ <span>
87
+ <?php
88
+ if (isset($options->clone)){
89
+ echo __("All files will be copied to: ", "wpstg") . $options->root . $options->clone;
90
+ }
91
+ ?>
92
+ </span>
93
+ </p>
94
+ </div>
95
+
96
+ <a href="#" class="wpstg-tab-header" data-id="#wpstg-advanced-settings">
97
+ <span class="wpstg-tab-triangle">&#9658;</span>
98
+ <?php echo __("Advanced Options", "wpstg")?>
99
+ </a>
100
+
101
+ <div class="wpstg-tab-section" id="wpstg-advanced-settings">
102
+ Coming Soon...
103
+ </div>
104
+
105
+ </div>
106
+
107
+ <button type="button" class="wpstg-prev-step-link wpstg-link-btn button-primary">
108
+ <?php _e("Back", "wpstg")?>
109
+ </button>
110
+
111
+ <?php
112
+ if (null !== $options->current)
113
+ {
114
+ $label = __("Update Clone", "wpstg");
115
+ $action = 'wpstg_update';
116
+
117
+ echo '<button type="button" id="wpstg-start-updating" class="wpstg-next-step-link wpstg-link-btn button-primary" data-action="'.$action.'">'.$label.'</button>';
118
+ }
119
+ else
120
+ {
121
+ $label = __("Start Cloning", "wpstg");
122
+ $action = 'wpstg_cloning';
123
+
124
+ echo '<button type="button" id="wpstg-start-cloning" class="wpstg-next-step-link wpstg-link-btn button-primary" data-action="'.$action.'">'.$label.'</button>';
125
+
126
+ }
127
+ ?>
128
+
129
  <a href="#" id="wpstg-check-space"><?php _e('Check Disk Space', 'wpstg'); ?></a>
apps/Backend/views/clone/ajax/single-overview.php CHANGED
@@ -1,49 +1,56 @@
1
- <div id="wpstg-step-1">
2
- <button id="wpstg-new-clone" class="wpstg-next-step-link wpstg-link-btn button-primary" data-action="wpstg_scanning">
3
- <?php echo __("Create new staging site", "wpstg")?>
4
- </button>
5
- </div>
6
-
7
- <?php if (isset($availableClones) && !empty($availableClones)):?>
8
- <!-- Existing Clones -->
9
- <div id="wpstg-existing-clones">
10
- <h3>
11
- <?php _e("Your Staging Sites:", "wpstg")?>
12
- </h3>
13
- <?php //wp_die(var_dump($availableClones)); ?>
14
- <?php foreach ($availableClones as $name => $data):?>
15
- <div id="<?php echo $data["directoryName"]; ?>" class="wpstg-clone">
16
-
17
- <?php $urlLogin = $data["url"] . "/wp-login.php"?>
18
-
19
- <a href="<?php echo $urlLogin?>" class="wpstg-clone-title" target="_blank">
20
- <?php //echo $name?>
21
- <?php echo $data["directoryName"]; ?>
22
- </a>
23
-
24
- <?php echo apply_filters("wpstg_before_stage_buttons", $html = '', $name, $data)?>
25
-
26
- <a href="<?php echo $urlLogin?>" class="wpstg-open-clone wpstg-clone-action" target="_blank">
27
- <?php _e("Open", "wpstg")?>
28
- </a>
29
-
30
- <a href="#" class="wpstg-execute-clone wpstg-clone-action" data-clone="<?php echo $name?>">
31
- <?php _e("Edit", "wpstg")?>
32
- </a>
33
-
34
- <a href="#" class="wpstg-remove-clone wpstg-clone-action" data-clone="<?php echo $name?>">
35
- <?php _e("Delete", "wpstg")?>
36
- </a>
37
-
38
- <?php echo apply_filters("wpstg_after_stage_buttons", $html = '', $name, $data)?>
39
- </div>
40
- <?php endforeach?>
41
- </div>
42
- <!-- /Existing Clones -->
43
- <?php endif?>
44
-
45
- <!-- Remove Clone -->
46
- <div id="wpstg-removing-clone">
47
-
48
- </div>
 
 
 
 
 
 
 
49
  <!-- /Remove Clone -->
1
+ <div id="wpstg-step-1">
2
+ <button id="wpstg-new-clone" class="wpstg-next-step-link wpstg-link-btn button-primary" data-action="wpstg_scanning">
3
+ <?php echo __("Create new staging site", "wpstg")?>
4
+ </button>
5
+ </div>
6
+
7
+ <?php if (isset($availableClones) && !empty($availableClones)):?>
8
+ <!-- Existing Clones -->
9
+ <div id="wpstg-existing-clones">
10
+ <h3>
11
+ <?php _e("Your Staging Sites:", "wpstg")?>
12
+ </h3>
13
+ <?php //wp_die(var_dump($availableClones)); ?>
14
+ <?php foreach ($availableClones as $name => $data):?>
15
+ <div id="<?php echo $data["directoryName"]; ?>" class="wpstg-clone">
16
+
17
+ <?php $urlLogin = $data["url"] . "/wp-login.php"?>
18
+
19
+ <a href="<?php echo $urlLogin?>" class="wpstg-clone-title" target="_blank">
20
+ <?php //echo $name?>
21
+ <?php echo $data["directoryName"]; ?>
22
+ </a>
23
+
24
+ <?php echo apply_filters("wpstg_before_stage_buttons", $html = '', $name, $data)?>
25
+
26
+ <a href="<?php echo $urlLogin?>" class="wpstg-open-clone wpstg-clone-action" target="_blank">
27
+ <?php _e("Open", "wpstg"); ?>
28
+ </a>
29
+
30
+ <a href="#" class="wpstg-execute-clone wpstg-clone-action" data-clone="<?php echo $name?>">
31
+ <?php _e("Update", "wpstg"); ?>
32
+ </a>
33
+
34
+ <a href="#" class="wpstg-remove-clone wpstg-clone-action" data-clone="<?php echo $name?>">
35
+ <?php _e("Delete", "wpstg"); ?>
36
+ </a>
37
+
38
+ <?php echo apply_filters("wpstg_after_stage_buttons", $html = '', $name, $data)?>
39
+ <div class="wpstg-staging-info">
40
+ <?php
41
+ $prefix = isset ($data['prefix']) ? __("DB prefix: <span class='wpstg-bold'>" . $data['prefix'], "wpstg") . '</span> ' : '&nbsp;&nbsp;&nbsp;';
42
+ //$path = isset ($data['directoryName']) ? __("Subdir: <span class='wpstg-bold'>" . $data['directoryName'], "wpstg") . '</span>' : '';
43
+ echo $prefix;
44
+ ?>
45
+ </div>
46
+ </div>
47
+ <?php endforeach?>
48
+ </div>
49
+ <!-- /Existing Clones -->
50
+ <?php endif?>
51
+
52
+ <!-- Remove Clone -->
53
+ <div id="wpstg-removing-clone">
54
+
55
+ </div>
56
  <!-- /Remove Clone -->
apps/Backend/views/clone/ajax/update.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class=successfullying-section">
2
+ <?php echo __("Copy Database Tables", "wpstg")?>
3
+ <div class="wpstg-progress-bar">
4
+ <div class="wpstg-progress" id="wpstg-db-progress" style="width:0"></div>
5
+ </div>
6
+ </div>
7
+
8
+ <div class="wpstg-cloning-section">
9
+ <?php echo __("Prepare Directories", "wpstg")?>
10
+ <div class="wpstg-progress-bar">
11
+ <div class="wpstg-progress" id="wpstg-directories-progress" style="width:0"></div>
12
+ </div>
13
+ </div>
14
+
15
+ <div class="wpstg-cloning-section">
16
+ <?php echo __("Copy Files", "wpstg")?>
17
+ <div class="wpstg-progress-bar">
18
+ <div class="wpstg-progress" id="wpstg-files-progress" style="width:0"></div>
19
+ </div>
20
+ </div>
21
+
22
+ <div class="wpstg-cloning-section">
23
+ <?php echo __("Replace Data", "wpstg")?>
24
+ <div class="wpstg-progress-bar">
25
+ <div class="wpstg-progress" id="wpstg-links-progress" style="width:0"></div>
26
+ </div>
27
+ </div>
28
+
29
+ <button type="button" id="wpstg-cancel-cloning-update" class="wpstg-link-btn button-primary">
30
+ <?php echo __("Cancel Update", "wpstg")?>
31
+ </button>
32
+
33
+ <button type="button" id="wpstg-show-log-button" class="button" data-clone="<?php echo $cloning->getOptions()->clone?>" style="margin-top: 5px;display:none;">
34
+ <?php _e('Display working log', 'wpstg')?>
35
+ </button>
36
+
37
+ <div>
38
+ <span id="wpstg-cloning-result"></span>
39
+ </div>
40
+
41
+
42
+ <div id="wpstg-error-wrapper">
43
+ <div id="wpstg-error-details"></div>
44
+ </div>
45
+
46
+ <div id="wpstg-log-details"></div>
apps/Core/WPStaging.php CHANGED
@@ -1,425 +1,429 @@
1
- <?php
2
-
3
- namespace WPStaging;
4
-
5
- // No Direct Access
6
- if( !defined( "WPINC" ) ) {
7
- die;
8
- }
9
-
10
- // Ensure to include autoloader class
11
- require_once __DIR__ . DIRECTORY_SEPARATOR . "Utils" . DIRECTORY_SEPARATOR . "Autoloader.php";
12
-
13
- use WPStaging\Backend\Administrator;
14
- use WPStaging\DTO\Settings;
15
- use WPStaging\Frontend\Frontend;
16
- use WPStaging\Utils\Autoloader;
17
- use WPStaging\Utils\Cache;
18
- use WPStaging\Utils\Loader;
19
- use WPStaging\Utils\Logger;
20
- use WPStaging\DI\InjectionAware;
21
- use WPStaging\Cron\Cron;
22
-
23
- /**
24
- * Class WPStaging
25
- * @package WPStaging
26
- */
27
- final class WPStaging {
28
-
29
- /**
30
- * Plugin version
31
- */
32
- const VERSION = "2.1.2";
33
-
34
- /**
35
- * Plugin name
36
- */
37
- const NAME = "WP Staging";
38
-
39
- /**
40
- * Plugin slug
41
- */
42
- const SLUG = "wp-staging";
43
-
44
- /**
45
- * Compatible WP Version
46
- */
47
- const WP_COMPATIBLE = "4.8.4";
48
-
49
- /**
50
- * Slug: Either wp-staging or wp-staging-pro
51
- * @var string
52
- */
53
- public $slug;
54
-
55
- /**
56
- * Absolute plugin path
57
- * @var string
58
- */
59
- public $pluginPath;
60
-
61
- /**
62
- * Services
63
- * @var array
64
- */
65
- private $services;
66
-
67
- /**
68
- * Singleton instance
69
- * @var WPStaging
70
- */
71
- private static $instance;
72
-
73
- /**
74
- * WPStaging constructor.
75
- */
76
- private function __construct() {
77
-
78
- $file = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . self::SLUG . ".php";
79
-
80
- $this->registerMain();
81
- $this->registerNamespaces();
82
- $this->loadLanguages();
83
- $this->loadDependencies();
84
- $this->defineHooks();
85
-
86
- // Licensing stuff be loaded in wpstg core to make cron hook available from frontpage
87
- $this->licensing();
88
-
89
- // Activation Hook
90
- register_activation_hook( $file, array($this, "onActivation") );
91
- }
92
-
93
- /**
94
- * Method to be executed upon activation of the plugin
95
- */
96
- public function onActivation() {
97
- $Activation = new \WPStaging\Backend\Activation\Activation();
98
- $Activation->install_dependancies();
99
- }
100
-
101
- public function registerMain() {
102
- // Slug of the plugin
103
- $this->slug = plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
104
-
105
- // absolute path to the main plugin dir
106
- $this->pluginPath = plugin_dir_path( dirname( dirname( __FILE__ ) ) );
107
-
108
- // URL to apps folder
109
- $this->url = plugin_dir_url( dirname( __FILE__ ) );
110
-
111
- // URL to backend public folder folder
112
- $this->backend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Backend/public/";
113
-
114
- // URL to frontend public folder folder
115
- $this->frontend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Frontend/public/";
116
- }
117
-
118
- /**
119
- * Define Hooks
120
- */
121
- public function defineHooks() {
122
- $loader = $this->get( "loader" );
123
- $loader->addAction( "admin_enqueue_scripts", $this, "enqueueElements", 100 );
124
- $loader->addAction( "wp_enqueue_scripts", $this, "enqueueElements", 100 );
125
- $this->addIntervals();
126
- }
127
-
128
- /**
129
- * Add new cron time event "weekly"
130
- */
131
- public function addIntervals(){
132
- $interval = new Cron();
133
- }
134
-
135
- /**
136
- * Scripts and Styles
137
- * @param string $hook
138
- */
139
- public function enqueueElements( $hook ) {
140
-
141
- // Load this css file on frontend and backend on all pages if current site is a staging site
142
- if( $this->isStagingSite() ) {
143
- wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", $this->getVersion() );
144
- }
145
-
146
- $availablePages = array(
147
- "toplevel_page_wpstg_clone",
148
- "wp-staging_page_wpstg-settings",
149
- "wp-staging_page_wpstg-tools",
150
- "wp-staging_page_wpstg-license",
151
- "wp-staging_page_wpstg-welcome",
152
- );
153
-
154
- // Load these css and js files only on wp staging admin pages
155
- if( !in_array( $hook, $availablePages ) || !is_admin() ) {
156
- return;
157
- }
158
-
159
- // Load admin js files
160
- wp_enqueue_script(
161
- "wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"), $this->getVersion(), false
162
- );
163
-
164
- // Load admin css files
165
- wp_enqueue_style(
166
- "wpstg-admin", $this->backend_url . "css/wpstg-admin.css", $this->getVersion()
167
- );
168
-
169
- wp_localize_script( "wpstg-admin-script", "wpstg", array(
170
- "ajaxurl" => admin_url( 'admin-ajax.php' ),
171
- "nonce" => wp_create_nonce( "wpstg_ajax_nonce" ),
172
- "mu_plugin_confirmation" => __(
173
- "If confirmed we will install an additional WordPress 'Must Use' plugin. "
174
- . "This plugin will allow us to control which plugins are loaded during "
175
- . "WP Staging specific operations. Do you wish to continue?", "wpstg"
176
- ),
177
- "plugin_compatibility_settings_problem" => __(
178
- "A problem occurred when trying to change the plugin compatibility setting.", "wpstg"
179
- ),
180
- "saved" => __( "Saved", "The settings were saved successfully", "wpstg" ),
181
- "status" => __( "Status", "Current request status", "wpstg" ),
182
- "response" => __( "Response", "The message the server responded with", "wpstg" ),
183
- "blacklist_problem" => __(
184
- "A problem occurred when trying to add plugins to backlist.", "wpstg"
185
- ),
186
- "cpuLoad" => $this->getCPULoadSetting(),
187
- "settings" => ( object ) array() // TODO add settings?
188
- ) );
189
- }
190
-
191
- /**
192
- * Caching and logging folder
193
- *
194
- * @return string
195
- */
196
- public static function getContentDir() {
197
- $wp_upload_dir = wp_upload_dir();
198
- $path = $wp_upload_dir['basedir'] . '/wp-staging';
199
- wp_mkdir_p( $path );
200
- return apply_filters( 'wpstg_get_upload_dir', $path . DIRECTORY_SEPARATOR );
201
- }
202
-
203
- /**
204
- * Register used namespaces
205
- */
206
- private function registerNamespaces() {
207
- $autoloader = new Autoloader();
208
- $this->set( "autoloader", $autoloader );
209
-
210
- //wp_die($this->pluginPath . 'apps' . DIRECTORY_SEPARATOR);
211
- // Autoloader
212
- $autoloader->registerNamespaces( array(
213
- "WPStaging" => array(
214
- $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR,
215
- $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR . 'Core' . DIRECTORY_SEPARATOR,
216
- )
217
- ) );
218
-
219
- // Register namespaces
220
- $autoloader->register();
221
- }
222
-
223
- /**
224
- * Get Instance
225
- * @return WPStaging
226
- */
227
- public static function getInstance() {
228
- if( null === static::$instance ) {
229
- static::$instance = new static();
230
- }
231
-
232
- return static::$instance;
233
- }
234
-
235
- /**
236
- * Prevent cloning
237
- * @return void
238
- */
239
- private function __clone() {
240
-
241
- }
242
-
243
- /**
244
- * Prevent unserialization
245
- * @return void
246
- */
247
- private function __wakeup() {
248
-
249
- }
250
-
251
- /**
252
- * Load Dependencies
253
- */
254
- private function loadDependencies() {
255
- // Set loader
256
- $this->set( "loader", new Loader() );
257
-
258
- // Set cache
259
- $this->set( "cache", new Cache() );
260
-
261
- // Set logger
262
- $this->set( "logger", new Logger() );
263
-
264
- // Set settings
265
- $this->set( "settings", new Settings() );
266
-
267
- // Set Administrator
268
- if( is_admin() ) {
269
- new Administrator( $this );
270
- } else {
271
- new Frontend( $this );
272
- }
273
- }
274
-
275
- /**
276
- * Execute Plugin
277
- */
278
- public function run() {
279
- $this->get( "loader" )->run();
280
- }
281
-
282
- /**
283
- * Set a variable to DI with given name
284
- * @param string $name
285
- * @param mixed $variable
286
- * @return $this
287
- */
288
- public function set( $name, $variable ) {
289
- // It is a function
290
- if( is_callable( $variable ) )
291
- $variable = $variable();
292
-
293
- // Add it to services
294
- $this->services[$name] = $variable;
295
-
296
- return $this;
297
- }
298
-
299
- /**
300
- * Get given name index from DI
301
- * @param string $name
302
- * @return mixed|null
303
- */
304
- public function get( $name ) {
305
- return (isset( $this->services[$name] )) ? $this->services[$name] : null;
306
- }
307
-
308
- /**
309
- * @return string
310
- */
311
- public function getVersion() {
312
- return self::VERSION;
313
- }
314
-
315
- /**
316
- * @return string
317
- */
318
- public function getName() {
319
- return self::NAME;
320
- }
321
-
322
- /**
323
- * @return string
324
- */
325
- public static function getSlug() {
326
- return plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
327
- }
328
-
329
- /**
330
- * Get path to main plugin file
331
- * @return string
332
- */
333
- public function getPath() {
334
- return dirname( dirname( __FILE__ ) );
335
- }
336
-
337
- /**
338
- * Get main plugin url
339
- * @return type
340
- */
341
- public function getUrl() {
342
- return plugin_dir_url( dirname( __FILE__ ) );
343
- }
344
-
345
- /**
346
- * @return array|mixed|object
347
- */
348
- public function getCPULoadSetting() {
349
- $options = $this->get( "settings" );
350
- $setting = $options->getCpuLoad();
351
-
352
- switch ( $setting ) {
353
- case "high":
354
- $cpuLoad = 0;
355
- break;
356
-
357
- case "medium":
358
- $cpuLoad = 1000;
359
- break;
360
-
361
- case "low":
362
- $cpuLoad = 3000;
363
- break;
364
-
365
- case "default":
366
- default:
367
- $cpuLoad = 1000;
368
- }
369
-
370
- return $cpuLoad;
371
- }
372
-
373
- /**
374
- * Load language file
375
- */
376
- public function loadLanguages() {
377
- $languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR;
378
- $languagesDirectory.= "vars" . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
379
-
380
- // Set filter for plugins languages directory
381
- $languagesDirectory = apply_filters( "wpstg_languages_directory", $languagesDirectory );
382
-
383
- // Traditional WP plugin locale filter
384
- $locale = apply_filters( "plugin_locale", get_locale(), "wpstg" );
385
- $moFile = sprintf( '%1$s-%2$s.mo', "wpstg", $locale );
386
-
387
- // Setup paths to current locale file
388
- $moFileLocal = $languagesDirectory . $moFile;
389
- $moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wpstg" . DIRECTORY_SEPARATOR . $moFile;
390
-
391
- // Global file (/wp-content/languages/WPSTG)
392
- if( file_exists( $moFileGlobal ) ) {
393
- load_textdomain( "wpstg", $moFileGlobal );
394
- }
395
- // Local file (/wp-content/plugins/wp-staging/languages/)
396
- elseif( file_exists( $moFileLocal ) ) {
397
- load_textdomain( "wpstg", $moFileGlobal );
398
- }
399
- // Default file
400
- else {
401
- load_plugin_textdomain( "wpstg", false, $languagesDirectory );
402
- }
403
- }
404
-
405
- /**
406
- * Check if it is a staging site
407
- * @return bool
408
- */
409
- private function isStagingSite() {
410
- return ("true" === get_option( "wpstg_is_staging_site" ));
411
- }
412
-
413
- /**
414
- * Initialize licensing functions
415
- * @return boolean
416
- */
417
- private function licensing() {
418
- // Add licensing stuff if class exists
419
- if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
420
- $licensing = new Backend\Pro\Licensing\Licensing();
421
- }
422
- return false;
423
- }
424
-
425
- }
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging;
4
+
5
+ // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
8
+ }
9
+
10
+ // Ensure to include autoloader class
11
+ require_once __DIR__ . DIRECTORY_SEPARATOR . "Utils" . DIRECTORY_SEPARATOR . "Autoloader.php";
12
+
13
+ use WPStaging\Backend\Administrator;
14
+ use WPStaging\DTO\Settings;
15
+ use WPStaging\Frontend\Frontend;
16
+ use WPStaging\Utils\Autoloader;
17
+ use WPStaging\Utils\Cache;
18
+ use WPStaging\Utils\Loader;
19
+ use WPStaging\Utils\Logger;
20
+ use WPStaging\DI\InjectionAware;
21
+ use WPStaging\Cron\Cron;
22
+
23
+ /**
24
+ * Class WPStaging
25
+ * @package WPStaging
26
+ */
27
+ final class WPStaging {
28
+
29
+ /**
30
+ * Plugin version
31
+ */
32
+ const VERSION = "2.1.3";
33
+
34
+ /**
35
+ * Plugin name
36
+ */
37
+ const NAME = "WP Staging";
38
+
39
+ /**
40
+ * Plugin slug
41
+ */
42
+ const SLUG = "wp-staging";
43
+
44
+ /**
45
+ * Compatible WP Version
46
+ */
47
+ const WP_COMPATIBLE = "4.8.4";
48
+
49
+ /**
50
+ * Slug: Either wp-staging or wp-staging-pro
51
+ * @var string
52
+ */
53
+ public $slug;
54
+
55
+ /**
56
+ * Absolute plugin path
57
+ * @var string
58
+ */
59
+ public $pluginPath;
60
+
61
+ /**
62
+ * Services
63
+ * @var array
64
+ */
65
+ private $services;
66
+
67
+ /**
68
+ * Singleton instance
69
+ * @var WPStaging
70
+ */
71
+ private static $instance;
72
+
73
+ /**
74
+ * WPStaging constructor.
75
+ */
76
+ private function __construct() {
77
+
78
+ $file = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . self::SLUG . ".php";
79
+
80
+ $this->registerMain();
81
+ $this->registerNamespaces();
82
+ $this->loadLanguages();
83
+ $this->loadDependencies();
84
+ $this->defineHooks();
85
+ // Licensing stuff be loaded in wpstg core to make cron hook available from frontpage
86
+ $this->initLicensing();
87
+ }
88
+
89
+ /**
90
+ * Method to be executed upon activation of the plugin
91
+ */
92
+ public function onActivation() {
93
+ $Activation = new \WPStaging\Backend\Activation\Activation();
94
+ $Activation->install_dependancies();
95
+ }
96
+
97
+ public function registerMain() {
98
+ // Slug of the plugin
99
+ $this->slug = plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
100
+
101
+ // absolute path to the main plugin dir
102
+ $this->pluginPath = plugin_dir_path( dirname( dirname( __FILE__ ) ) );
103
+
104
+ // URL to apps folder
105
+ $this->url = plugin_dir_url( dirname( __FILE__ ) );
106
+
107
+ // URL to backend public folder folder
108
+ $this->backend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Backend/public/";
109
+
110
+ // URL to frontend public folder folder
111
+ $this->frontend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Frontend/public/";
112
+ }
113
+
114
+ /**
115
+ * Define Hooks
116
+ */
117
+ public function defineHooks() {
118
+ $loader = $this->get( "loader" );
119
+ $loader->addAction( "admin_enqueue_scripts", $this, "enqueueElements", 100 );
120
+ $loader->addAction( "wp_enqueue_scripts", $this, "enqueueElements", 100 );
121
+ $this->addIntervals();
122
+ }
123
+
124
+ /**
125
+ * Add new cron time event "weekly"
126
+ */
127
+ public function addIntervals(){
128
+ $interval = new Cron();
129
+ }
130
+
131
+ /**
132
+ * Scripts and Styles
133
+ * @param string $hook
134
+ */
135
+ public function enqueueElements( $hook ) {
136
+
137
+ // Load this css file on frontend and backend on all pages if current site is a staging site
138
+ if( $this->isStagingSite() ) {
139
+ wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", $this->getVersion() );
140
+ }
141
+
142
+ $availablePages = array(
143
+ "toplevel_page_wpstg_clone",
144
+ "wp-staging_page_wpstg-settings",
145
+ "wp-staging_page_wpstg-tools",
146
+ "wp-staging_page_wpstg-license",
147
+ "wp-staging_page_wpstg-welcome",
148
+ );
149
+
150
+ // Load these css and js files only on wp staging admin pages
151
+ if( !in_array( $hook, $availablePages ) || !is_admin() ) {
152
+ return;
153
+ }
154
+
155
+ // Load admin js files
156
+ wp_enqueue_script(
157
+ "wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"), $this->getVersion(), false
158
+ );
159
+
160
+ // Load admin css files
161
+ wp_enqueue_style(
162
+ "wpstg-admin", $this->backend_url . "css/wpstg-admin.css", $this->getVersion()
163
+ );
164
+
165
+ wp_localize_script( "wpstg-admin-script", "wpstg", array(
166
+ "nonce" => wp_create_nonce( "wpstg_ajax_nonce" ),
167
+ "mu_plugin_confirmation" => __(
168
+ "If confirmed we will install an additional WordPress 'Must Use' plugin. "
169
+ . "This plugin will allow us to control which plugins are loaded during "
170
+ . "WP Staging specific operations. Do you wish to continue?", "wpstg"
171
+ ),
172
+ "plugin_compatibility_settings_problem" => __(
173
+ "A problem occurred when trying to change the plugin compatibility setting.", "wpstg"
174
+ ),
175
+ "saved" => __( "Saved", "The settings were saved successfully", "wpstg" ),
176
+ "status" => __( "Status", "Current request status", "wpstg" ),
177
+ "response" => __( "Response", "The message the server responded with", "wpstg" ),
178
+ "blacklist_problem" => __(
179
+ "A problem occurred when trying to add plugins to backlist.", "wpstg"
180
+ ),
181
+ "cpuLoad" => $this->getCPULoadSetting(),
182
+ "settings" => ( object ) array(), // TODO add settings?
183
+ "tblprefix" => self::getTablePrefix()
184
+ ) );
185
+ }
186
+
187
+ /**
188
+ * Get table prefix of the current site
189
+ * @return string
190
+ */
191
+ public static function getTablePrefix(){
192
+ $wpDB = WPStaging::getInstance()->get("wpdb");
193
+ return $wpDB->prefix;
194
+ }
195
+
196
+ /**
197
+ * Caching and logging folder
198
+ *
199
+ * @return string
200
+ */
201
+ public static function getContentDir() {
202
+ $wp_upload_dir = wp_upload_dir();
203
+ $path = $wp_upload_dir['basedir'] . '/wp-staging';
204
+ wp_mkdir_p( $path );
205
+ return apply_filters( 'wpstg_get_upload_dir', $path . DIRECTORY_SEPARATOR );
206
+ }
207
+
208
+ /**
209
+ * Register used namespaces
210
+ */
211
+ private function registerNamespaces() {
212
+ $autoloader = new Autoloader();
213
+ $this->set( "autoloader", $autoloader );
214
+
215
+ // Autoloader
216
+ $autoloader->registerNamespaces( array(
217
+ "WPStaging" => array(
218
+ $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR,
219
+ $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR . 'Core' . DIRECTORY_SEPARATOR,
220
+ )
221
+ ) );
222
+
223
+ // Register namespaces
224
+ $autoloader->register();
225
+ }
226
+
227
+ /**
228
+ * Get Instance
229
+ * @return WPStaging
230
+ */
231
+ public static function getInstance() {
232
+ if( null === static::$instance ) {
233
+ static::$instance = new static();
234
+ }
235
+
236
+ return static::$instance;
237
+ }
238
+
239
+ /**
240
+ * Prevent cloning
241
+ * @return void
242
+ */
243
+ private function __clone() {
244
+
245
+ }
246
+
247
+ /**
248
+ * Prevent unserialization
249
+ * @return void
250
+ */
251
+ private function __wakeup() {
252
+
253
+ }
254
+
255
+ /**
256
+ * Load Dependencies
257
+ */
258
+ private function loadDependencies() {
259
+ // Set loader
260
+ $this->set( "loader", new Loader() );
261
+
262
+ // Set cache
263
+ $this->set( "cache", new Cache() );
264
+
265
+ // Set logger
266
+ $this->set( "logger", new Logger() );
267
+
268
+ // Set settings
269
+ $this->set( "settings", new Settings() );
270
+
271
+ // Set Administrator
272
+ if( is_admin() ) {
273
+ new Administrator( $this );
274
+ } else {
275
+ new Frontend( $this );
276
+ }
277
+ }
278
+
279
+ /**
280
+ * Execute Plugin
281
+ */
282
+ public function run() {
283
+ $this->get( "loader" )->run();
284
+ }
285
+
286
+ /**
287
+ * Set a variable to DI with given name
288
+ * @param string $name
289
+ * @param mixed $variable
290
+ * @return $this
291
+ */
292
+ public function set( $name, $variable ) {
293
+ // It is a function
294
+ if( is_callable( $variable ) )
295
+ $variable = $variable();
296
+
297
+ // Add it to services
298
+ $this->services[$name] = $variable;
299
+
300
+ return $this;
301
+ }
302
+
303
+ /**
304
+ * Get given name index from DI
305
+ * @param string $name
306
+ * @return mixed|null
307
+ */
308
+ public function get( $name ) {
309
+ return (isset( $this->services[$name] )) ? $this->services[$name] : null;
310
+ }
311
+
312
+ /**
313
+ * @return string
314
+ */
315
+ public function getVersion() {
316
+ return self::VERSION;
317
+ }
318
+
319
+ /**
320
+ * @return string
321
+ */
322
+ public function getName() {
323
+ return self::NAME;
324
+ }
325
+
326
+ /**
327
+ * @return string
328
+ */
329
+ public static function getSlug() {
330
+ return plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
331
+ }
332
+
333
+ /**
334
+ * Get path to main plugin file
335
+ * @return string
336
+ */
337
+ public function getPath() {
338
+ return dirname( dirname( __FILE__ ) );
339
+ }
340
+
341
+ /**
342
+ * Get main plugin url
343
+ * @return type
344
+ */
345
+ public function getUrl() {
346
+ return plugin_dir_url( dirname( __FILE__ ) );
347
+ }
348
+
349
+ /**
350
+ * @return array|mixed|object
351
+ */
352
+ public function getCPULoadSetting() {
353
+ $options = $this->get( "settings" );
354
+ $setting = $options->getCpuLoad();
355
+
356
+ switch ( $setting ) {
357
+ case "high":
358
+ $cpuLoad = 0;
359
+ break;
360
+
361
+ case "medium":
362
+ $cpuLoad = 1000;
363
+ break;
364
+
365
+ case "low":
366
+ $cpuLoad = 3000;
367
+ break;
368
+
369
+ case "default":
370
+ default:
371
+ $cpuLoad = 1000;
372
+ }
373
+
374
+ return $cpuLoad;
375
+ }
376
+
377
+ /**
378
+ * Load language file
379
+ */
380
+ public function loadLanguages() {
381
+ $languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR;
382
+ $languagesDirectory.= "vars" . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
383
+
384
+ // Set filter for plugins languages directory
385
+ $languagesDirectory = apply_filters( "wpstg_languages_directory", $languagesDirectory );
386
+
387
+ // Traditional WP plugin locale filter
388
+ $locale = apply_filters( "plugin_locale", get_locale(), "wpstg" );
389
+ $moFile = sprintf( '%1$s-%2$s.mo', "wpstg", $locale );
390
+
391
+ // Setup paths to current locale file
392
+ $moFileLocal = $languagesDirectory . $moFile;
393
+ $moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wpstg" . DIRECTORY_SEPARATOR . $moFile;
394
+
395
+ // Global file (/wp-content/languages/WPSTG)
396
+ if( file_exists( $moFileGlobal ) ) {
397
+ load_textdomain( "wpstg", $moFileGlobal );
398
+ }
399
+ // Local file (/wp-content/plugins/wp-staging/languages/)
400
+ elseif( file_exists( $moFileLocal ) ) {
401
+ load_textdomain( "wpstg", $moFileGlobal );
402
+ }
403
+ // Default file
404
+ else {
405
+ load_plugin_textdomain( "wpstg", false, $languagesDirectory );
406
+ }
407
+ }
408
+
409
+ /**
410
+ * Check if it is a staging site
411
+ * @return bool
412
+ */
413
+ private function isStagingSite() {
414
+ return ("true" === get_option( "wpstg_is_staging_site" ));
415
+ }
416
+
417
+ /**
418
+ * Initialize licensing functions
419
+ * @return boolean
420
+ */
421
+ public function initLicensing() {
422
+ // Add licensing stuff if class exists
423
+ if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
424
+ $licensing = new Backend\Pro\Licensing\Licensing();
425
+ }
426
+ return false;
427
+ }
428
+
429
+ }
readme.txt CHANGED
@@ -9,7 +9,7 @@ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
  Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
10
  Requires at least: 3.6+
11
  Tested up to: 4.8
12
- Stable tag: 2.1.2
13
 
14
  A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
15
 
@@ -139,6 +139,15 @@ https://wp-staging.com
139
 
140
  == Changelog ==
141
 
 
 
 
 
 
 
 
 
 
142
  = 2.1.2 =
143
  * Fix: Remove LOCK_EX parameter in file_put_contents(). LOCK_EX is not working on several systems which results in cloning process timeouts
144
  * Fix: Huge Performance improvement in copying process by removing duplicate file entries in the cache file. This also prevents weird timeout issues on some hosted websites
9
  Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
10
  Requires at least: 3.6+
11
  Tested up to: 4.8
12
+ Stable tag: 2.1.3
13
 
14
  A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
15
 
139
 
140
  == Changelog ==
141
 
142
+ = 2.1.3 =
143
+ * New: Add more details to tools->system info log for better debugging
144
+ * New: Add buttons to select all default wp tables with one click
145
+ * New: Show used db table in list of staging sites
146
+ * Fix: Delete staging site not possible if db prefix is same as one of the live site
147
+ * Fix: Edit/Update clone function is duplicating tables.
148
+ * Fix: Other staging site can be overwritten when Edit/Update clone function is executed
149
+ * Fix: Several improvements to improve reliability and prevent timeouts and fatal errors during cloning
150
+
151
  = 2.1.2 =
152
  * Fix: Remove LOCK_EX parameter in file_put_contents(). LOCK_EX is not working on several systems which results in cloning process timeouts
153
  * Fix: Huge Performance improvement in copying process by removing duplicate file entries in the cache file. This also prevents weird timeout issues on some hosted websites
wp-staging.php CHANGED
@@ -7,7 +7,7 @@
7
  * Author: WP-Staging
8
  * Author URI: https://wp-staging.com
9
  * Contributors: ReneHermi, ilgityildirim
10
- * Version: 2.1.2
11
  * Text Domain: wpstg
12
  * Domain Path: /languages/
13
 
7
  * Author: WP-Staging
8
  * Author URI: https://wp-staging.com
9
  * Contributors: ReneHermi, ilgityildirim
10
+ * Version: 2.1.3
11
  * Text Domain: wpstg
12
  * Domain Path: /languages/
13