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

Version Description

  • New: Increase cloning performance
  • New: Show admin notice if php version and wordpress version do not meet requirements.
  • New: Show error if there is not enough free diskspace
  • New: Add resume function in case the cloning process interrupts
  • New: Add italian translation
  • New: Better looking admin notices
  • Fix: Different scheme of siteurl and home leads to non available staging site. Show admin notice to ask user to fix that first before creating a staging site
  • Fix: WP Staging welcome screen shown when any plugin is activated
  • Fix: Lower default settings to 10000, cpu load low. File copy limit to 50
Download this release

Release Info

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

Code changes from version 2.3.6 to 2.3.7

Files changed (34) hide show
  1. apps/Backend/Activation/Activation.php +13 -13
  2. apps/Backend/Administrator.php +5 -1
  3. apps/Backend/Modules/Jobs/Job.php +22 -7
  4. apps/Backend/Modules/Jobs/Multisite/Data.php +113 -53
  5. apps/Backend/Modules/Jobs/Multisite/Directories.php +60 -21
  6. apps/Backend/Modules/Jobs/Multisite/Files.php +29 -15
  7. apps/Backend/Modules/Jobs/Multisite/Finish.php +3 -3
  8. apps/Backend/Modules/Jobs/Multisite/SearchReplace.php +133 -34
  9. apps/Backend/Modules/Jobs/Scan.php +12 -10
  10. apps/Backend/Modules/Jobs/SearchReplace.php +8 -4
  11. apps/Backend/Modules/Jobs/Updating.php +239 -232
  12. apps/Backend/Modules/SystemInfo.php +9 -4
  13. apps/Backend/Notices/Notices.php +29 -17
  14. apps/Backend/public/css/wpstg-admin.css +14 -0
  15. apps/Backend/public/js/wpstg-admin.js +61 -39
  16. apps/Backend/views/_includes/messages/beta.php +1 -1
  17. apps/Backend/views/_includes/messages/cache-directory-permission-problem.php +1 -1
  18. apps/Backend/views/_includes/messages/logs-directory-permission-problem.php +1 -1
  19. apps/Backend/views/_includes/messages/staging-directory-permission-problem.php +1 -1
  20. apps/Backend/views/_includes/messages/uploads-cache-directory-permission-problem.php +1 -1
  21. apps/Backend/views/_includes/messages/vars-directory-permission-problem.php +1 -1
  22. apps/Backend/views/_includes/messages/wp-version-compatible-message.php +1 -1
  23. apps/Backend/views/_includes/messages/wrong-scheme.php +7 -0
  24. apps/Backend/views/clone/ajax/start.php +4 -0
  25. apps/Backend/views/welcome/welcome.php +2 -1
  26. apps/Core/Utils/Cache.php +188 -205
  27. apps/Core/Utils/Multisite.php +38 -5
  28. apps/Core/Utils/requirements-check.php +70 -0
  29. apps/Core/WPStaging.php +3 -3
  30. install.php +46 -0
  31. languages/wp-staging-it_1.mo +0 -0
  32. languages/wp-staging-it_1.po +418 -0
  33. readme.txt +14 -2
  34. wp-staging.php +60 -31
apps/Backend/Activation/Activation.php CHANGED
@@ -8,7 +8,7 @@ if( !defined( "WPINC" ) ) {
8
  }
9
 
10
  use WPStaging\WPStaging;
11
- use WPStaging\Backend\Optimizer\Optimizer;
12
  use WPStaging\Cron\Cron;
13
 
14
  class Activation {
@@ -45,17 +45,17 @@ class Activation {
45
  }
46
  }
47
 
48
- public static function install_dependancies() {
49
- // Register cron job.
50
- $cron = new \WPStaging\Cron\Cron;
51
- $cron->schedule_event();
52
-
53
- // Install Optimizer
54
- $optimizer = new Optimizer();
55
- $optimizer->installOptimizer();
56
-
57
- // Add the transient to redirect for class Welcome (not for multisites)
58
- set_transient( 'wpstg_activation_redirect', true, 3600 );
59
- }
60
 
61
  }
8
  }
9
 
10
  use WPStaging\WPStaging;
11
+ //use WPStaging\Backend\Optimizer\Optimizer;
12
  use WPStaging\Cron\Cron;
13
 
14
  class Activation {
45
  }
46
  }
47
 
48
+ // public static function install_dependancies() {
49
+ // // Register cron job.
50
+ // $cron = new \WPStaging\Cron\Cron;
51
+ // $cron->schedule_event();
52
+ //
53
+ // // Install Optimizer
54
+ // $optimizer = new Optimizer();
55
+ // $optimizer->installOptimizer();
56
+ //
57
+ // // Add the transient to redirect for class Welcome (not for multisites)
58
+ // set_transient( 'wpstg_activation_redirect', true, 3600 );
59
+ // }
60
 
61
  }
apps/Backend/Administrator.php CHANGED
@@ -80,7 +80,7 @@ class Administrator extends InjectionAware {
80
  $Welcome = new Activation\Welcome();
81
 
82
  $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
83
- $loader->addAction( "activated_plugin", $Activation, 'install_dependancies' );
84
  $loader->addAction( "admin_menu", $this, "addMenu", 10 );
85
  $loader->addAction( "admin_init", $this, "setOptionFormElements" );
86
  $loader->addAction( "admin_init", $this, "upgrade" );
@@ -483,6 +483,10 @@ class Administrator extends InjectionAware {
483
 
484
  $cloning = new Cloning();
485
 
 
 
 
 
486
  wp_send_json( $cloning->start() );
487
  }
488
 
80
  $Welcome = new Activation\Welcome();
81
 
82
  $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
83
+ //$loader->addAction( "activated_plugin", $Activation, 'install_dependancies' );
84
  $loader->addAction( "admin_menu", $this, "addMenu", 10 );
85
  $loader->addAction( "admin_init", $this, "setOptionFormElements" );
86
  $loader->addAction( "admin_init", $this, "upgrade" );
483
 
484
  $cloning = new Cloning();
485
 
486
+ // Uncomment these lines to test different error codes
487
+ //http_response_code(504);
488
+ //wp_send_json( '<html><body><head></head><body>test</body></html>' );
489
+
490
  wp_send_json( $cloning->start() );
491
  }
492
 
apps/Backend/Modules/Jobs/Job.php CHANGED
@@ -80,10 +80,22 @@ abstract class Job implements JobInterface {
80
  protected $maxRecursionLimit;
81
 
82
  /**
83
- * Multisite Home Url
84
  * @var string
85
  */
86
- protected $multisiteHomeUrl;
 
 
 
 
 
 
 
 
 
 
 
 
87
 
88
  /**
89
  * @var int
@@ -99,7 +111,10 @@ abstract class Job implements JobInterface {
99
  $this->maxMemoryLimit = $this->getMemoryInBytes( @ini_get( "memory_limit" ) );
100
 
101
  $multisite = new Multisite;
102
- $this->multisiteHomeUrl = $multisite->getHomeURL();
 
 
 
103
 
104
  //$this->maxExecutionTime = (int) ini_get("max_execution_time");
105
  $this->maxExecutionTime = ( int ) 30;
@@ -172,11 +187,11 @@ abstract class Job implements JobInterface {
172
  * Set default settings
173
  */
174
  protected function setDefaultSettings() {
175
- $this->settings->queryLimit = "20000";
176
  $this->settings->querySRLimit = "5000";
177
- $this->settings->fileLimit = "1";
178
  $this->settings->batchSize = "2";
179
- $this->settings->cpuLoad = 'medium';
180
  $this->settings->maxFileSize = 8;
181
  update_option( 'wpstg_settings', $this->settings );
182
  }
@@ -187,7 +202,7 @@ abstract class Job implements JobInterface {
187
  protected function setLimits() {
188
 
189
  if( !isset( $this->settings->cpuLoad ) ) {
190
- $this->settings->cpuLoad = "medium";
191
  }
192
 
193
  $memoryLimit = self::MAX_MEMORY_RATIO;
80
  protected $maxRecursionLimit;
81
 
82
  /**
83
+ * Multisite Home Url without Scheme
84
  * @var string
85
  */
86
+ protected $multisiteHomeUrlWithoutScheme;
87
+
88
+ /**
89
+ * Multisite home domain without scheme
90
+ * @var type
91
+ */
92
+ protected $multisiteDomainWithoutScheme;
93
+
94
+ /**
95
+ * Multisite home domain without scheme
96
+ * @var type
97
+ */
98
+ protected $multisiteHomeDomain;
99
 
100
  /**
101
  * @var int
111
  $this->maxMemoryLimit = $this->getMemoryInBytes( @ini_get( "memory_limit" ) );
112
 
113
  $multisite = new Multisite;
114
+ $this->multisiteHomeUrlWithoutScheme = $multisite->getHomeUrlWithoutScheme();
115
+ $this->multisiteHomeDomain = $multisite->getHomeDomain();
116
+ $this->multisiteDomainWithoutScheme = $multisite->getHomeDomainWithoutScheme();
117
+ //$this->multisiteUrl = $multisite->getHomeDomain();
118
 
119
  //$this->maxExecutionTime = (int) ini_get("max_execution_time");
120
  $this->maxExecutionTime = ( int ) 30;
187
  * Set default settings
188
  */
189
  protected function setDefaultSettings() {
190
+ $this->settings->queryLimit = "10000";
191
  $this->settings->querySRLimit = "5000";
192
+ $this->settings->fileLimit = "50";
193
  $this->settings->batchSize = "2";
194
+ $this->settings->cpuLoad = 'low';
195
  $this->settings->maxFileSize = 8;
196
  update_option( 'wpstg_settings', $this->settings );
197
  }
202
  protected function setLimits() {
203
 
204
  if( !isset( $this->settings->cpuLoad ) ) {
205
+ $this->settings->cpuLoad = "low";
206
  }
207
 
208
  $memoryLimit = self::MAX_MEMORY_RATIO;
apps/Backend/Modules/Jobs/Multisite/Data.php CHANGED
@@ -29,7 +29,7 @@ class Data extends JobExecutable {
29
  * @var string
30
  */
31
  private $prefix;
32
-
33
  /**
34
  * Tables e.g wpstg3_options
35
  * @var array
@@ -51,27 +51,27 @@ class Data extends JobExecutable {
51
  $this->options->currentStep = 1;
52
  }
53
  }
54
-
55
  /**
56
  * Get a list of tables to copy
57
  */
58
- private function getTables(){
59
  $strings = new Strings();
60
  $this->tables = array();
61
- foreach($this->options->tables as $table){
62
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
63
  }
64
  // Add extra global tables from main multisite (wpstgx_users and wpstgx_usermeta)
65
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, 'users' );
66
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, 'usermeta' );
67
-
68
  }
 
69
  /**
70
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
71
  * @return void
72
  */
73
  protected function calculateTotalSteps() {
74
- $this->options->totalSteps = 15;
75
  }
76
 
77
  /**
@@ -157,7 +157,7 @@ class Data extends JobExecutable {
157
  }
158
 
159
  // Live Path === Staging path
160
- if( $this->multisiteHomeUrl . $this->options->cloneDirectoryName === $this->multisiteHomeUrl ) {
161
  return true;
162
  }
163
 
@@ -247,26 +247,26 @@ class Data extends JobExecutable {
247
  return true;
248
  }
249
  // Skip - Table is not selected or updated
250
- if (!in_array($this->prefix . 'options', $this->tables)){
251
- $this->log("Preparing Data Step1: Skipping");
252
  return true;
253
  }
254
 
255
  // Installed in sub-directory
256
  if( $this->isSubDir() ) {
257
- $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName );
258
  // Replace URLs
259
  $result = $this->db->query(
260
  $this->db->prepare(
261
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", rtrim( $this->multisiteHomeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName
262
  )
263
  );
264
  } else {
265
- $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeUrl, "/" ) . '/' . $this->options->cloneDirectoryName );
266
  // Replace URLs
267
  $result = $this->db->query(
268
  $this->db->prepare(
269
- "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->multisiteHomeUrl . '/' . $this->options->cloneDirectoryName
270
  )
271
  );
272
  }
@@ -288,14 +288,14 @@ class Data extends JobExecutable {
288
  protected function step2() {
289
 
290
  $this->log( "Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
291
-
292
  // Skip - Table does not exist
293
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
294
  return true;
295
  }
296
  // Skip - Table is not selected or updated
297
- if (!in_array($this->prefix . 'options', $this->tables)){
298
- $this->log("Preparing Data Step2: Skipping");
299
  return true;
300
  }
301
 
@@ -330,15 +330,15 @@ class Data extends JobExecutable {
330
  protected function step3() {
331
 
332
  $this->log( "Preparing Data Step3: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}" );
333
-
334
  // Skip - Table does not exist
335
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
336
  return true;
337
  }
338
-
339
  // Skip - Table is not selected or updated
340
- if (!in_array($this->prefix . 'options', $this->tables)){
341
- $this->log( "Preparing Data Step3: Skipping" );
342
  return true;
343
  }
344
 
@@ -368,10 +368,10 @@ class Data extends JobExecutable {
368
  if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
369
  return true;
370
  }
371
-
372
  // Skip - Table is not selected or updated
373
- if (!in_array($this->prefix . 'usermeta', $this->tables)){
374
- $this->log("Preparing Data Step4: Skipping");
375
  return true;
376
  }
377
 
@@ -406,7 +406,7 @@ class Data extends JobExecutable {
406
  $content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
407
 
408
  // Replace URLs
409
- $content = str_replace( $this->multisiteHomeUrl, $this->multisiteHomeUrl . '/' . $this->options->cloneDirectoryName, $content );
410
 
411
  if( false === @file_put_contents( $path, $content ) ) {
412
  $this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
@@ -473,15 +473,15 @@ class Data extends JobExecutable {
473
  protected function step7() {
474
 
475
  $this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
476
-
477
  // Skip - Table does not exist
478
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
479
  return true;
480
  }
481
-
482
  // Skip - Table is not selected or updated
483
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
484
- $this->log("Preparing Data Step7: Skipping");
485
  return true;
486
  }
487
 
@@ -508,18 +508,18 @@ class Data extends JobExecutable {
508
  protected function step8() {
509
 
510
  $this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
511
-
512
  // Skip - Table does not exist
513
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
514
  return true;
515
  }
516
-
517
  // Skip - Table is not selected or updated
518
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
519
  $this->log( "Preparing Data Step8: Skipping" );
520
  return true;
521
  }
522
-
523
  $result = $this->db->query(
524
  $this->db->prepare(
525
  "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
@@ -547,13 +547,13 @@ class Data extends JobExecutable {
547
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
548
  return true;
549
  }
550
-
551
  // Skip - Table is not selected or updated
552
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
553
  $this->log( "Preparing Data Step9: Skipping" );
554
  return true;
555
  }
556
-
557
  $result = $this->db->query(
558
  $this->db->prepare(
559
  "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
@@ -755,13 +755,13 @@ class Data extends JobExecutable {
755
  $this->returnException( 'Data Crunching Step 8: Fatal Error ' . $this->prefix . 'options does not exist' );
756
  return false;
757
  }
758
-
759
  // Skip - Table is not selected or updated
760
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
761
- $this->log("Preparing Data Step14: Skipping");
762
  return true;
763
  }
764
-
765
  // Get active_plugins value from sub site options table
766
  $active_plugins = $this->db->get_var( "SELECT option_value FROM {$this->db->prefix}options WHERE option_name = 'active_plugins' " );
767
 
@@ -799,41 +799,41 @@ class Data extends JobExecutable {
799
  $this->log( "Data Crunching Step 14: Successfull!" );
800
  return true;
801
  }
802
-
803
  /**
804
  * Update Table Prefix in wp_options
805
  * @return bool
806
  */
807
  protected function step15() {
808
- $this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options. Error: {$this->db->last_error}" );
809
 
810
  // Skip - Table does not exist
811
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
812
  return true;
813
  }
814
-
815
  // Skip - Table is not selected or updated
816
- if (!in_array($this->prefix . 'options', $this->tables)){
817
- $this->log("Preparing Data Step4: Skipping");
818
  return true;
819
  }
820
 
821
-
822
- $this->log( "Updating db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
823
-
824
  // Filter the rows below. Do not update them!
825
  $filters = array(
826
  'wp_mail_smtp',
827
  'wp_mail_smtp_version',
828
  'wp_mail_smtp_debug',
829
  );
830
-
831
- $filters = apply_filters('wpstg_data_excl_rows', $filters);
832
-
833
  $where = "";
834
- foreach($filters as $filter){
835
  $where .= " AND option_name <> '" . $filter . "'";
836
- }
837
 
838
  $updateOptions = $this->db->query(
839
  $this->db->prepare(
@@ -849,8 +849,63 @@ class Data extends JobExecutable {
849
 
850
  return true;
851
  }
852
-
853
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
854
 
855
  /**
856
  * Return URL to staging site
@@ -858,10 +913,10 @@ class Data extends JobExecutable {
858
  */
859
  protected function getStagingSiteUrl() {
860
  if( $this->isSubDir() ) {
861
- return rtrim( $this->multisiteHomeUrl, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName;
862
  }
863
 
864
- return rtrim( $this->multisiteHomeUrl, "/" ) . '/' . $this->options->cloneDirectoryName;
865
  }
866
 
867
  /**
@@ -869,7 +924,12 @@ class Data extends JobExecutable {
869
  * @return boolean
870
  */
871
  protected function isSubDir() {
872
- if( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
 
 
 
 
 
873
  return true;
874
  }
875
  return false;
29
  * @var string
30
  */
31
  private $prefix;
32
+
33
  /**
34
  * Tables e.g wpstg3_options
35
  * @var array
51
  $this->options->currentStep = 1;
52
  }
53
  }
54
+
55
  /**
56
  * Get a list of tables to copy
57
  */
58
+ private function getTables() {
59
  $strings = new Strings();
60
  $this->tables = array();
61
+ foreach ( $this->options->tables as $table ) {
62
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
63
  }
64
  // Add extra global tables from main multisite (wpstgx_users and wpstgx_usermeta)
65
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, 'users' );
66
  $this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, 'usermeta' );
 
67
  }
68
+
69
  /**
70
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
71
  * @return void
72
  */
73
  protected function calculateTotalSteps() {
74
+ $this->options->totalSteps = 16;
75
  }
76
 
77
  /**
157
  }
158
 
159
  // Live Path === Staging path
160
+ if( $this->multisiteHomeDomain . $this->options->cloneDirectoryName === $this->multisiteHomeDomain ) {
161
  return true;
162
  }
163
 
247
  return true;
248
  }
249
  // Skip - Table is not selected or updated
250
+ if( !in_array( $this->prefix . 'options', $this->tables ) ) {
251
+ $this->log( "Preparing Data Step1: Skipping" );
252
  return true;
253
  }
254
 
255
  // Installed in sub-directory
256
  if( $this->isSubDir() ) {
257
+ $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName );
258
  // Replace URLs
259
  $result = $this->db->query(
260
  $this->db->prepare(
261
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", rtrim( $this->multisiteHomeDomain, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName
262
  )
263
  );
264
  } else {
265
+ $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName );
266
  // Replace URLs
267
  $result = $this->db->query(
268
  $this->db->prepare(
269
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName
270
  )
271
  );
272
  }
288
  protected function step2() {
289
 
290
  $this->log( "Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
291
+
292
  // Skip - Table does not exist
293
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
294
  return true;
295
  }
296
  // Skip - Table is not selected or updated
297
+ if( !in_array( $this->prefix . 'options', $this->tables ) ) {
298
+ $this->log( "Preparing Data Step2: Skipping" );
299
  return true;
300
  }
301
 
330
  protected function step3() {
331
 
332
  $this->log( "Preparing Data Step3: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}" );
333
+
334
  // Skip - Table does not exist
335
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
336
  return true;
337
  }
338
+
339
  // Skip - Table is not selected or updated
340
+ if( !in_array( $this->prefix . 'options', $this->tables ) ) {
341
+ $this->log( "Preparing Data Step3: Skipping" );
342
  return true;
343
  }
344
 
368
  if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
369
  return true;
370
  }
371
+
372
  // Skip - Table is not selected or updated
373
+ if( !in_array( $this->prefix . 'usermeta', $this->tables ) ) {
374
+ $this->log( "Preparing Data Step4: Skipping" );
375
  return true;
376
  }
377
 
406
  $content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
407
 
408
  // Replace URLs
409
+ $content = str_replace( $this->multisiteHomeDomain, $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName, $content );
410
 
411
  if( false === @file_put_contents( $path, $content ) ) {
412
  $this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
473
  protected function step7() {
474
 
475
  $this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
476
+
477
  // Skip - Table does not exist
478
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
479
  return true;
480
  }
481
+
482
  // Skip - Table is not selected or updated
483
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
484
+ $this->log( "Preparing Data Step7: Skipping" );
485
  return true;
486
  }
487
 
508
  protected function step8() {
509
 
510
  $this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
511
+
512
  // Skip - Table does not exist
513
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
514
  return true;
515
  }
516
+
517
  // Skip - Table is not selected or updated
518
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
519
  $this->log( "Preparing Data Step8: Skipping" );
520
  return true;
521
  }
522
+
523
  $result = $this->db->query(
524
  $this->db->prepare(
525
  "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
547
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
548
  return true;
549
  }
550
+
551
  // Skip - Table is not selected or updated
552
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
553
  $this->log( "Preparing Data Step9: Skipping" );
554
  return true;
555
  }
556
+
557
  $result = $this->db->query(
558
  $this->db->prepare(
559
  "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
755
  $this->returnException( 'Data Crunching Step 8: Fatal Error ' . $this->prefix . 'options does not exist' );
756
  return false;
757
  }
758
+
759
  // Skip - Table is not selected or updated
760
  if( !in_array( $this->prefix . 'options', $this->tables ) ) {
761
+ $this->log( "Preparing Data Step14: Skipping" );
762
  return true;
763
  }
764
+
765
  // Get active_plugins value from sub site options table
766
  $active_plugins = $this->db->get_var( "SELECT option_value FROM {$this->db->prefix}options WHERE option_name = 'active_plugins' " );
767
 
799
  $this->log( "Data Crunching Step 14: Successfull!" );
800
  return true;
801
  }
802
+
803
  /**
804
  * Update Table Prefix in wp_options
805
  * @return bool
806
  */
807
  protected function step15() {
808
+ $this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options." );
809
 
810
  // Skip - Table does not exist
811
  if( false === $this->isTable( $this->prefix . 'options' ) ) {
812
  return true;
813
  }
814
+
815
  // Skip - Table is not selected or updated
816
+ if( !in_array( $this->prefix . 'options', $this->tables ) ) {
817
+ $this->log( "Preparing Data Step4: Skipping" );
818
  return true;
819
  }
820
 
821
+
822
+ $this->log( "Updating db option_names in {$this->prefix}options. " );
823
+
824
  // Filter the rows below. Do not update them!
825
  $filters = array(
826
  'wp_mail_smtp',
827
  'wp_mail_smtp_version',
828
  'wp_mail_smtp_debug',
829
  );
830
+
831
+ $filters = apply_filters( 'wpstg_data_excl_rows', $filters );
832
+
833
  $where = "";
834
+ foreach ( $filters as $filter ) {
835
  $where .= " AND option_name <> '" . $filter . "'";
836
+ }
837
 
838
  $updateOptions = $this->db->query(
839
  $this->db->prepare(
849
 
850
  return true;
851
  }
852
+
853
+ /**
854
+ * Change upload_path in wp_options (if it is defined)
855
+ * @return bool
856
+ */
857
+ protected function step16() {
858
+ $this->log( "Preparing Data Step16: Updating upload_path {$this->prefix}options." );
859
+
860
+ // Skip - Table does not exist
861
+ if( false === $this->isTable( $this->prefix . 'options' ) ) {
862
+ return true;
863
+ }
864
+
865
+ $newUploadPath = $this->getNewUploadPath();
866
+
867
+ if( false === $newUploadPath ) {
868
+ $this->log( "Preparing Data Step16: Skipping" );
869
+ return true;
870
+ }
871
+
872
+ // Skip - Table is not selected or updated
873
+ if( !in_array( $this->prefix . 'options', $this->tables ) ) {
874
+ $this->log( "Preparing Data Step16: Skipping" );
875
+ return true;
876
+ }
877
+
878
+ $error = isset( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
879
+
880
+ $this->log( "Updating upload_path in {$this->prefix}options. {$error}" );
881
+
882
+ $updateOptions = $this->db->query(
883
+ $this->db->prepare(
884
+ "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
885
+ )
886
+ );
887
+
888
+ if( !$updateOptions ) {
889
+ $this->log( "Preparing Data Step16: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
890
+ return true;
891
+ }
892
+ $this->Log( "Preparing Data: Finished Step 16 successfully" );
893
+ return true;
894
+ }
895
+
896
+ protected function getNewUploadPath() {
897
+ $uploadPath = get_option( 'upload_path' );
898
+
899
+ if( !$uploadPath ) {
900
+ return false;
901
+ }
902
+
903
+ $customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
904
+
905
+ $newUploadPath = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR . $customSlug;
906
+
907
+ return $newUploadPath;
908
+ }
909
 
910
  /**
911
  * Return URL to staging site
913
  */
914
  protected function getStagingSiteUrl() {
915
  if( $this->isSubDir() ) {
916
+ return rtrim( $this->multisiteHomeDomain, "/" ) . $this->getSubDir() . $this->options->cloneDirectoryName;
917
  }
918
 
919
+ return rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName;
920
  }
921
 
922
  /**
924
  * @return boolean
925
  */
926
  protected function isSubDir() {
927
+ // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
928
+ // This is happening much more often than you would expect
929
+ $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
930
+ $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
931
+
932
+ if( $home !== $siteurl ) {
933
  return true;
934
  }
935
  return false;
apps/Backend/Modules/Jobs/Multisite/Directories.php CHANGED
@@ -100,7 +100,6 @@ class Directories extends JobExecutable {
100
  }
101
  } catch ( \Exception $e ) {
102
  $this->returnException( 'Error: ' . $e->getMessage() );
103
- //throw new \Exception('Out of disk space.');
104
  } catch ( \Exception $e ) {
105
  // Skip bad file permissions
106
  }
@@ -117,7 +116,7 @@ class Directories extends JobExecutable {
117
 
118
  // Skip it
119
  if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
120
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR);
121
  return true;
122
  }
123
  // open file handle
@@ -131,7 +130,7 @@ class Directories extends JobExecutable {
131
  'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
132
  'uploads' . DIRECTORY_SEPARATOR . 'sites'
133
  );
134
-
135
  /**
136
  * Get user excluded folders
137
  */
@@ -169,7 +168,8 @@ class Directories extends JobExecutable {
169
  // Write path line
170
  foreach ( $iterator as $item ) {
171
  if( $item->isFile() ) {
172
- if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
 
173
  $this->options->totalFiles++;
174
 
175
  // Add current file size
@@ -178,8 +178,8 @@ class Directories extends JobExecutable {
178
  }
179
  }
180
  } catch ( \Exception $e ) {
181
- //$this->returnException('Out of disk space.');
182
- throw new \Exception( 'Error: ' . $e->getMessage() );
183
  } catch ( \Exception $e ) {
184
  // Skip bad file permissions
185
  }
@@ -198,7 +198,7 @@ class Directories extends JobExecutable {
198
 
199
  // Skip it
200
  if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
201
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR);
202
  return true;
203
  }
204
 
@@ -250,7 +250,7 @@ class Directories extends JobExecutable {
250
 
251
  // Skip it
252
  if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
253
- $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR);
254
  return true;
255
  }
256
 
@@ -291,20 +291,28 @@ class Directories extends JobExecutable {
291
  $this->close( $files );
292
  return true;
293
  }
294
-
295
  /**
296
  * Step 4
297
- * Get WP Content Uploads Files multisite folder wp-content/uploads/sites
298
  */
299
  private function getWpContentUploadsSites() {
300
-
 
301
  if( is_main_site() ) {
302
  return true;
303
  }
304
-
305
  $blogId = get_current_blog_id();
306
 
307
- $path = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blogId . DIRECTORY_SEPARATOR;
 
 
 
 
 
 
 
308
 
309
  // Skip it
310
  if( $this->isDirectoryExcluded( $path ) ) {
@@ -323,7 +331,7 @@ class Directories extends JobExecutable {
323
  'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
324
  'uploads' . DIRECTORY_SEPARATOR . 'sites'
325
  );
326
-
327
  /**
328
  * Get user excluded folders
329
  */
@@ -346,6 +354,7 @@ class Directories extends JobExecutable {
346
 
347
  // Exclude sites, uploads, plugins or themes
348
  $iterator = new \WPStaging\Iterators\RecursiveFilterExclude( $iterator, $excludePaths );
 
349
  // Recursively iterate over content directory
350
  $iterator = new \RecursiveIteratorIterator( $iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD );
351
  $this->log( "Scanning /wp-content/uploads/sites/{$blogId} for its sub-directories and files" );
@@ -353,8 +362,9 @@ class Directories extends JobExecutable {
353
  // Write path line
354
  foreach ( $iterator as $item ) {
355
  if( $item->isFile() ) {
356
- $test = $iterator->getSubPathName();
357
- if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blogId . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
 
358
  $this->options->totalFiles++;
359
 
360
  // Add current file size
@@ -363,8 +373,8 @@ class Directories extends JobExecutable {
363
  }
364
  }
365
  } catch ( \Exception $e ) {
366
- //$this->returnException('Out of disk space.');
367
- throw new \Exception( 'Error: ' . $e->getMessage() );
368
  } catch ( \Exception $e ) {
369
  // Skip bad file permissions
370
  }
@@ -374,6 +384,36 @@ class Directories extends JobExecutable {
374
  return true;
375
  }
376
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  /**
378
  * Step 5 - x
379
  * Get extra folders of the wp root level
@@ -525,7 +565,7 @@ class Directories extends JobExecutable {
525
  $this->prepareResponse( false, true );
526
  return false;
527
  }
528
-
529
  if( $this->options->currentStep == 4 ) {
530
  $this->getWpContentUploadsSites();
531
  $this->prepareResponse( false, true );
@@ -583,7 +623,6 @@ class Directories extends JobExecutable {
583
  $this->files = explode( PHP_EOL, $this->files );
584
  }
585
 
586
-
587
  /**
588
  * Replace forward slash with current directory separator
589
  *
@@ -605,7 +644,7 @@ class Directories extends JobExecutable {
605
  $directory = $this->sanitizeDirectorySeparator( $directory );
606
  foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
607
  $excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
608
- if( strpos( $directory, $excludedDirectory ) === 0 ) {
609
  return true;
610
  }
611
  }
100
  }
101
  } catch ( \Exception $e ) {
102
  $this->returnException( 'Error: ' . $e->getMessage() );
 
103
  } catch ( \Exception $e ) {
104
  // Skip bad file permissions
105
  }
116
 
117
  // Skip it
118
  if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
119
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR );
120
  return true;
121
  }
122
  // open file handle
130
  'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
131
  'uploads' . DIRECTORY_SEPARATOR . 'sites'
132
  );
133
+
134
  /**
135
  * Get user excluded folders
136
  */
168
  // Write path line
169
  foreach ( $iterator as $item ) {
170
  if( $item->isFile() ) {
171
+ $file = 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL;
172
+ if( $this->write( $files, $file ) ) {
173
  $this->options->totalFiles++;
174
 
175
  // Add current file size
178
  }
179
  }
180
  } catch ( \Exception $e ) {
181
+ $this->returnException( 'Error: ' . $e->getMessage() );
182
+ //throw new \Exception( 'Error: ' . $e->getMessage() );
183
  } catch ( \Exception $e ) {
184
  // Skip bad file permissions
185
  }
198
 
199
  // Skip it
200
  if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
201
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR );
202
  return true;
203
  }
204
 
250
 
251
  // Skip it
252
  if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
253
+ $this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR );
254
  return true;
255
  }
256
 
291
  $this->close( $files );
292
  return true;
293
  }
294
+
295
  /**
296
  * Step 4
297
+ * Get WP Content Uploads Files multisite folder wp-content/uploads/sites or wp-content/blogs.dir/ID/files
298
  */
299
  private function getWpContentUploadsSites() {
300
+
301
+ // Skip if main site is cloned
302
  if( is_main_site() ) {
303
  return true;
304
  }
305
+
306
  $blogId = get_current_blog_id();
307
 
308
+ // Absolute path to uploads folder
309
+ //$path = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blogId . DIRECTORY_SEPARATOR;
310
+ $path = $this->getAbsUploadPath();
311
+
312
+ // Skip it
313
+ if( !is_dir( $path ) ) {
314
+ return true;
315
+ }
316
 
317
  // Skip it
318
  if( $this->isDirectoryExcluded( $path ) ) {
331
  'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
332
  'uploads' . DIRECTORY_SEPARATOR . 'sites'
333
  );
334
+
335
  /**
336
  * Get user excluded folders
337
  */
354
 
355
  // Exclude sites, uploads, plugins or themes
356
  $iterator = new \WPStaging\Iterators\RecursiveFilterExclude( $iterator, $excludePaths );
357
+
358
  // Recursively iterate over content directory
359
  $iterator = new \RecursiveIteratorIterator( $iterator, \RecursiveIteratorIterator::LEAVES_ONLY, \RecursiveIteratorIterator::CATCH_GET_CHILD );
360
  $this->log( "Scanning /wp-content/uploads/sites/{$blogId} for its sub-directories and files" );
362
  // Write path line
363
  foreach ( $iterator as $item ) {
364
  if( $item->isFile() ) {
365
+ //$file = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . $blogId . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL;
366
+ $file = $this->getRelUploadPath() . $iterator->getSubPathName() . PHP_EOL;
367
+ if( $this->write( $files, $file ) ) {
368
  $this->options->totalFiles++;
369
 
370
  // Add current file size
373
  }
374
  }
375
  } catch ( \Exception $e ) {
376
+ $this->returnException( 'Error: ' . $e->getMessage() );
377
+ //throw new \Exception( 'Error: ' . $e->getMessage() );
378
  } catch ( \Exception $e ) {
379
  // Skip bad file permissions
380
  }
384
  return true;
385
  }
386
 
387
+ /**
388
+ * Get absolute path to the upload folder e.g. /srv/www/wp-content/blogs.dir/ID/files or /srv/www/wp-content/uploads/sites/ID/
389
+ * @return type
390
+ */
391
+ private function getAbsUploadPath() {
392
+ // Check first which method is used
393
+ $uploads = wp_upload_dir();
394
+ $basedir = $uploads['basedir'];
395
+
396
+ return trailingslashit($basedir);
397
+
398
+ // if( false === strpos( $basedir, 'blogs.dir' ) ) {
399
+ // // Since WP 3.5
400
+ // return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
401
+ // } else {
402
+ // // old blog structure
403
+ // return 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
404
+ // }
405
+ }
406
+ /**
407
+ * Get relative path to the upload folder like wp-content/uploads or wp-content/blogs.dir/2/files
408
+ * @return string
409
+ */
410
+ private function getRelUploadPath() {
411
+ $uploads = wp_upload_dir();
412
+ $basedir = $uploads['basedir'];
413
+
414
+ return trailingslashit(str_replace(\WPStaging\WPStaging::getWPpath(), '', $basedir));
415
+ }
416
+
417
  /**
418
  * Step 5 - x
419
  * Get extra folders of the wp root level
565
  $this->prepareResponse( false, true );
566
  return false;
567
  }
568
+
569
  if( $this->options->currentStep == 4 ) {
570
  $this->getWpContentUploadsSites();
571
  $this->prepareResponse( false, true );
623
  $this->files = explode( PHP_EOL, $this->files );
624
  }
625
 
 
626
  /**
627
  * Replace forward slash with current directory separator
628
  *
644
  $directory = $this->sanitizeDirectorySeparator( $directory );
645
  foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
646
  $excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
647
+ if( strpos( trailingslashit( $directory ), trailingslashit( $excludedDirectory ) ) === 0 ) {
648
  return true;
649
  }
650
  }
apps/Backend/Modules/Jobs/Multisite/Files.php CHANGED
@@ -36,7 +36,7 @@ class Files extends JobExecutable {
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
 
@@ -152,7 +152,7 @@ class Files extends JobExecutable {
152
  * @return bool
153
  */
154
  private function copyFile( $file ) {
155
- $file = trim( ABSPATH . $file );
156
 
157
  $directory = dirname( $file );
158
 
@@ -215,8 +215,8 @@ class Files extends JobExecutable {
215
  * @return bool|string
216
  */
217
  private function getDestination( $file ) {
218
- $file = $this->replaceMultisiteUploadFolder( $file );
219
- $relativePath = str_replace( ABSPATH, null, $file );
220
  $destinationPath = $this->destination . $relativePath;
221
  $destinationDirectory = dirname( $destinationPath );
222
 
@@ -228,6 +228,31 @@ class Files extends JobExecutable {
228
  return $destinationPath;
229
  }
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  /**
232
  * Copy bigger files than $this->settings->batchSize
233
  * @param string $src
@@ -337,15 +362,4 @@ class Files extends JobExecutable {
337
  return false;
338
  }
339
 
340
- /**
341
- * Replace relative path of file if its located in multisite upload folder wp-content/uploads/sites/x/
342
- * @return boolean
343
- */
344
- private function replaceMultisiteUploadFolder( $file ) {
345
- $search = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
346
- $replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
347
-
348
- return str_replace( $search, $replace, $file );
349
- }
350
-
351
  }
36
  */
37
  public function initialize() {
38
 
39
+ $this->destination = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR;
40
 
41
  $filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
42
 
152
  * @return bool
153
  */
154
  private function copyFile( $file ) {
155
+ $file = trim( \WPStaging\WPStaging::getWPpath() . $file );
156
 
157
  $directory = dirname( $file );
158
 
215
  * @return bool|string
216
  */
217
  private function getDestination( $file ) {
218
+ $file = $this->getMultisiteUploadFolder( $file );
219
+ $relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
220
  $destinationPath = $this->destination . $relativePath;
221
  $destinationDirectory = dirname( $destinationPath );
222
 
228
  return $destinationPath;
229
  }
230
 
231
+ /**
232
+ * Replace relative path of file if its located in multisite upload folder
233
+ * wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
234
+ * @return boolean
235
+ */
236
+ private function getMultisiteUploadFolder( $file ) {
237
+ // Check first which method is used
238
+ $uploads = wp_upload_dir();
239
+ $basedir = $uploads['basedir'];
240
+
241
+ if( false === strpos( $basedir, 'blogs.dir' ) ) {
242
+ // Since WP 3.5
243
+ $search = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
244
+ $replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
245
+ $uploadsFolder = str_replace( $search, $replace, $file );
246
+ } else {
247
+ // old blog structure
248
+ $search = 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
249
+ $replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
250
+ $uploadsFolder = str_replace( $search, $replace, $file );
251
+ }
252
+
253
+ return $uploadsFolder;
254
+ }
255
+
256
  /**
257
  * Copy bigger files than $this->settings->batchSize
258
  * @param string $src
362
  return false;
363
  }
364
 
 
 
 
 
 
 
 
 
 
 
 
365
  }
apps/Backend/Modules/Jobs/Multisite/Finish.php CHANGED
@@ -41,8 +41,8 @@ class Finish extends Job
41
  $return = array(
42
  "directoryName" => $this->options->cloneDirectoryName,
43
  "path" => ABSPATH . $this->options->cloneDirectoryName,
44
- //"url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
45
- "url" => $this->multisiteHomeUrl . '/' . $this->options->cloneDirectoryName,
46
  "number" => $this->options->cloneNumber,
47
  "version" => \WPStaging\WPStaging::VERSION,
48
  "status" => 'finished',
@@ -98,7 +98,7 @@ class Finish extends Job
98
  "directoryName" => $this->options->cloneDirectoryName,
99
  "path" => ABSPATH . $this->options->cloneDirectoryName,
100
  //"url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
101
- "url" => $this->multisiteHomeUrl . '/' . $this->options->cloneDirectoryName,
102
  "number" => $this->options->cloneNumber,
103
  "version" => \WPStaging\WPStaging::VERSION,
104
  "status" => false,
41
  $return = array(
42
  "directoryName" => $this->options->cloneDirectoryName,
43
  "path" => ABSPATH . $this->options->cloneDirectoryName,
44
+ "url" => $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName,
45
+ //"url" => $this->multisiteUrl . '/' . $this->options->cloneDirectoryName,
46
  "number" => $this->options->cloneNumber,
47
  "version" => \WPStaging\WPStaging::VERSION,
48
  "status" => 'finished',
98
  "directoryName" => $this->options->cloneDirectoryName,
99
  "path" => ABSPATH . $this->options->cloneDirectoryName,
100
  //"url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
101
+ "url" => $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName,
102
  "number" => $this->options->cloneNumber,
103
  "version" => \WPStaging\WPStaging::VERSION,
104
  "status" => false,
apps/Backend/Modules/Jobs/Multisite/SearchReplace.php CHANGED
@@ -109,7 +109,6 @@ class SearchReplace extends JobExecutable {
109
  return true;
110
  }
111
 
112
-
113
  /**
114
  * Stop Execution immediately
115
  * return mixed bool | json
@@ -223,30 +222,37 @@ class SearchReplace extends JobExecutable {
223
  if( $this->isSubDir() ) {
224
  // Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
225
  $args['search_for'] = array(
226
- rtrim( $this->multisiteHomeUrl, "/" ) . $this->getSubDir(),
227
  ABSPATH,
228
- str_replace( '/', '\/', rtrim( $this->multisiteHomeUrl, '/' ) ) . str_replace( '/', '\/', $this->getSubDir() ) // // Used by revslider and several visual editors
 
229
  );
230
 
231
 
232
  $args['replace_with'] = array(
233
- rtrim( $this->multisiteHomeUrl, "/" ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName,
234
  rtrim( ABSPATH, '/' ) . '/' . $this->options->cloneDirectoryName,
235
- str_replace( '/', '\/', rtrim( $this->multisiteHomeUrl, "/" ) ) . str_replace( '/', '\/', $this->getSubDir() ) . '\/' . $this->options->cloneDirectoryName, // Used by revslider and several visual editors
 
236
  );
237
  } else {
238
  $args['search_for'] = array(
239
- rtrim( $this->multisiteHomeUrl, '/' ),
240
  ABSPATH,
241
- str_replace( '/', '\/', rtrim( $this->multisiteHomeUrl, '/' ) )
 
242
  );
243
  $args['replace_with'] = array(
244
- rtrim( $this->multisiteHomeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
245
  rtrim( ABSPATH, '/' ) . '/' . $this->options->cloneDirectoryName,
246
- str_replace( '/', '\/', rtrim( $this->multisiteHomeUrl, '/' ) ) . '\/' . $this->options->cloneDirectoryName,
 
247
  );
248
  }
249
 
 
 
 
250
  $args['replace_guids'] = 'off';
251
  $args['dry_run'] = 'off';
252
  $args['case_insensitive'] = false;
@@ -254,8 +260,8 @@ class SearchReplace extends JobExecutable {
254
  $args['replace_mails'] = 'off';
255
 
256
  // Allow filtering of search & replace parameters
257
- $args = apply_filters('wpstg_clone_searchreplace_params', $args);
258
-
259
  // Get a list of columns in this table.
260
  list( $primary_key, $columns ) = $this->get_columns( $table );
261
 
@@ -274,7 +280,7 @@ class SearchReplace extends JobExecutable {
274
  // Grab the content of the table.
275
  $data = $this->db->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
276
 
277
- // Filter certain option_name (of other plugins)
278
  $filter = array(
279
  'Admin_custome_login_Slidshow',
280
  'Admin_custome_login_Social',
@@ -284,13 +290,14 @@ class SearchReplace extends JobExecutable {
284
  'Admin_custome_login_top',
285
  'Admin_custome_login_dashboard',
286
  'Admin_custome_login_Version',
287
- );
288
-
 
289
  apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
290
 
291
  // Loop through the data.
292
  foreach ( $data as $row ) {
293
- //$current_row++;
294
  $update_sql = array();
295
  $where_sql = array();
296
  $upd = false;
@@ -299,12 +306,12 @@ class SearchReplace extends JobExecutable {
299
  if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
300
  continue;
301
  }
302
-
303
  // Skip rows with transients (They can store huge data and we need to save memory)
304
  if( isset( $row['option_name'] ) && strpos( $row['option_name'], '_transient' ) === 0 ) {
305
  continue;
306
  }
307
-
308
 
309
  foreach ( $columns as $column ) {
310
 
@@ -322,7 +329,7 @@ class SearchReplace extends JobExecutable {
322
 
323
 
324
  // Skip mail addresses
325
- if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' . $this->homeUrl ) ) {
326
  continue;
327
  }
328
 
@@ -351,20 +358,21 @@ class SearchReplace extends JobExecutable {
351
  // 1. local.wordpress.test -> local.wordpress.test/staging
352
  // 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
353
  $tmp = $args;
354
- if ( false === strpos( $dataRow, $tmp['search_for'][0] )){
355
- array_shift($tmp['search_for']); // rtrim( $this->homeUrl, '/' ),
356
- array_shift($tmp['replace_with']); // rtrim( $this->homeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
357
  } else {
358
- unset($tmp['search_for'][1]);
359
- unset($tmp['replace_with'][1]);
360
  // recount array
361
- $tmp['search_for'] = array_values($tmp['search_for']);
362
- $tmp['replace_with'] = array_values($tmp['replace_with']);
363
  }
364
 
365
  // Run a search replace on the data row and respect the serialisation.
366
  $i = 0;
367
  foreach ( $tmp['search_for'] as $replace ) {
 
368
  $dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
369
  $i++;
370
  }
@@ -388,7 +396,7 @@ class SearchReplace extends JobExecutable {
388
  $result = $this->db->query( $sql );
389
 
390
  if( !$result ) {
391
- $this->log( "Error updating row {$current_row}", \WPStaging\Utils\Logger::TYPE_ERROR );
392
  }
393
  }
394
  } // end row loop
@@ -403,6 +411,38 @@ class SearchReplace extends JobExecutable {
403
  return true;
404
  }
405
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  /**
407
  * Adapted from interconnect/it's search/replace script.
408
  *
@@ -439,7 +479,7 @@ class SearchReplace extends JobExecutable {
439
  foreach ( $props as $key => $value ) {
440
  if( $key === '' || ord( $key[0] ) === 0 ) {
441
  continue;
442
- }
443
  $tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
444
  }
445
 
@@ -448,10 +488,10 @@ class SearchReplace extends JobExecutable {
448
  } else {
449
  if( is_string( $data ) ) {
450
  if( !empty( $from ) && !empty( $to ) ) {
451
- $data = $this->str_replace( $from, $to, $data, $case_insensitive );
 
452
  }
453
  }
454
- }
455
 
456
  if( $serialized ) {
457
  return serialize( $data );
@@ -463,6 +503,60 @@ class SearchReplace extends JobExecutable {
463
  return $data;
464
  }
465
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
466
  /**
467
  * Check if the object is a valid one and not __PHP_Incomplete_Class_Name
468
  * Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
@@ -489,7 +583,7 @@ class SearchReplace extends JobExecutable {
489
  // // Assume it must be an valid object
490
  // return true;
491
  // }
492
-
493
  /**
494
  * Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
495
  * @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
@@ -547,13 +641,13 @@ class SearchReplace extends JobExecutable {
547
  foreach ( $excludes as $exclude ) {
548
  $regexExclude .= $exclude . '(*SKIP)(FAIL)|';
549
  }
550
-
551
  if( 'on' === $case_insensitive ) {
552
  //$data = str_ireplace( $from, $to, $data );
553
- $data = preg_replace( '#' . $regexExclude . preg_quote ( $from) . '#i', $to, $data );
554
  } else {
555
  //$data = str_replace( $from, $to, $data );
556
- $data = preg_replace( '#' . $regexExclude . preg_quote($from) . '#', $to, $data );
557
  }
558
 
559
  return $data;
@@ -648,7 +742,12 @@ class SearchReplace extends JobExecutable {
648
  * @return boolean
649
  */
650
  private function isSubDir() {
651
- if( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
 
 
 
 
 
652
  return true;
653
  }
654
  return false;
109
  return true;
110
  }
111
 
 
112
  /**
113
  * Stop Execution immediately
114
  * return mixed bool | json
222
  if( $this->isSubDir() ) {
223
  // Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
224
  $args['search_for'] = array(
225
+ rtrim( $this->multisiteHomeUrlWithoutScheme, "/" ) . $this->getSubDir(),
226
  ABSPATH,
227
+ str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ) . str_replace( '/', '\/', $this->getSubDir() ), // // Used by revslider and several visual editors
228
+ $this->getImagePathLive()
229
  );
230
 
231
 
232
  $args['replace_with'] = array(
233
+ rtrim( $this->multisiteDomainWithoutScheme, "/" ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName,
234
  rtrim( ABSPATH, '/' ) . '/' . $this->options->cloneDirectoryName,
235
+ str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, "/" ) ) . str_replace( '/', '\/', $this->getSubDir() ) . '\/' . $this->options->cloneDirectoryName, // Used by revslider and several visual editors
236
+ $this->getImagePathStaging()
237
  );
238
  } else {
239
  $args['search_for'] = array(
240
+ rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ),
241
  ABSPATH,
242
+ str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ),
243
+ $this->getImagePathLive()
244
  );
245
  $args['replace_with'] = array(
246
+ rtrim( $this->multisiteDomainWithoutScheme, '/' ) . '/' . $this->options->cloneDirectoryName,
247
  rtrim( ABSPATH, '/' ) . '/' . $this->options->cloneDirectoryName,
248
+ str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, '/' ) ) . '\/' . $this->options->cloneDirectoryName,
249
+ $this->getImagePathStaging()
250
  );
251
  }
252
 
253
+ //$this->log( 'Search: ' . $this->multisiteHomeUrlWithoutScheme . ' Replace: ' . rtrim( $this->multisiteDomainWithoutScheme, '/' ) . '/' . $this->options->cloneDirectoryName );
254
+
255
+
256
  $args['replace_guids'] = 'off';
257
  $args['dry_run'] = 'off';
258
  $args['case_insensitive'] = false;
260
  $args['replace_mails'] = 'off';
261
 
262
  // Allow filtering of search & replace parameters
263
+ $args = apply_filters( 'wpstg_clone_searchreplace_params', $args );
264
+
265
  // Get a list of columns in this table.
266
  list( $primary_key, $columns ) = $this->get_columns( $table );
267
 
280
  // Grab the content of the table.
281
  $data = $this->db->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
282
 
283
+ // Filter certain rows option_name in wpstg_options
284
  $filter = array(
285
  'Admin_custome_login_Slidshow',
286
  'Admin_custome_login_Social',
290
  'Admin_custome_login_top',
291
  'Admin_custome_login_dashboard',
292
  'Admin_custome_login_Version',
293
+ 'upload_path',
294
+ );
295
+
296
  apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
297
 
298
  // Loop through the data.
299
  foreach ( $data as $row ) {
300
+ $current_row++;
301
  $update_sql = array();
302
  $where_sql = array();
303
  $upd = false;
306
  if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
307
  continue;
308
  }
309
+
310
  // Skip rows with transients (They can store huge data and we need to save memory)
311
  if( isset( $row['option_name'] ) && strpos( $row['option_name'], '_transient' ) === 0 ) {
312
  continue;
313
  }
314
+
315
 
316
  foreach ( $columns as $column ) {
317
 
329
 
330
 
331
  // Skip mail addresses
332
+ if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' . $this->multisiteDomainWithoutScheme ) ) {
333
  continue;
334
  }
335
 
358
  // 1. local.wordpress.test -> local.wordpress.test/staging
359
  // 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
360
  $tmp = $args;
361
+ if( false === strpos( $dataRow, $tmp['search_for'][0] ) ) {
362
+ array_shift( $tmp['search_for'] ); // rtrim( $this->homeUrl, '/' ),
363
+ array_shift( $tmp['replace_with'] ); // rtrim( $this->homeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
364
  } else {
365
+ unset( $tmp['search_for'][1] );
366
+ unset( $tmp['replace_with'][1] );
367
  // recount array
368
+ $tmp['search_for'] = array_values( $tmp['search_for'] );
369
+ $tmp['replace_with'] = array_values( $tmp['replace_with'] );
370
  }
371
 
372
  // Run a search replace on the data row and respect the serialisation.
373
  $i = 0;
374
  foreach ( $tmp['search_for'] as $replace ) {
375
+ //$this->log( "Search for: {$tmp['search_for'][$i]} Replace with {$tmp['replace_with'][$i]}", \WPStaging\Utils\Logger::TYPE_ERROR );
376
  $dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
377
  $i++;
378
  }
396
  $result = $this->db->query( $sql );
397
 
398
  if( !$result ) {
399
+ $this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
400
  }
401
  }
402
  } // end row loop
411
  return true;
412
  }
413
 
414
+ /**
415
+ * Get path to multisite image folder e.g. wp-content/blogs.dir/ID/files or wp-content/uploads/sites/ID
416
+ * @return string
417
+ */
418
+ private function getImagePathLive() {
419
+ // Check first which structure is used
420
+ $uploads = wp_upload_dir();
421
+ $basedir = $uploads['basedir'];
422
+ $blogId = get_current_blog_id();
423
+
424
+ if( false === strpos( $basedir, 'blogs.dir' ) ) {
425
+ // Since WP 3.5
426
+ $path = $blogId > 1 ?
427
+ 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR :
428
+ 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
429
+ } else {
430
+ // old blog structure
431
+ $path = $blogId > 1 ?
432
+ 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR :
433
+ 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
434
+ }
435
+ return $path;
436
+ }
437
+
438
+ /**
439
+ * Get path to staging site image path wp-content/uploads
440
+ * @return string
441
+ */
442
+ private function getImagePathStaging() {
443
+ return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
444
+ }
445
+
446
  /**
447
  * Adapted from interconnect/it's search/replace script.
448
  *
479
  foreach ( $props as $key => $value ) {
480
  if( $key === '' || ord( $key[0] ) === 0 ) {
481
  continue;
482
+ }
483
  $tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
484
  }
485
 
488
  } else {
489
  if( is_string( $data ) ) {
490
  if( !empty( $from ) && !empty( $to ) ) {
491
+ $data = $this->str_replace( $from, $to, $data, $case_insensitive );
492
+ }
493
  }
494
  }
 
495
 
496
  if( $serialized ) {
497
  return serialize( $data );
503
  return $data;
504
  }
505
 
506
+ // private function recursive_unserialize_replace_( $from = '', $to = '', $data = '', $serialised = false, $case_insensitive = false ) {
507
+ // try {
508
+ //
509
+ // // Check first if its an object and repair it if necessary
510
+ // //$data = $this->fixObject($data);
511
+ //
512
+ // if( is_string( $data ) && !is_serialized_string( $data ) && ( $unserialized = $this->unserialize( $data ) ) !== false ) {
513
+ // $data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
514
+ // } elseif( is_array( $data ) ) {
515
+ // $_tmp = array();
516
+ // foreach ( $data as $key => $value ) {
517
+ // $_tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
518
+ // }
519
+ //
520
+ // $data = $_tmp;
521
+ // unset( $_tmp );
522
+ // }
523
+ //
524
+ // // Submitted by Tina Matter
525
+ // elseif( $this->isValidObject( $data ) ) {
526
+ // $_tmp = $data; // new $data_class( );
527
+ // $props = get_object_vars( $data );
528
+ // foreach ( $props as $key => $value ) {
529
+ // if( $key === '' || ord( $key[0] ) === 0 ) {
530
+ // continue;
531
+ // }
532
+ // $_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
533
+ // }
534
+ //
535
+ // $data = $_tmp;
536
+ // unset( $_tmp );
537
+ // } elseif( is_serialized_string( $data ) ) {
538
+ // if( false !== ($data = $this->unserialize( $data )) ) {
539
+ // $data = $this->str_replace( $from, $to, $data, $case_insensitive );
540
+ // $data = serialize( $data );
541
+ // }
542
+ // } else {
543
+ // if( is_string( $data ) ) {
544
+ // $data = $this->str_replace( $from, $to, $data, $case_insensitive );
545
+ // }
546
+ // }
547
+ //
548
+ // if( $serialised ) {
549
+ // return serialize( $data );
550
+ // }
551
+ // } catch ( Exception $error ) {
552
+ //
553
+ // }
554
+ //
555
+ // return $data;
556
+ // }
557
+
558
+
559
+
560
  /**
561
  * Check if the object is a valid one and not __PHP_Incomplete_Class_Name
562
  * Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
583
  // // Assume it must be an valid object
584
  // return true;
585
  // }
586
+
587
  /**
588
  * Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
589
  * @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
641
  foreach ( $excludes as $exclude ) {
642
  $regexExclude .= $exclude . '(*SKIP)(FAIL)|';
643
  }
644
+
645
  if( 'on' === $case_insensitive ) {
646
  //$data = str_ireplace( $from, $to, $data );
647
+ $data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#i', $to, $data );
648
  } else {
649
  //$data = str_replace( $from, $to, $data );
650
+ $data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#', $to, $data );
651
  }
652
 
653
  return $data;
742
  * @return boolean
743
  */
744
  private function isSubDir() {
745
+ // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
746
+ // This is happening much more often than you would expect
747
+ $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
748
+ $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
749
+
750
+ if( $home !== $siteurl ) {
751
  return true;
752
  }
753
  return false;
apps/Backend/Modules/Jobs/Scan.php CHANGED
@@ -137,20 +137,23 @@ class Scan extends Job {
137
  $data = reset( $directory );
138
  unset( $directory[key( $directory )] );
139
 
 
140
  $isChecked = (
141
  empty( $this->options->includedDirectories ) ||
142
  in_array( $data["path"], $this->options->includedDirectories )
143
  );
144
 
145
- //$isDisabled = ($this->options->existingClones && isset($this->options->existingClones[$name]));
146
  // Include wp core folders and their sub dirs.
147
  // Exclude all other folders (default setting)
 
 
148
  $isDisabled = ($name !== 'wp-admin' &&
149
  $name !== 'wp-includes' &&
150
  $name !== 'wp-content') &&
151
- false === strpos( strrev( $data["path"] ), strrev( "wp-admin" ) ) &&
152
- false === strpos( strrev( $data["path"] ), strrev( "wp-includes" ) ) &&
153
- false === strpos( strrev( $data["path"] ), strrev( "wp-content" ) ) ? true : false;
154
 
155
  // Extra class to differentiate between wp core and non core folders
156
  $class = !$isDisabled ? 'wpstg-root' : 'wpstg-extra';
@@ -163,15 +166,15 @@ class Scan extends Job {
163
  $output .= " checked";
164
  //if ($forceDisabled || $isDisabled) $output .= " disabled";
165
 
166
- $output .= " name='selectedDirectories[]' value='{$data["path"]}'>";
167
 
168
  $output .= "<a href='#' class='wpstg-expand-dirs ";
169
- if( !$isChecked || $isDisabled )
170
  $output .= " disabled";
 
171
  $output .= "'>{$name}";
172
  $output .= "</a>";
173
-
174
- $output .= "<span class='wpstg-size-info'>{$this->formatSize( $data["size"] )}</span>";
175
 
176
  if( !empty( $directory ) ) {
177
  $output .= "<div class='wpstg-dir wpstg-subdir'>";
@@ -294,7 +297,7 @@ class Scan extends Job {
294
  */
295
  protected function getSubDirectories( $path ) {
296
 
297
- if (!is_readable($path)){
298
  return false;
299
  }
300
 
@@ -325,7 +328,6 @@ class Scan extends Job {
325
 
326
  //echo $directory->getRealPath() . '<br>';
327
  //echo 'abspath: ' . \WPStaging\WPStaging::getWPpath() . '<br>';
328
-
329
  //if( strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
330
  if( strpos( $directory->getRealPath(), \WPStaging\WPStaging::getWPpath() ) !== 0 ) {
331
  return false;
137
  $data = reset( $directory );
138
  unset( $directory[key( $directory )] );
139
 
140
+
141
  $isChecked = (
142
  empty( $this->options->includedDirectories ) ||
143
  in_array( $data["path"], $this->options->includedDirectories )
144
  );
145
 
146
+
147
  // Include wp core folders and their sub dirs.
148
  // Exclude all other folders (default setting)
149
+ $dataPath = isset( $data["path"] ) ? $data["path"] : '';
150
+ $dataSize = isset( $data["size"] ) ? $data["size"] : '';
151
  $isDisabled = ($name !== 'wp-admin' &&
152
  $name !== 'wp-includes' &&
153
  $name !== 'wp-content') &&
154
+ false === strpos( strrev( $dataPath ), strrev( "wp-admin" ) ) &&
155
+ false === strpos( strrev( $dataPath ), strrev( "wp-includes" ) ) &&
156
+ false === strpos( strrev( $dataPath ), strrev( "wp-content" ) ) ? true : false;
157
 
158
  // Extra class to differentiate between wp core and non core folders
159
  $class = !$isDisabled ? 'wpstg-root' : 'wpstg-extra';
166
  $output .= " checked";
167
  //if ($forceDisabled || $isDisabled) $output .= " disabled";
168
 
169
+ $output .= " name='selectedDirectories[]' value='{$dataPath}'>";
170
 
171
  $output .= "<a href='#' class='wpstg-expand-dirs ";
172
+ if( !$isChecked || $isDisabled ) {
173
  $output .= " disabled";
174
+ }
175
  $output .= "'>{$name}";
176
  $output .= "</a>";
177
+ $output .= "<span class='wpstg-size-info'>{$this->formatSize( $dataSize )}</span>";
 
178
 
179
  if( !empty( $directory ) ) {
180
  $output .= "<div class='wpstg-dir wpstg-subdir'>";
297
  */
298
  protected function getSubDirectories( $path ) {
299
 
300
+ if( !is_readable( $path ) ) {
301
  return false;
302
  }
303
 
328
 
329
  //echo $directory->getRealPath() . '<br>';
330
  //echo 'abspath: ' . \WPStaging\WPStaging::getWPpath() . '<br>';
 
331
  //if( strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
332
  if( strpos( $directory->getRealPath(), \WPStaging\WPStaging::getWPpath() ) !== 0 ) {
333
  return false;
apps/Backend/Modules/Jobs/SearchReplace.php CHANGED
@@ -47,7 +47,6 @@ class SearchReplace extends JobExecutable {
47
  $this->db = WPStaging::getInstance()->get( "wpdb" );
48
  $this->tmpPrefix = $this->options->prefix;
49
  $helper = new Helper();
50
- //$this->homeUrl = $helper->get_home_url();
51
  $this->homeUrl = $helper->get_home_url_without_scheme();
52
  }
53
 
@@ -293,7 +292,7 @@ class SearchReplace extends JobExecutable {
293
  'Admin_custome_login_top',
294
  'Admin_custome_login_dashboard',
295
  'Admin_custome_login_Version',
296
- 'upload_path'
297
  );
298
 
299
  $filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
@@ -398,7 +397,7 @@ class SearchReplace extends JobExecutable {
398
  $result = $this->db->query( $sql );
399
 
400
  if( !$result ) {
401
- $this->log( "Error updating row {$current_row}", \WPStaging\Utils\Logger::TYPE_ERROR );
402
  }
403
  }
404
  } // end row loop
@@ -658,7 +657,12 @@ class SearchReplace extends JobExecutable {
658
  * @return boolean
659
  */
660
  private function isSubDir() {
661
- if( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
 
 
 
 
 
662
  return true;
663
  }
664
  return false;
47
  $this->db = WPStaging::getInstance()->get( "wpdb" );
48
  $this->tmpPrefix = $this->options->prefix;
49
  $helper = new Helper();
 
50
  $this->homeUrl = $helper->get_home_url_without_scheme();
51
  }
52
 
292
  'Admin_custome_login_top',
293
  'Admin_custome_login_dashboard',
294
  'Admin_custome_login_Version',
295
+ 'upload_path',
296
  );
297
 
298
  $filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
397
  $result = $this->db->query( $sql );
398
 
399
  if( !$result ) {
400
+ $this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
401
  }
402
  }
403
  } // end row loop
657
  * @return boolean
658
  */
659
  private function isSubDir() {
660
+ // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
661
+ // This is happening much more often than you would expect
662
+ $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
663
+ $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
664
+
665
+ if( $home !== $siteurl ) {
666
  return true;
667
  }
668
  return false;
apps/Backend/Modules/Jobs/Updating.php CHANGED
@@ -1,248 +1,255 @@
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
- // Define mainJob to differentiate between cloning, updating and pushing
42
- $this->options->mainJob = 'updating';
43
-
44
- // Job
45
- $this->options->job = new \stdClass();
46
-
47
- // Check if clone data already exists and use that one
48
- if (isset($this->options->existingClones[$this->options->clone]) )
49
- {
50
- $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]['number'];
51
- $this->options->prefix = $this->getStagingPrefix();
52
- } else {
53
- wp_die('Fatal Error: Can not update clone because there is no clone data.');
54
- }
55
-
56
-
57
- // Excluded Tables
58
  // if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
59
  // {
60
  // $this->options->excludedTables = $_POST["excludedTables"];
61
  // }
62
- // Included Tables
63
- if (isset($_POST["includedTables"]) && is_array($_POST["includedTables"]))
64
- {
65
- $this->options->tables = $_POST["includedTables"];
66
- } else {
67
- $this->options->tables = array();
68
- }
69
-
70
- // Excluded Directories
71
- if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"]))
72
- {
73
- $this->options->excludedDirectories = $_POST["excludedDirectories"];
74
- }
75
-
76
- // Excluded Directories TOTAL
77
- // Do not copy these folders and plugins
78
- $excludedDirectories = array(
79
- ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
80
- ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login'
81
- );
82
-
83
- $this->options->excludedDirectories = array_merge($excludedDirectories, $this->options->excludedDirectories);
84
-
85
- // Included Directories
86
- if (isset($_POST["includedDirectories"]) && is_array($_POST["includedDirectories"]))
87
- {
88
- $this->options->includedDirectories = $_POST["includedDirectories"];
89
- }
90
-
91
- // Extra Directories
92
- if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"]) )
93
- {
94
- $this->options->extraDirectories = $_POST["extraDirectories"];
95
- }
96
-
97
- // Directories to Copy
98
- $this->options->directoriesToCopy = array_merge(
99
- $this->options->includedDirectories,
100
- $this->options->extraDirectories
101
- );
102
-
103
- array_unshift($this->options->directoriesToCopy, ABSPATH);
104
-
105
- // Delete files to copy listing
106
- $this->cache->delete("files_to_copy");
107
-
108
- return $this->saveOptions();
109
- }
110
-
111
-
112
- /**
113
- * Check and return prefix of the staging site
114
- */
115
- public function getStagingPrefix() {
116
- // prefix not defined! Happens if staging site has ben generated with older version of wpstg
117
- // Try to get staging prefix from wp-config.php of staging site
118
- $this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
119
- if (empty($this->options->prefix)) {
120
- // Throw error if wp-config.php is not readable
121
- $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
122
- if (false === ($content = @file_get_contents($path))) {
123
- $this->log("Can not open {$path}. Can't read contents", Logger::TYPE_ERROR);
124
- $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");
125
- 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");
126
  } else {
127
- // Get prefix from wp-config.php
128
- preg_match("/table_prefix\s*=\s*'(\w*)';/", $content, $matches);
129
-
130
- if (!empty($matches[1])) {
131
- $this->options->prefix = $matches[1];
132
- } else {
133
- $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");
134
- 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");
135
- }
136
  }
137
- }
138
-
139
- // Die() if staging prefix is the same as the live prefix
140
- if ($this->db->prefix == $this->options->prefix) {
141
- $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");
142
- 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");
143
- }
144
-
145
- // Else
146
- return $this->options->prefix;
147
- }
148
-
149
- /**
150
- * Start the cloning job
151
- */
152
- public function start()
153
- {
154
- if (null === $this->options->currentJob)
155
- {
156
- $this->log("Cloning job for {$this->options->clone} finished");
157
- return true;
158
- }
159
-
160
- $methodName = "job" . ucwords($this->options->currentJob);
161
-
162
- if (!method_exists($this, $methodName))
163
- {
164
- $this->log("Can't execute job; Job's method {$methodName} is not found");
165
- throw new JobNotFoundException($methodName);
166
- }
167
-
168
- // Call the job
169
- //$this->log("execute job: Job's method {$methodName}");
170
- return $this->{$methodName}();
171
- }
172
-
173
- /**
174
- * @param object $response
175
- * @param string $nextJob
176
- * @return object
177
- */
178
- private function handleJobResponse($response, $nextJob)
179
- {
180
- // Job is not done
181
- if (true !== $response->status)
182
- {
183
- return $response;
184
- }
185
-
186
- $this->options->currentJob = $nextJob;
187
- $this->options->currentStep = 0;
188
- $this->options->totalSteps = 0;
189
-
190
- // Save options
191
- $this->saveOptions();
192
-
193
- return $response;
194
- }
195
-
196
-
197
-
198
-
199
- /**
200
- * Clone Database
201
- * @return object
202
- */
203
- public function jobDatabase()
204
- {
205
- $database = new Database();
206
- return $this->handleJobResponse($database->start(), "directories");
207
- }
208
-
209
- /**
210
- * Get All Files From Selected Directories Recursively Into a File
211
- * @return object
212
- */
213
- public function jobDirectories()
214
- {
215
- $directories = new Directories();
216
- return $this->handleJobResponse($directories->start(), "files");
217
- }
218
-
219
- /**
220
- * Copy Files
221
- * @return object
222
- */
223
- public function jobFiles()
224
- {
225
- $files = new Files();
226
- return $this->handleJobResponse($files->start(), "data");
227
- }
228
-
229
- /**
230
- * Replace Data
231
- * @return object
232
- */
233
- public function jobData()
234
- {
235
- $data = new Data();
236
- return $this->handleJobResponse($data->start(), "finish");
237
- }
238
-
239
- /**
240
- * Save Clone Data
241
- * @return object
242
- */
243
- public function jobFinish()
244
- {
245
- $finish = new Finish();
246
- return $this->handleJobResponse($finish->start(), '');
247
- }
248
- }
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+
3
  namespace WPStaging\Backend\Modules\Jobs;
4
 
5
  use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
6
  use WPStaging\WPStaging;
7
+ use WPStaging\Backend\Modules\Jobs\Multisite\Database as muDatabase;
8
+ use WPStaging\Backend\Modules\Jobs\Multisite\SearchReplace as muSearchReplace;
9
+ use WPStaging\Backend\Modules\Jobs\Multisite\Data as muData;
10
+ use WPStaging\Backend\Modules\Jobs\Multisite\Finish as muFinish;
11
+ use WPStaging\Backend\Modules\Jobs\Multisite\Directories as muDirectories;
12
+ use WPStaging\Backend\Modules\Jobs\Multisite\Files as muFiles;
13
 
14
  /**
15
  * Class Cloning
16
  * @package WPStaging\Backend\Modules\Jobs
17
  */
18
+ class Updating extends Job {
19
+
20
+ /**
21
+ * Initialize is called in \Job
22
+ */
23
+ public function initialize() {
24
+ $this->db = WPStaging::getInstance()->get( "wpdb" );
25
+ }
26
+
27
+ /**
28
+ * Save Chosen Cloning Settings
29
+ * @return bool
30
+ */
31
+ public function save() {
32
+ if( !isset( $_POST ) || !isset( $_POST["cloneID"] ) ) {
33
+ return false;
34
+ }
35
+
36
+ // Generate Options
37
+ // Clone
38
+ $this->options->clone = $_POST["cloneID"];
39
+ $this->options->cloneDirectoryName = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
40
+ $this->options->cloneNumber = 1;
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
+ // Define mainJob to differentiate between cloning, updating and pushing
47
+ $this->options->mainJob = 'updating';
48
+
49
+ // Job
50
+ $this->options->job = new \stdClass();
51
+
52
+ // Check if clone data already exists and use that one
53
+ if( isset( $this->options->existingClones[$this->options->clone] ) ) {
54
+ $this->options->cloneNumber = $this->options->existingClones[$this->options->clone]['number'];
55
+ $this->options->prefix = $this->getStagingPrefix();
56
+ } else {
57
+ wp_die( 'Fatal Error: Can not update clone because there is no clone data.' );
58
+ }
59
+
60
+
61
+ // Excluded Tables
 
 
 
62
  // if (isset($_POST["excludedTables"]) && is_array($_POST["excludedTables"]))
63
  // {
64
  // $this->options->excludedTables = $_POST["excludedTables"];
65
  // }
66
+ // Included Tables
67
+ if( isset( $_POST["includedTables"] ) && is_array( $_POST["includedTables"] ) ) {
68
+ $this->options->tables = $_POST["includedTables"];
69
+ } else {
70
+ $this->options->tables = array();
71
+ }
72
+
73
+ // Excluded Directories
74
+ if( isset( $_POST["excludedDirectories"] ) && is_array( $_POST["excludedDirectories"] ) ) {
75
+ $this->options->excludedDirectories = $_POST["excludedDirectories"];
76
+ }
77
+
78
+ // Excluded Directories TOTAL
79
+ // Do not copy these folders and plugins
80
+ $excludedDirectories = array(
81
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
82
+ ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login'
83
+ );
84
+
85
+ $this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
86
+
87
+ // Included Directories
88
+ if( isset( $_POST["includedDirectories"] ) && is_array( $_POST["includedDirectories"] ) ) {
89
+ $this->options->includedDirectories = $_POST["includedDirectories"];
90
+ }
91
+
92
+ // Extra Directories
93
+ if( isset( $_POST["extraDirectories"] ) && !empty( $_POST["extraDirectories"] ) ) {
94
+ $this->options->extraDirectories = $_POST["extraDirectories"];
95
+ }
96
+
97
+ // Directories to Copy
98
+ $this->options->directoriesToCopy = array_merge(
99
+ $this->options->includedDirectories, $this->options->extraDirectories
100
+ );
101
+
102
+ array_unshift( $this->options->directoriesToCopy, ABSPATH );
103
+
104
+ // Delete files to copy listing
105
+ $this->cache->delete( "files_to_copy" );
106
+
107
+ return $this->saveOptions();
108
+ }
109
+
110
+ /**
111
+ * Check and return prefix of the staging site
112
+ */
113
+ public function getStagingPrefix() {
114
+ // prefix not defined! Happens if staging site has ben generated with older version of wpstg
115
+ // Try to get staging prefix from wp-config.php of staging site
116
+ $this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
117
+ if( empty( $this->options->prefix ) ) {
118
+ // Throw error if wp-config.php is not readable
119
+ $path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
120
+ if( false === ($content = @file_get_contents( $path )) ) {
121
+ $this->log( "Can not open {$path}. Can't read contents", Logger::TYPE_ERROR );
122
+ $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" );
123
+ 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" );
124
+ } else {
125
+ // Get prefix from wp-config.php
126
+ preg_match( "/table_prefix\s*=\s*'(\w*)';/", $content, $matches );
127
+
128
+ if( !empty( $matches[1] ) ) {
129
+ $this->options->prefix = $matches[1];
130
  } else {
131
+ $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" );
132
+ 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" );
 
 
 
 
 
 
 
133
  }
134
+ }
135
+ }
136
+
137
+ // Die() if staging prefix is the same as the live prefix
138
+ if( $this->db->prefix == $this->options->prefix ) {
139
+ $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" );
140
+ 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" );
141
+ }
142
+
143
+ // Else
144
+ return $this->options->prefix;
145
+ }
146
+
147
+ /**
148
+ * Start the cloning job
149
+ */
150
+ public function start() {
151
+ if( null === $this->options->currentJob ) {
152
+ $this->log( "Cloning job for {$this->options->clone} finished" );
153
+ return true;
154
+ }
155
+
156
+ $methodName = "job" . ucwords( $this->options->currentJob );
157
+
158
+ if( !method_exists( $this, $methodName ) ) {
159
+ $this->log( "Can't execute job; Job's method {$methodName} is not found" );
160
+ throw new JobNotFoundException( $methodName );
161
+ }
162
+
163
+ // Call the job
164
+ //$this->log("execute job: Job's method {$methodName}");
165
+ return $this->{$methodName}();
166
+ }
167
+
168
+ /**
169
+ * @param object $response
170
+ * @param string $nextJob
171
+ * @return object
172
+ */
173
+ private function handleJobResponse( $response, $nextJob ) {
174
+ // Job is not done
175
+ if( true !== $response->status ) {
176
+ return $response;
177
+ }
178
+
179
+ $this->options->currentJob = $nextJob;
180
+ $this->options->currentStep = 0;
181
+ $this->options->totalSteps = 0;
182
+
183
+ // Save options
184
+ $this->saveOptions();
185
+
186
+ return $response;
187
+ }
188
+
189
+ /**
190
+ * Clone Database
191
+ * @return object
192
+ */
193
+ public function jobDatabase() {
194
+ if( is_multisite() ) {
195
+ $database = new muDatabase();
196
+ } else {
197
+ $database = new Database();
198
+ }
199
+ return $this->handleJobResponse( $database->start(), "directories" );
200
+ }
201
+
202
+ /**
203
+ * Get All Files From Selected Directories Recursively Into a File
204
+ * @return object
205
+ */
206
+ public function jobDirectories() {
207
+ if( is_multisite() ) {
208
+ $directories = new muDirectories();
209
+ } else {
210
+ $directories = new Directories();
211
+ }
212
+ return $this->handleJobResponse( $directories->start(), "files" );
213
+ }
214
+
215
+ /**
216
+ * Copy Files
217
+ * @return object
218
+ */
219
+ public function jobFiles() {
220
+ if( is_multisite() ) {
221
+ $files = new muFiles();
222
+ } else {
223
+ $files = new Files();
224
+ }
225
+ return $this->handleJobResponse( $files->start(), "data" );
226
+ }
227
+
228
+ /**
229
+ * Replace Data
230
+ * @return object
231
+ */
232
+ public function jobData() {
233
+ if( is_multisite() ) {
234
+ $data = new muData();
235
+ } else {
236
+ $data = new Data();
237
+ }
238
+ return $this->handleJobResponse( $data->start(), "finish" );
239
+ }
240
+
241
+ /**
242
+ * Save Clone Data
243
+ * @return object
244
+ */
245
+ public function jobFinish() {
246
+ if( is_multisite() ) {
247
+ $finish = new muFinish();
248
+ } else {
249
+ $finish = new Finish();
250
+ }
251
+ $finish = new Finish();
252
+ return $this->handleJobResponse( $finish->start(), '' );
253
+ }
254
+
255
+ }
apps/Backend/Modules/SystemInfo.php CHANGED
@@ -139,8 +139,9 @@ class SystemInfo extends InjectionAware {
139
 
140
  $output = $this->info( "Multisite:", ($this->isMultiSite ? "Yes" : "No" ) );
141
  $output .= $this->info( "Multisite Blog ID:", get_current_blog_id() );
142
- $output .= $this->info( "MultiSite URL scheme:", $multisite->getHomeURL() );
143
  $output .= $this->info( "MultiSite URL without scheme:", $multisite->getHomeUrlWithoutScheme() );
 
144
 
145
  return apply_filters( "wpstg_sysinfo_after_multisite_info", $output );
146
 
@@ -159,7 +160,7 @@ class SystemInfo extends InjectionAware {
159
  // Clones data < 1.1.6.x
160
  $clones = ( object ) get_option( 'wpstg_existing_clones', array() );
161
  // Clones data version > 2.x
162
- $clonesBeta = get_option( 'wpstg_existing_clones_beta' );
163
 
164
 
165
  $output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
@@ -172,7 +173,6 @@ class SystemInfo extends InjectionAware {
172
 
173
  $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
174
 
175
- $i = 1;
176
  foreach ( $clones as $key => $value ) {
177
  $output .= $this->info( "Site name & subfolder :", $value );
178
  }
@@ -508,7 +508,12 @@ class SystemInfo extends InjectionAware {
508
  * @return boolean
509
  */
510
  private function isSubDir() {
511
- if( get_option( 'siteurl' ) !== get_option( 'home' ) ) {
 
 
 
 
 
512
  return true;
513
  }
514
  return false;
139
 
140
  $output = $this->info( "Multisite:", ($this->isMultiSite ? "Yes" : "No" ) );
141
  $output .= $this->info( "Multisite Blog ID:", get_current_blog_id() );
142
+ $output .= $this->info( "MultiSite URL:", $multisite->getHomeURL() );
143
  $output .= $this->info( "MultiSite URL without scheme:", $multisite->getHomeUrlWithoutScheme() );
144
+ $output .= $this->info( "MultiSite is Main Site:", is_main_site() ? 'Yes' : 'No' );
145
 
146
  return apply_filters( "wpstg_sysinfo_after_multisite_info", $output );
147
 
160
  // Clones data < 1.1.6.x
161
  $clones = ( object ) get_option( 'wpstg_existing_clones', array() );
162
  // Clones data version > 2.x
163
+ $clonesBeta = get_option( 'wpstg_existing_clones_beta', array() );
164
 
165
 
166
  $output = "-- WP Staging Settings" . PHP_EOL . PHP_EOL;
173
 
174
  $output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
175
 
 
176
  foreach ( $clones as $key => $value ) {
177
  $output .= $this->info( "Site name & subfolder :", $value );
178
  }
508
  * @return boolean
509
  */
510
  private function isSubDir() {
511
+ // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
512
+ // This is happening much more often than you would expect
513
+ $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
514
+ $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
515
+
516
+ if( $home !== $siteurl ) {
517
  return true;
518
  }
519
  return false;
apps/Backend/Notices/Notices.php CHANGED
@@ -77,14 +77,10 @@ class Notices {
77
 
78
  public function messages() {
79
 
80
- $this->plugin_deactivated_notice();
81
 
82
- // Do not display notices to user_roles lower than 'update_plugins'
83
- if( !current_user_can( 'update_plugins' ) ) {
84
- return;
85
- }
86
 
87
- $viewsNoticesPath = "{$this->path}views/_includes/messages/";
88
 
89
  // Show rating review message on all admin pages
90
  if( $this->canShow( "wpstg_rating", 7 ) ) {
@@ -92,26 +88,18 @@ class Notices {
92
  }
93
 
94
 
95
- // Display messages below on wp quads admin page only
96
- if( !$this->isAdminPage() ) {
97
  return;
98
  }
99
 
100
 
101
  $varsDirectory = \WPStaging\WPStaging::getContentDir();
102
-
103
-
104
- // Poll do not show any longer
105
- /* if( $this->canShow( "wpstg_poll", 7 ) ) {
106
- require_once "{$viewsNoticesPath}poll.php";
107
- } */
108
-
109
- // Cache directory in uploads is not writable
110
  if( !wp_is_writable( $varsDirectory ) ) {
111
  require_once "{$viewsNoticesPath}/uploads-cache-directory-permission-problem.php";
112
  }
113
  // Staging directory is not writable
114
- if( !wp_is_writable( get_home_path() ) ) {
115
  require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
116
  }
117
 
@@ -130,6 +118,30 @@ class Notices {
130
  require_once "{$viewsNoticesPath}transient.php";
131
  delete_transient( "wp_staging_deactivated_notice_id" );
132
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
  }
134
 
135
  /**
77
 
78
  public function messages() {
79
 
80
+ $viewsNoticesPath = "{$this->path}views/_includes/messages/";
81
 
82
+ $this->plugin_deactivated_notice();
 
 
 
83
 
 
84
 
85
  // Show rating review message on all admin pages
86
  if( $this->canShow( "wpstg_rating", 7 ) ) {
88
  }
89
 
90
 
91
+ // Display messages below to admins only, only on admin panel
92
+ if( !current_user_can( "update_plugins" ) || !$this->isAdminPage() ) {
93
  return;
94
  }
95
 
96
 
97
  $varsDirectory = \WPStaging\WPStaging::getContentDir();
 
 
 
 
 
 
 
 
98
  if( !wp_is_writable( $varsDirectory ) ) {
99
  require_once "{$viewsNoticesPath}/uploads-cache-directory-permission-problem.php";
100
  }
101
  // Staging directory is not writable
102
+ if( !wp_is_writable( ABSPATH ) ) {
103
  require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
104
  }
105
 
118
  require_once "{$viewsNoticesPath}transient.php";
119
  delete_transient( "wp_staging_deactivated_notice_id" );
120
  }
121
+ // Rating
122
+ if( $this->canShow( "wpstg_rating", 7 ) ) {
123
+ require_once "{$viewsNoticesPath}rating.php";
124
+ }
125
+
126
+ // Different scheme in home and siteurl
127
+ if ($this->isDifferentScheme()){
128
+ require_once "{$viewsNoticesPath}wrong-scheme.php";
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Check if the url scheme of siteurl and home is identical
134
+ * @return boolean
135
+ */
136
+ private function isDifferentScheme(){
137
+ $siteurlScheme = parse_url(get_option('siteurl'), PHP_URL_SCHEME);
138
+ $homeScheme = parse_url(get_option('home'), PHP_URL_SCHEME);
139
+
140
+ if ($siteurlScheme === $homeScheme){
141
+ return false;
142
+ }
143
+ return true;
144
+
145
  }
146
 
147
  /**
apps/Backend/public/css/wpstg-admin.css CHANGED
@@ -936,4 +936,18 @@ color:#777777;
936
  .wpstg-message p {
937
  margin: 3px 0;
938
  font-size: 13px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
939
  }
936
  .wpstg-message p {
937
  margin: 3px 0;
938
  font-size: 13px;
939
+ }
940
+
941
+
942
+ .wpstg-error {
943
+ display:block;
944
+ padding: 10px;
945
+ background-color: #f5e0de;
946
+ color:#b65147;
947
+ margin: 10px;
948
+ margin-left:0px;
949
+ }
950
+
951
+ #wpstg-resume-cloning {
952
+ display:none;
953
  }
apps/Backend/public/js/wpstg-admin.js CHANGED
@@ -49,11 +49,11 @@ var WPStaging = (function ($)
49
  {
50
  cache.get("#wpstg-try-again").css("display", "inline-block");
51
  cache.get("#wpstg-cancel-cloning").text("Reset");
52
- cache.get("#wpstg-cloning-result").text("Fail");
 
 
53
  cache.get("#wpstg-error-wrapper").show();
54
- cache.get("#wpstg-error-details")
55
- .show()
56
- .html(message);
57
  cache.get("#wpstg-removing-clone").removeClass("loading");
58
  cache.get("#wpstg-loader").hide();
59
  };
@@ -240,8 +240,6 @@ var WPStaging = (function ($)
240
  that.isCancelled = true;
241
  that.progressBar = 0;
242
 
243
-
244
- //$("#wpstg-cloning-result").text("Please wait...this can take up a while.");
245
  $("#wpstg-processing-status").text("Please wait...this can take up a while.");
246
  $("#wpstg-loader, #wpstg-show-log-button").hide();
247
 
@@ -249,12 +247,30 @@ var WPStaging = (function ($)
249
 
250
  cancelCloning();
251
  })
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
252
  // Cancel update cloning
253
  .on("click", "#wpstg-cancel-cloning-update", function () {
254
- if (!confirm("Are you sure you want to cancel clone updating process?"))
255
- {
256
- return false;
257
- }
258
 
259
  var $this = $(this);
260
 
@@ -337,9 +353,7 @@ var WPStaging = (function ($)
337
  if (response.length < 1)
338
  {
339
  showError(
340
- "Something went wrong! Error: No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
341
- "Than try again. If that does not help, " +
342
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
343
  );
344
  }
345
 
@@ -392,9 +406,7 @@ var WPStaging = (function ($)
392
 
393
 
394
  showError(
395
- "Fatal Unknown Error. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
396
- "Than try again. If that does not help, " +
397
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
398
  );
399
  },
400
  success: function (data) {
@@ -406,18 +418,22 @@ var WPStaging = (function ($)
406
  statusCode: {
407
  404: function (data) {
408
  showError(
409
- "Something went wrong; can't find ajax request URL! Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
410
- "Than try again. If that does not help, " +
411
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
412
  );
413
- // Try again after 10 seconds
414
  },
415
  500: function () {
416
  showError(
417
- "Something went wrong! Internal server error while processing the request! Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
418
- "Than try again. If that does not help, " +
419
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
420
  );
 
 
 
 
 
 
 
 
421
  }
422
  }
423
  });
@@ -435,8 +451,18 @@ var WPStaging = (function ($)
435
  .on("click", ".wpstg-next-step-link", function (e) {
436
  e.preventDefault();
437
 
438
- var $this = $(this),
439
- isScan = false;
 
 
 
 
 
 
 
 
 
 
440
 
441
  // Button is disabled
442
  if ($this.attr("disabled"))
@@ -480,7 +506,7 @@ var WPStaging = (function ($)
480
  {
481
  showError(
482
  "Something went wrong! No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
483
- "Then try again. If that does not help, " +
484
  "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
485
  );
486
  }
@@ -626,7 +652,7 @@ var WPStaging = (function ($)
626
  }
627
 
628
  that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
629
- // Remove this to keep &_POST[] small otherwise mod_security will throw erro 404
630
  //that.data.excludedTables = getExcludedTables();
631
  that.data.includedTables = getIncludedTables();
632
  that.data.includedDirectories = getIncludedDirectories();
@@ -655,9 +681,7 @@ var WPStaging = (function ($)
655
  if (response.length < 1)
656
  {
657
  showError(
658
- "Something went wrong! No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
659
- "Then try again. If that does not help, " +
660
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
661
  );
662
  }
663
 
@@ -722,9 +746,7 @@ var WPStaging = (function ($)
722
  // Error
723
  if ("undefined" !== typeof response.error && "undefined" !== typeof response.message) {
724
  showError(
725
- "Something went wrong! Error:" + response.message + ". Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
726
- "Than try again. If that does not help, " +
727
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
728
  );
729
  console.log(response.message);
730
  }
@@ -838,6 +860,7 @@ var WPStaging = (function ($)
838
  );
839
  };
840
 
 
841
  /**
842
  * Scroll the window log to bottom
843
  * @returns void
@@ -974,6 +997,8 @@ var WPStaging = (function ($)
974
  console.log("Starting cloning process...");
975
 
976
  cache.get("#wpstg-loader").show();
 
 
977
 
978
  // Clone Database
979
  setTimeout(function () {
@@ -1025,9 +1050,7 @@ var WPStaging = (function ($)
1025
  if (false === response)
1026
  {
1027
  showError(
1028
- "Something went wrong! Error: No response. <br/><br/> Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
1029
- "Then try again. If that does not help, " +
1030
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
1031
  );
1032
  cache.get("#wpstg-loader").hide();
1033
  cache.get(".wpstg-loader").hide();
@@ -1038,9 +1061,7 @@ var WPStaging = (function ($)
1038
  if ("undefined" !== typeof (response.error) && response.error) {
1039
  console.log(response.message);
1040
  showError(
1041
- "Something went wrong! Error:" + response.message + ". Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
1042
- "Then try again. If that does not help, " +
1043
- "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
1044
  );
1045
 
1046
  return;
@@ -1102,6 +1123,7 @@ var WPStaging = (function ($)
1102
  cache.get("#wpstg_staging_name").html(that.data.cloneID);
1103
  cache.get("#wpstg-finished-result").show();
1104
  cache.get("#wpstg-cancel-cloning").hide();
 
1105
  cache.get("#wpstg-cancel-cloning-update").prop("disabled", true);
1106
 
1107
  var $link1 = cache.get("#wpstg-clone-url-1");
49
  {
50
  cache.get("#wpstg-try-again").css("display", "inline-block");
51
  cache.get("#wpstg-cancel-cloning").text("Reset");
52
+ cache.get("#wpstg-resume-cloning").show();
53
+ //cache.get("#wpstg-cloning-result").text("Fail");
54
+ //cache.get("#wpstg-processing-status").text("Process Failed");
55
  cache.get("#wpstg-error-wrapper").show();
56
+ cache.get("#wpstg-error-details").show().html(message);
 
 
57
  cache.get("#wpstg-removing-clone").removeClass("loading");
58
  cache.get("#wpstg-loader").hide();
59
  };
240
  that.isCancelled = true;
241
  that.progressBar = 0;
242
 
 
 
243
  $("#wpstg-processing-status").text("Please wait...this can take up a while.");
244
  $("#wpstg-loader, #wpstg-show-log-button").hide();
245
 
247
 
248
  cancelCloning();
249
  })
250
+ // Resume cloning
251
+ .on("click", "#wpstg-resume-cloning", function () {
252
+
253
+ var $this = $(this);
254
+
255
+ $("#wpstg-try-again, #wpstg-home-link").hide();
256
+
257
+ that.isCancelled = false;
258
+ //that.progressBar = 0;
259
+
260
+ $("#wpstg-processing-status").text("Try to resume cloning process...");
261
+ $("#wpstg-error-details").hide();
262
+ $("#wpstg-loader").show();
263
+
264
+ $this.parent().append(ajaxSpinner);
265
+
266
+ that.startCloning();
267
+ })
268
  // Cancel update cloning
269
  .on("click", "#wpstg-cancel-cloning-update", function () {
270
+ // if (!confirm("Are you sure you want to cancel clone updating process?"))
271
+ // {
272
+ // return false;
273
+ // }
274
 
275
  var $this = $(this);
276
 
353
  if (response.length < 1)
354
  {
355
  showError(
356
+ "Something went wrong! Error: No response. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
357
  );
358
  }
359
 
406
 
407
 
408
  showError(
409
+ "Fatal Unknown Error. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
410
  );
411
  },
412
  success: function (data) {
418
  statusCode: {
419
  404: function (data) {
420
  showError(
421
+ "Something went wrong! can't find ajax request URL! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
422
  );
423
+
424
  },
425
  500: function () {
426
  showError(
427
+ "Something went wrong! Internal server error while processing the request! Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
428
  );
429
+ },
430
+ 504: function () {
431
+ showError("It looks like your server is rate limiting ajax requests. Please try to resume after a minute. If this still not works try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report.\n\ ");
432
+ var obj = new Object();
433
+ obj.status = false;
434
+ obj.error = 'custom error';
435
+ return JSON.stringify(obj);
436
+
437
  }
438
  }
439
  });
451
  .on("click", ".wpstg-next-step-link", function (e) {
452
  e.preventDefault();
453
 
454
+ var $this = $(this);
455
+ var isScan = false;
456
+
457
+ if ($this.data("action") === "wpstg_update") {
458
+ // Update Clone - confirmed
459
+ if (!confirm("Are you sure you want to update the staging site with data from the live site? \n\nMake sure to exclude all the tables and folders which you do not want to overwrite first! \n\nDo not necessarily cancel the updating process! This can break your staging site."))
460
+ {
461
+ return false;
462
+ }
463
+
464
+ }
465
+
466
 
467
  // Button is disabled
468
  if ($this.attr("disabled"))
506
  {
507
  showError(
508
  "Something went wrong! No response. Go to WP Staging > Settings and lower 'File Copy Limit' and 'DB Query Limit'. Also set 'CPU Load Priority to low.'" +
509
+ "and try again. If that does not help, " +
510
  "<a href='https://wp-staging.com/support/' target='_blank'>open a support ticket</a> "
511
  );
512
  }
652
  }
653
 
654
  that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
655
+ // Remove this to keep &_POST[] small otherwise mod_security will throw error 404
656
  //that.data.excludedTables = getExcludedTables();
657
  that.data.includedTables = getIncludedTables();
658
  that.data.includedDirectories = getIncludedDirectories();
681
  if (response.length < 1)
682
  {
683
  showError(
684
+ "Something went wrong! No response. Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
685
  );
686
  }
687
 
746
  // Error
747
  if ("undefined" !== typeof response.error && "undefined" !== typeof response.message) {
748
  showError(
749
+ "Something went wrong! Error:" + response.message + ". Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
750
  );
751
  console.log(response.message);
752
  }
860
  );
861
  };
862
 
863
+
864
  /**
865
  * Scroll the window log to bottom
866
  * @returns void
997
  console.log("Starting cloning process...");
998
 
999
  cache.get("#wpstg-loader").show();
1000
+ cache.get("#wpstg-cancel-cloning").text('Cancel');
1001
+ cache.get("#wpstg-resume-cloning").hide();
1002
 
1003
  // Clone Database
1004
  setTimeout(function () {
1050
  if (false === response)
1051
  {
1052
  showError(
1053
+ "Something went wrong! Error: No response. <br/><br/> Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
1054
  );
1055
  cache.get("#wpstg-loader").hide();
1056
  cache.get(".wpstg-loader").hide();
1061
  if ("undefined" !== typeof (response.error) && response.error) {
1062
  console.log(response.message);
1063
  showError(
1064
+ "Something went wrong! Error:" + response.message + ". Please try the <a href='https://wp-staging.com/docs/wp-staging-settings-for-small-servers/' target='_blank'>WP Staging Small Server Settings</a> or submit an error report."
 
 
1065
  );
1066
 
1067
  return;
1123
  cache.get("#wpstg_staging_name").html(that.data.cloneID);
1124
  cache.get("#wpstg-finished-result").show();
1125
  cache.get("#wpstg-cancel-cloning").hide();
1126
+ cache.get("#wpstg-resume-cloning").hide();
1127
  cache.get("#wpstg-cancel-cloning-update").prop("disabled", true);
1128
 
1129
  var $link1 = cache.get("#wpstg-clone-url-1");
apps/Backend/views/_includes/messages/beta.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="wpstg_beta_notice error" style="box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);">
2
  <p>
3
  WP Staging is well tested and we did a lot to catch every possible error but
4
  we can not handle all possible combinations of server, plugins and themes. <br>
1
+ <div class="wpstg_beta_notice wpstg-error" style="box-shadow: 0 1px 1px 0 rgba(0,0,0,.1);">
2
  <p>
3
  WP Staging is well tested and we did a lot to catch every possible error but
4
  we can not handle all possible combinations of server, plugins and themes. <br>
apps/Backend/views/_includes/messages/cache-directory-permission-problem.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}cache"?> is not write and/or readable.
4
  <br>
1
+ <div class="wpstg-error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}cache"?> is not write and/or readable.
4
  <br>
apps/Backend/views/_includes/messages/logs-directory-permission-problem.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}logs"?> is not write and/or readable.
4
  <br>
1
+ <div class="wpstg-error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}logs"?> is not write and/or readable.
4
  <br>
apps/Backend/views/_includes/messages/staging-directory-permission-problem.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <strong>
4
  <?php echo sprintf(__('WP Staging Folder Permission error:</strong>
1
+ <div class="wpstg-error">
2
  <p>
3
  <strong>
4
  <?php echo sprintf(__('WP Staging Folder Permission error:</strong>
apps/Backend/views/_includes/messages/uploads-cache-directory-permission-problem.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong>
4
  <?php echo \WPStaging\WPStaging::getContentDir()?>
1
+ <div class="wpstg-error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong>
4
  <?php echo \WPStaging\WPStaging::getContentDir()?>
apps/Backend/views/_includes/messages/vars-directory-permission-problem.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}"?> is not write and/or readable.
4
  <br>
1
+ <div class="wpstg-error">
2
  <p>
3
  <strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}"?> is not write and/or readable.
4
  <br>
apps/Backend/views/_includes/messages/wp-version-compatible-message.php CHANGED
@@ -1,4 +1,4 @@
1
- <div class="error">
2
  <p>
3
  <?php
4
  echo sprintf( __(
1
+ <div class="wpstg-error">
2
  <p>
3
  <?php
4
  echo sprintf( __(
apps/Backend/views/_includes/messages/wrong-scheme.php ADDED
@@ -0,0 +1,7 @@
 
 
 
 
 
 
 
1
+ <div class="wpstg-error">
2
+ <p>
3
+ <strong><?php _e( 'WP Staging HTTP/HTTPS Scheme Error:', 'wp-staging' ); ?></strong>
4
+ <?php echo sprintf(__( 'Go to <a href="%s" target="_blank">Settings > General</a> and make sure that WordPress Address (URL) and Site Address (URL) do both contain the same http / https scheme.', 'wp-staging' ), admin_url() . 'options-general.php'); ?>
5
+ <br>
6
+ <?php _e( 'Otherwise your staging site will not be reachable after creation.', 'wp-staging' ); ?></p>
7
+ </div>
apps/Backend/views/clone/ajax/start.php CHANGED
@@ -17,6 +17,10 @@
17
  <?php echo __("Cancel", "wp-staging")?>
18
  </button>
19
 
 
 
 
 
20
  <button type="button" id="wpstg-show-log-button" class="button" data-clone="<?php echo $cloning->getOptions()->clone?>" style="margin-top: 5px;display:none;">
21
  <?php _e('Display working log', 'wp-staging')?>
22
  </button>
17
  <?php echo __("Cancel", "wp-staging")?>
18
  </button>
19
 
20
+ <button type="button" id="wpstg-resume-cloning" class="wpstg-link-btn button-primary">
21
+ <?php echo __("Resume", "wp-staging")?>
22
+ </button>
23
+
24
  <button type="button" id="wpstg-show-log-button" class="button" data-clone="<?php echo $cloning->getOptions()->clone?>" style="margin-top: 5px;display:none;">
25
  <?php _e('Display working log', 'wp-staging')?>
26
  </button>
apps/Backend/views/welcome/welcome.php CHANGED
@@ -8,8 +8,9 @@
8
  <li><strong>Authentication</strong> - <?php _e( 'Staging Site is available to authenticated users only', 'wp-staging' ); ?></li>
9
  <li><strong>High Performance</strong> - <?php _e( 'Cloning process is fast and does not slow down website loading', 'wp-staging' ); ?></li>
10
  <li><strong>Secure</strong> - <?php _e( 'WP Staging is coded well for protection of your data', 'wp-staging' ); ?></li>
 
11
  <a href="http://wp-staging.com/?utm_source=wpstg&utm_medium=addon_page&utm_term=click-wpstaging-pro&utm_campaign=wpstaging" target="_blank" class="wpstg-button green">Buy WP Staging Pro</a>
12
  <a href="<?php echo admin_url(); ?>admin.php?page=wpstg_clone" target="_self" style="margin-left:30px;">Skip - Start Cloning</a>
13
- <div class="wpstg-footer"> <?php _e( 'Comes with our 30-day no questions asked money back guarantee', 'wp-staging' ); ?></div>
14
  </div>
15
  </div>
8
  <li><strong>Authentication</strong> - <?php _e( 'Staging Site is available to authenticated users only', 'wp-staging' ); ?></li>
9
  <li><strong>High Performance</strong> - <?php _e( 'Cloning process is fast and does not slow down website loading', 'wp-staging' ); ?></li>
10
  <li><strong>Secure</strong> - <?php _e( 'WP Staging is coded well for protection of your data', 'wp-staging' ); ?></li>
11
+ <li><strong>Multisites</strong> - <?php _e( 'WP Staging Pro allows to clone and push Multisites, (main site & sub sites)', 'wp-staging' ); ?></li>
12
  <a href="http://wp-staging.com/?utm_source=wpstg&utm_medium=addon_page&utm_term=click-wpstaging-pro&utm_campaign=wpstaging" target="_blank" class="wpstg-button green">Buy WP Staging Pro</a>
13
  <a href="<?php echo admin_url(); ?>admin.php?page=wpstg_clone" target="_self" style="margin-left:30px;">Skip - Start Cloning</a>
14
+ <div class="wpstg-footer"> <?php _e( 'Comes with our 30-day money back guarantee * You need to give us chance to resolve your issue first.', 'wp-staging' ); ?></div>
15
  </div>
16
  </div>
apps/Core/Utils/Cache.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  namespace WPStaging\Utils;
3
 
4
  // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
  }
9
 
10
  use WPStaging\WPStaging;
@@ -13,206 +13,189 @@ use WPStaging\WPStaging;
13
  * Class Cache
14
  * @package WPStaging\Utils
15
  */
16
- class Cache
17
- {
18
- /**
19
- * Cache directory (full path)
20
- * @var string
21
- */
22
- private $cacheDir;
23
-
24
- /**
25
- * Cache file extension
26
- * @var string
27
- */
28
- private $cacheExtension = "cache";
29
-
30
- /**
31
- * Lifetime of cache files in seconds
32
- * @var int
33
- */
34
- private $lifetime = 2592000; // 30 days
35
-
36
- /**
37
- * Cache constructor.
38
- * @param null|int $lifetime
39
- * @param null|string $cacheDir
40
- * @param null|string $cacheExtension
41
- * @throws \Exception
42
- */
43
- public function __construct($lifetime = null, $cacheDir = null, $cacheExtension = null)
44
- {
45
- // Set lifetime
46
- $lifetime = (int) $lifetime;
47
- if ($lifetime > 0)
48
- {
49
- $this->lifetime = $lifetime;
50
- }
51
-
52
- // Set cache directory
53
- if (!empty($cacheDir) && is_dir($cacheDir))
54
- {
55
- $this->cacheDir = $cacheDir;
56
- }
57
- // Set default
58
- else
59
- {
60
-
61
- $this->cacheDir = \WPStaging\WPStaging::getContentDir();
62
- }
63
-
64
- // Set cache extension
65
- if (!empty($cacheExtension))
66
- {
67
- $this->cacheExtension = $cacheExtension;
68
- }
69
-
70
- // If cache directory doesn't exists, create it
71
- if (!is_dir($this->cacheDir) && !@mkdir($this->cacheDir, 0775, true))
72
- {
73
- throw new \Exception("Failed to create cache directory " . $this->cacheDir . '! Make sure folder permission is 755 and owner is correct. Should be www-data or similar.');
74
- }
75
-
76
- }
77
-
78
- /**
79
- * Get cache
80
- * @param string $cacheFileName
81
- * @param mixed $defaultValue
82
- * @param null|int $lifetime
83
- * @return mixed|null
84
- */
85
- public function get($cacheFileName, $defaultValue = null, $lifetime = null)
86
- {
87
- // Check if file is valid
88
- if (false === ($cacheFile = $this->isValid($cacheFileName, true, $lifetime)))
89
- {
90
- return $defaultValue;
91
- }
92
-
93
- return @unserialize(file_get_contents($cacheFile));
94
- }
95
-
96
- /**
97
- * Saves value to given cache file
98
- * @param string $cacheFileName
99
- * @param mixed $value
100
- * @return bool
101
- * @throws \Exception
102
- */
103
- public function save($cacheFileName, $value)
104
- {
105
- $cacheFile = $this->cacheDir . $cacheFileName . '.' . $this->cacheExtension;
106
-
107
- // Attempt to delete cache file if it exists
108
- if (is_file($cacheFile) && !@unlink($cacheFile))
109
- {
110
- $this->returnException("Can't delete existing cache file");
111
- throw new \Exception("Can't delete existing cache file");
112
- }
113
-
114
- // Save it to file
115
- //return (file_put_contents($cacheFile, @serialize($value), LOCK_EX) !== false);
116
- if (!file_put_contents($cacheFile, @serialize($value))){
117
- $this->returnException(" Can't save data to: " . $cacheFile);
118
- return false;
119
- }
120
- return true;
121
- //return (file_put_contents($cacheFile, @serialize($value)) !== false);
122
- }
123
-
124
- /**
125
- * Checks if file is valid or not
126
- * @param $cacheFileName
127
- * @param bool $deleteFileIfInvalid
128
- * @param null|int $lifetime
129
- * @return string|bool
130
- * @throws \Exception
131
- */
132
- public function isValid($cacheFileName, $deleteFileIfInvalid = false, $lifetime = null)
133
- {
134
- // Lifetime
135
- $lifetime = (int) $lifetime;
136
- if (-1 > $lifetime || 0 == $lifetime)
137
- {
138
- $lifetime = $this->lifetime;
139
- }
140
-
141
- // Get full path of the given cache file
142
- $cacheFile = $this->cacheDir . $cacheFileName . '.' . $this->cacheExtension;
143
-
144
- // File doesn't exist
145
- if (!is_file($cacheFile))
146
- {
147
- return false;
148
- }
149
-
150
- // As long as file exists, don't check lifetime
151
- if (-1 == $lifetime)
152
- {
153
- return $cacheFile;
154
- }
155
-
156
- // Time is up, file is invalid
157
- if (time() - filemtime($cacheFile) >= $lifetime)
158
- {
159
-
160
- // Attempt to delete the file
161
- if ($deleteFileIfInvalid === true && !@unlink($cacheFile))
162
- {
163
- throw new \Exception("Attempting to delete invalid cache file has failed!");
164
- }
165
-
166
- // No need to delete the file, return
167
- return false;
168
- }
169
-
170
- return $cacheFile;
171
- }
172
-
173
- /**
174
- * Delete a cache file
175
- * @param string $cacheFileName
176
- * @return bool
177
- * @throws \Exception
178
- */
179
- public function delete($cacheFileName)
180
- {
181
- if (false !== ($cacheFile = $this->isValid($cacheFileName, true)) && false === @unlink($cacheFile))
182
- {
183
- throw new \Exception("Couldn't delete cache: {$cacheFileName}. Full Path: {$cacheFile}");
184
- }
185
-
186
- return true;
187
- }
188
-
189
- /**
190
- * @return string
191
- */
192
- public function getCacheDir()
193
- {
194
- return $this->cacheDir;
195
- }
196
-
197
- /**
198
- * @return string
199
- */
200
- public function getCacheExtension()
201
- {
202
- return $this->cacheExtension;
203
- }
204
-
205
-
206
- /**
207
- * Throw a errror message via json and stop further execution
208
- * @param string $message
209
- */
210
- protected function returnException($message = ''){
211
- wp_die( json_encode(array(
212
- 'job' => isset($this->options->currentJob) ? $this->options->currentJob : '',
213
- 'status' => false,
214
- 'message' => $message,
215
- 'error' => true
216
- )));
217
  }
218
- }
1
  <?php
2
+
3
  namespace WPStaging\Utils;
4
 
5
  // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
 
8
  }
9
 
10
  use WPStaging\WPStaging;
13
  * Class Cache
14
  * @package WPStaging\Utils
15
  */
16
+ class Cache {
17
+
18
+ /**
19
+ * Cache directory (full path)
20
+ * @var string
21
+ */
22
+ private $cacheDir;
23
+
24
+ /**
25
+ * Cache file extension
26
+ * @var string
27
+ */
28
+ private $cacheExtension = "cache";
29
+
30
+ /**
31
+ * Lifetime of cache files in seconds
32
+ * @var int
33
+ */
34
+ private $lifetime = 2592000; // 30 days
35
+
36
+ /**
37
+ * Cache constructor.
38
+ * @param null|int $lifetime
39
+ * @param null|string $cacheDir
40
+ * @param null|string $cacheExtension
41
+ * @throws \Exception
42
+ */
43
+
44
+ public function __construct( $lifetime = null, $cacheDir = null, $cacheExtension = null ) {
45
+ // Set lifetime
46
+ $lifetime = ( int ) $lifetime;
47
+ if( $lifetime > 0 ) {
48
+ $this->lifetime = $lifetime;
49
+ }
50
+
51
+ // Set cache directory
52
+ if( !empty( $cacheDir ) && is_dir( $cacheDir ) ) {
53
+ $this->cacheDir = $cacheDir;
54
+ }
55
+ // Set default
56
+ else {
57
+
58
+ $this->cacheDir = \WPStaging\WPStaging::getContentDir();
59
+ }
60
+
61
+ // Set cache extension
62
+ if( !empty( $cacheExtension ) ) {
63
+ $this->cacheExtension = $cacheExtension;
64
+ }
65
+
66
+ // If cache directory doesn't exists, create it
67
+ if( !is_dir( $this->cacheDir ) && !@mkdir( $this->cacheDir, 0775, true ) ) {
68
+ throw new \Exception( "Failed to create cache directory " . $this->cacheDir . '! Make sure folder permission is 755 and owner is correct. Should be www-data or similar.' );
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Get cache
74
+ * @param string $cacheFileName
75
+ * @param mixed $defaultValue
76
+ * @param null|int $lifetime
77
+ * @return mixed|null
78
+ */
79
+ public function get( $cacheFileName, $defaultValue = null, $lifetime = null ) {
80
+ // Check if file is valid
81
+ if( false === ($cacheFile = $this->isValid( $cacheFileName, true, $lifetime )) ) {
82
+ return $defaultValue;
83
+ }
84
+
85
+ return @unserialize( file_get_contents( $cacheFile ) );
86
+ }
87
+
88
+ /**
89
+ * Saves value to given cache file
90
+ * @param string $cacheFileName
91
+ * @param mixed $value
92
+ * @return bool
93
+ * @throws \Exception
94
+ */
95
+ public function save( $cacheFileName, $value ) {
96
+ $cacheFile = $this->cacheDir . $cacheFileName . '.' . $this->cacheExtension;
97
+
98
+ // Attempt to delete cache file if it exists
99
+ if( is_file( $cacheFile ) && !@unlink( $cacheFile ) ) {
100
+ $this->returnException( "Can't delete existing cache file" );
101
+ throw new \Exception( "Can't delete existing cache file" );
102
+ }
103
+
104
+ try {
105
+ // Save it to file
106
+ if( !file_put_contents( $cacheFile, @serialize( $value ) ) ) {
107
+ $this->returnException( " Can't save data to: " . $cacheFile . " Disk quota exceeded or not enough free disk space left" );
108
+ return false;
109
+ }
110
+ } catch ( Exception $e ) {
111
+ $this->returnException( " Can't save data to: " . $cacheFile . " Error: " . $e );
112
+ return false;
113
+ }
114
+ return true;
115
+ }
116
+
117
+ /**
118
+ * Checks if file is valid or not
119
+ * @param $cacheFileName
120
+ * @param bool $deleteFileIfInvalid
121
+ * @param null|int $lifetime
122
+ * @return string|bool
123
+ * @throws \Exception
124
+ */
125
+ public function isValid( $cacheFileName, $deleteFileIfInvalid = false, $lifetime = null ) {
126
+ // Lifetime
127
+ $lifetime = ( int ) $lifetime;
128
+ if( -1 > $lifetime || 0 == $lifetime ) {
129
+ $lifetime = $this->lifetime;
130
+ }
131
+
132
+ // Get full path of the given cache file
133
+ $cacheFile = $this->cacheDir . $cacheFileName . '.' . $this->cacheExtension;
134
+
135
+ // File doesn't exist
136
+ if( !is_file( $cacheFile ) ) {
137
+ return false;
138
+ }
139
+
140
+ // As long as file exists, don't check lifetime
141
+ if( -1 == $lifetime ) {
142
+ return $cacheFile;
143
+ }
144
+
145
+ // Time is up, file is invalid
146
+ if( time() - filemtime( $cacheFile ) >= $lifetime ) {
147
+
148
+ // Attempt to delete the file
149
+ if( $deleteFileIfInvalid === true && !@unlink( $cacheFile ) ) {
150
+ throw new \Exception( "Attempting to delete invalid cache file has failed!" );
151
+ }
152
+
153
+ // No need to delete the file, return
154
+ return false;
155
+ }
156
+
157
+ return $cacheFile;
158
+ }
159
+
160
+ /**
161
+ * Delete a cache file
162
+ * @param string $cacheFileName
163
+ * @return bool
164
+ * @throws \Exception
165
+ */
166
+ public function delete( $cacheFileName ) {
167
+ if( false !== ($cacheFile = $this->isValid( $cacheFileName, true )) && false === @unlink( $cacheFile ) ) {
168
+ throw new \Exception( "Couldn't delete cache: {$cacheFileName}. Full Path: {$cacheFile}" );
169
+ }
170
+
171
+ return true;
172
+ }
173
+
174
+ /**
175
+ * @return string
176
+ */
177
+ public function getCacheDir() {
178
+ return $this->cacheDir;
179
+ }
180
+
181
+ /**
182
+ * @return string
183
+ */
184
+ public function getCacheExtension() {
185
+ return $this->cacheExtension;
186
+ }
187
+
188
+ /**
189
+ * Throw a errror message via json and stop further execution
190
+ * @param string $message
191
+ */
192
+ protected function returnException( $message = '' ) {
193
+ wp_die( json_encode( array(
194
+ 'job' => isset( $this->options->currentJob ) ? $this->options->currentJob : '',
195
+ 'status' => false,
196
+ 'message' => $message,
197
+ 'error' => true
198
+ ) ) );
199
+ }
200
+
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  }
 
apps/Core/Utils/Multisite.php CHANGED
@@ -12,15 +12,48 @@ if( !defined( "WPINC" ) ) {
12
  class Multisite {
13
 
14
  /**
15
- * Get multisite main site homeurl
16
- * @return string
17
  */
18
- public function getHomeURL() {
 
 
19
  $helper = new Helper();
 
 
20
 
21
- $url = $helper->get_home_url();
22
- $result = parse_url( $url );
 
 
 
 
23
  return $result['scheme'] . "://" . $result['host'];
24
  }
25
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
12
  class Multisite {
13
 
14
  /**
15
+ *
16
+ * @var object
17
  */
18
+ private $url;
19
+
20
+ public function __construct() {
21
  $helper = new Helper();
22
+ $this->url = $helper->get_home_url();
23
+ }
24
 
25
+ /**
26
+ * Get multisite main site domain e.g. https://blog.domain.com or https://domain.com
27
+ * @return string
28
+ */
29
+ public function getHomeDomain() {
30
+ $result = parse_url( $this->url );
31
  return $result['scheme'] . "://" . $result['host'];
32
  }
33
 
34
+ /**
35
+ * Return domain without scheme e.g. blog.domain.com or domain.com
36
+ * @param string $str
37
+ * @return string
38
+ */
39
+ public function getHomeDomainWithoutScheme() {
40
+ return preg_replace( '#^https?://#', '', rtrim( $this->getHomeDomain(), '/' ) );
41
+ }
42
+ /**
43
+ * Get home url e.g. blog.domain.com
44
+ * @return type
45
+ */
46
+ public function getHomeUrl() {
47
+ return $this->url;
48
+ }
49
+
50
+ /**
51
+ * Return url without scheme e.g. blog.domain.com/site1 or domain.com/site1
52
+ * @param string $str
53
+ * @return string
54
+ */
55
+ public function getHomeUrlWithoutScheme() {
56
+ return preg_replace( '#^https?://#', '', rtrim( $this->url, '/' ) );
57
+ }
58
+
59
  }
apps/Core/Utils/requirements-check.php ADDED
@@ -0,0 +1,70 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Wpstg_Requirements_Check {
4
+
5
+ private $title = '';
6
+ private $php = '5.2.4';
7
+ private $wp = '3.8';
8
+ private $file;
9
+
10
+ public function __construct( $args ) {
11
+ foreach ( array('title', 'php', 'wp', 'file') as $setting ) {
12
+ if( isset( $args[$setting] ) ) {
13
+ $this->$setting = $args[$setting];
14
+ }
15
+ }
16
+ }
17
+
18
+ public function passes() {
19
+ $passes = $this->php_passes() && $this->wp_passes();
20
+ if( !$passes ) {
21
+ add_action( 'admin_notices', array($this, 'deactivate') );
22
+ }
23
+ return $passes;
24
+ }
25
+
26
+ public function deactivate() {
27
+ if( isset( $this->file ) ) {
28
+ deactivate_plugins( plugin_basename( $this->file ) );
29
+ }
30
+ }
31
+
32
+ private function php_passes() {
33
+ if( $this->__php_at_least( $this->php ) ) {
34
+ return true;
35
+ } else {
36
+ add_action( 'admin_notices', array($this, 'php_version_notice') );
37
+ return false;
38
+ }
39
+ }
40
+
41
+ private static function __php_at_least( $min_version ) {
42
+ return version_compare( phpversion(), $min_version, '>=' );
43
+ }
44
+
45
+ public function php_version_notice() {
46
+ echo '<div class="error">';
47
+ echo "<p>The &#8220;" . esc_html( $this->title ) . "&#8221; plugin cannot run on PHP versions older than " . $this->php . '. Please contact your host and ask them to upgrade.</p>';
48
+ echo '</div>';
49
+ }
50
+
51
+ private function wp_passes() {
52
+ if( $this->__wp_at_least( $this->wp ) ) {
53
+ return true;
54
+ } else {
55
+ add_action( 'admin_notices', array($this, 'wp_version_notice') );
56
+ return false;
57
+ }
58
+ }
59
+
60
+ private static function __wp_at_least( $min_version ) {
61
+ return version_compare( get_bloginfo( 'version' ), $min_version, '>=' );
62
+ }
63
+
64
+ public function wp_version_notice() {
65
+ echo '<div class="error">';
66
+ echo "<p>The &#8220;" . esc_html( $this->title ) . "&#8221; plugin cannot run on WordPress versions older than " . $this->wp . '. Please update WordPress.</p>';
67
+ echo '</div>';
68
+ }
69
+
70
+ }
apps/Core/WPStaging.php CHANGED
@@ -29,7 +29,7 @@ final class WPStaging {
29
  /**
30
  * Plugin version
31
  */
32
- const VERSION = "2.3.6";
33
 
34
  /**
35
  * Plugin name
@@ -375,12 +375,12 @@ final class WPStaging {
375
  break;
376
 
377
  case "low":
378
- $cpuLoad = 1500;
379
  break;
380
 
381
  case "default":
382
  default:
383
- $cpuLoad = 1000;
384
  }
385
 
386
  return $cpuLoad;
29
  /**
30
  * Plugin version
31
  */
32
+ const VERSION = "2.3.7";
33
 
34
  /**
35
  * Plugin name
375
  break;
376
 
377
  case "low":
378
+ $cpuLoad = 0;
379
  break;
380
 
381
  case "default":
382
  default:
383
+ $cpuLoad = 0;
384
  }
385
 
386
  return $cpuLoad;
install.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging;
4
+
5
+ use WPStaging\WPStaging;
6
+ use WPStaging\Backend\Optimizer\Optimizer;
7
+ use WPStaging\Cron\Cron;
8
+
9
+ /**
10
+ * Install Function
11
+ *
12
+ */
13
+ // Exit if accessed directly
14
+ if( !defined( 'ABSPATH' ) )
15
+ exit;
16
+
17
+ /*
18
+ * Install Multisite
19
+ * check first if multisite is enabled
20
+ * @since 2.1.1
21
+ *
22
+ */
23
+
24
+
25
+ class Install {
26
+
27
+ public function __construct() {
28
+ register_activation_hook( __DIR__ . DIRECTORY_SEPARATOR . WPSTG_PLUGIN_SLUG . '.php', array($this, 'activation') );
29
+ }
30
+
31
+ public static function activation() {
32
+ // Register cron job.
33
+ $cron = new \WPStaging\Cron\Cron;
34
+ $cron->schedule_event();
35
+
36
+ // Install Optimizer
37
+ $optimizer = new Optimizer();
38
+ $optimizer->installOptimizer();
39
+
40
+ // Add the transient to redirect for class Welcome (not for multisites)
41
+ set_transient( 'wpstg_activation_redirect', true, 3600 );
42
+ }
43
+
44
+ }
45
+
46
+ new Install();
languages/wp-staging-it_1.mo ADDED
Binary file
languages/wp-staging-it_1.po ADDED
@@ -0,0 +1,418 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Translation of Plugins - WP Staging &#8211; DB &amp; File Duplicator &amp; Migration - Stable Readme (latest release) in Italian
2
+ # This file is distributed under the same license as the Plugins - WP Staging &#8211; DB &amp; File Duplicator &amp; Migration - Stable Readme (latest release) package.
3
+ msgid ""
4
+ msgstr ""
5
+ "PO-Revision-Date: 2015-12-01 15:35:13+0000\n"
6
+ "MIME-Version: 1.0\n"
7
+ "Content-Type: text/plain; charset=UTF-8\n"
8
+ "Content-Transfer-Encoding: 8bit\n"
9
+ "Plural-Forms: nplurals=2; plural=n != 1;\n"
10
+ "X-Generator: GlotPress/2.4.0-alpha\n"
11
+ "Language: it\n"
12
+ "Project-Id-Version: Plugins - WP Staging &#8211; DB &amp; File Duplicator &amp; Migration - Stable Readme (latest release)\n"
13
+
14
+ #. Short description.
15
+ msgid "A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators."
16
+ msgstr ""
17
+
18
+ #. Plugin name.
19
+ msgid "WP Staging - DB &amp; File Duplicator &amp; Migration"
20
+ msgstr ""
21
+
22
+ #. Found in changelog list item.
23
+ msgid "Fix: Missing http(s) scheme after cloning multisites results in not working clones"
24
+ msgstr ""
25
+
26
+ #. Found in changelog list item.
27
+ msgid "New: Support for Windows Azure cloud servers"
28
+ msgstr ""
29
+
30
+ #. Found in changelog list item.
31
+ msgid "Fix: Do not search &amp; replace mail addresses"
32
+ msgstr ""
33
+
34
+ #. Found in changelog list item.
35
+ msgid "Fix: Remove term 'Error' from login page"
36
+ msgstr ""
37
+
38
+ #. Found in changelog list item.
39
+ msgid "New: Login options not needed any more - removed"
40
+ msgstr ""
41
+
42
+ #. Found in changelog list item.
43
+ msgid "New: Detect if wp-config.php has been moved one folder level up"
44
+ msgstr ""
45
+
46
+ #. Found in changelog list item.
47
+ msgid "New: Better error reporting"
48
+ msgstr ""
49
+
50
+ #. Found in changelog list item.
51
+ msgid "New: Compatible up to WordPress 4.9.8"
52
+ msgstr ""
53
+
54
+ #. Found in changelog list item.
55
+ msgid "New: Setting to specify the maximum allowed file size to copy"
56
+ msgstr ""
57
+
58
+ #. Found in changelog list item.
59
+ msgid "Fix: Search &amp; replace path not correct if scheme http/https is not identical in wp-config and db wp_options"
60
+ msgstr ""
61
+
62
+ #. Found in changelog list item.
63
+ msgid "Fix: Creating a new clone resets the custom wp staging user settings. E.g. ignores authentication setting"
64
+ msgstr ""
65
+
66
+ #. Found in changelog list item.
67
+ msgid "Tweak: Remove certain debugging notices from the default log window"
68
+ msgstr ""
69
+
70
+ #. Found in changelog list item.
71
+ msgid "Tweaks: remove term \"error\" from several log entries"
72
+ msgstr ""
73
+
74
+ #. Found in changelog list item.
75
+ msgid "Fix: Search &amp; Replace not working if serialized object contains __PHP_Incomplete_Class_Name"
76
+ msgstr ""
77
+
78
+ #. Found in changelog list item.
79
+ msgid "Fix: Skip search &amp; replace for objects where key is null"
80
+ msgstr ""
81
+
82
+ #. Found in changelog list item.
83
+ msgid "Fix: Parameter must be an array or an object that implements Callable"
84
+ msgstr ""
85
+
86
+ #. Found in changelog list item.
87
+ msgid "Fix: wp-config.php not copied when previous clone updating process has been failed"
88
+ msgstr ""
89
+
90
+ #. Found in changelog list item.
91
+ msgid "Fix: Undefined object $this-&gt;tables"
92
+ msgstr ""
93
+
94
+ #. Found in changelog list item.
95
+ msgid "Fix: Can not open upload folder in file selection menu"
96
+ msgstr ""
97
+
98
+ #. Found in changelog list item.
99
+ msgid "Fix: Progress bar not shown as intented for clone updating process"
100
+ msgstr ""
101
+
102
+ #. Found in changelog list item.
103
+ msgid "Fix: If cloning update process is interupted it may happen that staging site is not available any longer. (Updating the clone does not copy index.php to staging site again)"
104
+ msgstr ""
105
+
106
+ #. Found in changelog list item.
107
+ msgid "Fix: Progress bar for step 'database' is not filling up to 100%"
108
+ msgstr ""
109
+
110
+ #. Found in changelog list item.
111
+ msgid "New: Use the new progress bar for clone updating process"
112
+ msgstr ""
113
+
114
+ #. Found in changelog list item.
115
+ msgid "New: Add multisite informations in system info log"
116
+ msgstr ""
117
+
118
+ #. Found in changelog list item.
119
+ msgid "New: Option to allow adjustment of the allowed maximum size of files that are going to be copied while cloning."
120
+ msgstr ""
121
+
122
+ #. Found in changelog list item.
123
+ msgid "Security: Do not allow to create a new staging site into a subfolder which already exists"
124
+ msgstr ""
125
+
126
+ #. Found in changelog list item.
127
+ msgid "Fix: Missing trailingslash results to wrong absolute paths in database after Search &amp; Replace operation "
128
+ msgstr ""
129
+
130
+ #. Found in changelog list item.
131
+ msgid "New: Compatible to WordPress 4.9.6"
132
+ msgstr ""
133
+
134
+ #. Found in changelog list item.
135
+ msgid "New: Add new setting which allow to specify the search &amp; replace processing query limit"
136
+ msgstr ""
137
+
138
+ #. Found in changelog list item.
139
+ msgid "New: Supports search &amp; replace for revslider image slider and several visual editors which are using non default serialized data"
140
+ msgstr ""
141
+
142
+ #. Found in changelog list item.
143
+ msgid "New: Add filter 'wpstg_fiter_search_replace_rows' to exclude certain tables from search &amp; replace"
144
+ msgstr ""
145
+
146
+ #. Found in changelog list item.
147
+ msgid "New: Add datetime timestamp internally to clone. (Used in WP Staging pro)"
148
+ msgstr ""
149
+
150
+ #. Found in changelog list item.
151
+ msgid "New: Support for custom upload folder. For instance, if upload folder has been renamed and removed outsite wp-content folder"
152
+ msgstr ""
153
+
154
+ #. Found in changelog list item.
155
+ msgid "New: Exclude tables for plugin wp_mail_smtp"
156
+ msgstr ""
157
+
158
+ #. Found in changelog list item.
159
+ msgid "New: Add filter 'wpstg_filter_options_replace' to exclude certain tables from updating while cloning"
160
+ msgstr ""
161
+
162
+ #. Found in changelog list item.
163
+ msgid "Fix: WP_SITEURL &amp; WP_HOME not replaced if constant contains php generated string"
164
+ msgstr ""
165
+
166
+ #. Found in changelog list item.
167
+ msgid "Fix: Serialize replace is not working properly for serialized strings"
168
+ msgstr ""
169
+
170
+ #. Found in faq list item.
171
+ msgid ""
172
+ "I can not login to the staging site\n"
173
+ "If you are using a security plugin like All In One WP Security &amp; Firewall you need to install latest version of WP Staging. \n"
174
+ "Go to WP Staging &gt; Settings and add the slug to the custom login page which you set up in All In One WP Security &amp; Firewall plugin."
175
+ msgstr ""
176
+
177
+ #. Found in installation list item, faq list item.
178
+ msgid "Upload and install it via the WordPress plugin backend wp-admin &gt; plugins &gt; add new &gt; uploads"
179
+ msgstr ""
180
+
181
+ #. Found in installation list item, faq list item.
182
+ msgid "Download the file \"wp-staging.zip\":"
183
+ msgstr ""
184
+
185
+ #. Found in description paragraph.
186
+ msgid ""
187
+ "Permalinks are disabled on the staging site because the staging site is cloned into a subfolder and permalinks are not working on all systems\n"
188
+ "without doing changes to the .htaccess (Apache server) or nginx.conf (Nginx Server).\n"
189
+ "<a href=\"https://wp-staging.com/docs/activate-permalinks-staging-site/\" title=\"activate permalinks on staging site\">Read here</a> how to activate permalinks on the staging site."
190
+ msgstr ""
191
+
192
+ #. Found in description list item.
193
+ msgid "New: Compatible to All In One WP Security &amp; Firewall"
194
+ msgstr ""
195
+
196
+ #. Found in description paragraph.
197
+ msgid "Note: WordPress 5.0 will be shipped with a new visual editor called Gutenberg. Use WP Staging to check if Gutenberg editor is working as intended on your website and that all used plugins are compatible with that new editor."
198
+ msgstr ""
199
+
200
+ #. Found in changelog paragraph.
201
+ msgid "Complete changelog: <a href=\"https://wp-staging.com/changelog.txt\">https://wp-staging.com/changelog.txt</a>"
202
+ msgstr ""
203
+
204
+ #. Found in description paragraph.
205
+ msgid "https://wp-staging.com"
206
+ msgstr ""
207
+
208
+ #. Found in description paragraph.
209
+ msgid ""
210
+ "<strong>This cloning and staging plugin is well tested and work in progress. <br /><br />\n"
211
+ "If you find any issue, please open a <a href=\"https://wp-staging.com/support/\" title=\"support ticket\">support ticket</a>.\n"
212
+ "</strong>\n"
213
+ "<br /><br />\n"
214
+ "<strong>Note: </strong> For pushing &amp; migrating plugins and theme files to live site, check out the pro version <a href=\"https://wp-staging.com/\" title=\"WP Staging Pro\">https://wp-staging.com/</a>\n"
215
+ "<br /><br />"
216
+ msgstr ""
217
+
218
+ #. Found in faq header.
219
+ msgid "Installation Instructions"
220
+ msgstr ""
221
+
222
+ #. Found in description list item.
223
+ msgid ""
224
+ "WordPress duplicating process on windows server (not tested but will probably work) \n"
225
+ "Edit: Duplication on windows server seems to be working well: <a href=\"https://wordpress.org/support/topic/wont-copy-files?replies=5\" title=\"Read more\">Read more</a> "
226
+ msgstr ""
227
+
228
+ #. Found in description list item.
229
+ msgid ""
230
+ "<strong>Safe: </strong> Access to staging site is granted for administrators only.\n"
231
+ "<br /><br />\n"
232
+ "<strong>More safe:</strong> \n"
233
+ "<br />"
234
+ msgstr ""
235
+
236
+ #. Found in description paragraph.
237
+ msgid "[youtube https://www.youtube.com/watch?v=Ye3fC6cdB3A]"
238
+ msgstr ""
239
+
240
+ #. Found in description header.
241
+ msgid "Official Site"
242
+ msgstr ""
243
+
244
+ #. Found in installation list item, faq list item.
245
+ msgid "Activate the plugin through the 'Plugins' menu in WordPress."
246
+ msgstr "Attivare il plugin tramite il menu 'Plugin' di WordPress"
247
+
248
+ #. Found in description paragraph.
249
+ msgid ""
250
+ "Install it via the admin dashboard and to 'Plugins', click 'Add New' and search the plugins for 'Staging'. Install the plugin with 'Install Now'.\n"
251
+ "After installation goto the settings page 'Staging' and do your adjustments there."
252
+ msgstr ""
253
+
254
+ #. Found in description paragraph.
255
+ msgid ""
256
+ "This plugin has been done in hundreds of hours to work on even the smallest shared webhosting package but i am limited in testing this only on a handful of different server so i need your help:\n"
257
+ "Please open a <a href=\"https://wordpress.org/support/plugin/wp-staging/\" title=\"support request\">support request</a> and describe your problem exactely. In wp-content/wp-staging/logs you find extended logfiles. Have a look at them and let me know the error-thrown lines."
258
+ msgstr ""
259
+
260
+ #. Found in description paragraph.
261
+ msgid ""
262
+ "So, if you have created a local or webhosted development site and you need to migrate this site the first time to your production domain than you are doing nothing wrong with using\n"
263
+ "the Duplicator plugin! If you need all you latest production data like posts, updated plugins, theme data and styles in a testing environment than i recommend to use WP Staging instead!"
264
+ msgstr ""
265
+
266
+ #. Found in description paragraph.
267
+ msgid ""
268
+ "At first, i love the <a href=\"https://wordpress.org/plugins/duplicator/\" title=\"Duplicator plugin\">Duplicator plugin</a>. Duplicator is a great tool for migrating from development site to production one or from production site to development one. \n"
269
+ "The downside is that Duplicator needs adjustments, manually interventions and prerequirements for this. Duplicator also needs some skills to be able to create a development / staging site, where WP Staging does not need more than a click from you.\n"
270
+ "However, Duplicator is best placed to be a tool for first-time creation of your production site. This is something where it is very handy and powerful."
271
+ msgstr ""
272
+
273
+ #. Found in description paragraph.
274
+ msgid ""
275
+ "If you want to migrate your local database to a already existing production site you can use a tool like WP Migrate DB.\n"
276
+ "WP Staging is only for creating a staging site with latest data from your production site. So it goes the opposite way of WP Migrate DB.\n"
277
+ "Both tools are excellent cooperating eachother."
278
+ msgstr ""
279
+
280
+ #. Found in description paragraph.
281
+ msgid "This is were WP Staging steps in... Site cloning and staging site creation simplified!"
282
+ msgstr ""
283
+
284
+ #. Found in description paragraph.
285
+ msgid ""
286
+ "Nope! If your local hardware and software environment is not a 100% exact clone of your production server there is NO guarantee that every aspect \n"
287
+ "of your local copy is working on your live website exactely as you would expect it. \n"
288
+ "There are some obvious things like differences in the config of php and the server you are running but even such non obvious settings like the amount of ram or the \n"
289
+ "the cpu performance can lead to unexpected results on your production website. \n"
290
+ "There are dozens of other possible cause of failure which can not be handled well when you are testing your changes on a local staging platform."
291
+ msgstr ""
292
+
293
+ #. Found in description paragraph.
294
+ msgid "<strong> I think its time to change this, so i created \"WP Staging\" for WordPress migration of staging sites</strong>"
295
+ msgstr ""
296
+
297
+ #. Found in description paragraph.
298
+ msgid ""
299
+ "Some people are also afraid of installing plugins updates because they follow the rule \"never touch a running system\" with having in mind that untested updates are increasing the risk of breaking their site.\n"
300
+ "I totally understand this and i am guilty as well here, but unfortunately this leads to one of the main reasons why WordPress installations are often outdated, not updated at all and unsecure due to this non-update behavior."
301
+ msgstr ""
302
+
303
+ #. Found in description paragraph.
304
+ msgid ""
305
+ "Testing a plugin update before installing it in live environment isn´t done very often by most user because existing staging solutions are too complex and need a lot of time to create a \n"
306
+ "up-to-date copy of your website."
307
+ msgstr ""
308
+
309
+ #. Found in description paragraph.
310
+ msgid ""
311
+ "Plugin updates and theme customizations should be tested on a staging platform first. Its recommended to have the staging platform on the same server where the production website is located.\n"
312
+ "When you run a plugin update or plan to install a new one, it is a necessary task to check first the modifications on a clone of your production website.\n"
313
+ "This makes sure that any modifications is working on your website without throwing unexpected errors or preventing your site from loading. (Better known as the wordpress blank page error)"
314
+ msgstr ""
315
+
316
+ #. Found in description paragraph.
317
+ msgid "<strong>Change your workflow of updating themes and plugins data:</strong>"
318
+ msgstr ""
319
+
320
+ #. Found in description paragraph.
321
+ msgid "WP Staging helps you to prevent your website from being broken or unavailable because of installing untested plugin updates!"
322
+ msgstr ""
323
+
324
+ #. Found in description paragraph.
325
+ msgid "<em>* Time of creation depends on size of your database and file size</em>"
326
+ msgstr ""
327
+
328
+ #. Found in description list item.
329
+ msgid "Everything running as expected? You are on the save side for migration of all these modifications to your production site!"
330
+ msgstr ""
331
+
332
+ #. Found in description list item.
333
+ msgid "Test everything on your staging site first"
334
+ msgstr ""
335
+
336
+ #. Found in description list item.
337
+ msgid "Customize theme, configuration and plugins or install new plugins"
338
+ msgstr ""
339
+
340
+ #. Found in description list item.
341
+ msgid "Use WP Staging for migration of a production website to a clone site for staging purposes"
342
+ msgstr ""
343
+
344
+ #. Found in description list item.
345
+ msgid "Wordpress migration of wordpress multisites (not tested)"
346
+ msgstr ""
347
+
348
+ #. Found in description list item.
349
+ msgid "Extensive logging if duplication or migration process should fail."
350
+ msgstr ""
351
+
352
+ #. Found in description list item.
353
+ msgid "Admin bar reflects that you are working on a staging site"
354
+ msgstr ""
355
+
356
+ #. Found in description list item.
357
+ msgid "<strong>Fast: </strong> Migration process lasts only a few seconds or minutes, depending on the site's size and server I/O power"
358
+ msgstr ""
359
+
360
+ #. Found in description list item.
361
+ msgid "<strong>Easy: </strong> Staging migration applicable for everyone. No configuration needed!"
362
+ msgstr ""
363
+
364
+ #. Found in description header.
365
+ msgid "How to install and setup?"
366
+ msgstr ""
367
+
368
+ #. Found in description header.
369
+ msgid "Important"
370
+ msgstr "Wichtig"
371
+
372
+ #. Found in description header.
373
+ msgid "I need you feedback"
374
+ msgstr ""
375
+
376
+ #. Found in description header.
377
+ msgid "What are the benefits compared to a plugin like Duplicator?"
378
+ msgstr ""
379
+
380
+ #. Found in description header.
381
+ msgid "I just want to migrate the database from one installation to another"
382
+ msgstr ""
383
+
384
+ #. Found in description header.
385
+ msgid " Can´t i just use my local wordpress development copy for testing like xampp / lampp? "
386
+ msgstr ""
387
+
388
+ #. Found in description header.
389
+ msgid " Why should i use a staging website? "
390
+ msgstr ""
391
+
392
+ #. Found in description header.
393
+ msgid "What does not work or is not tested when running wordpress migration?"
394
+ msgstr ""
395
+
396
+ #. Found in description header.
397
+ msgid "Main Features"
398
+ msgstr ""
399
+
400
+ #. Found in description header.
401
+ msgid " WP Staging for WordPress Migration "
402
+ msgstr ""
403
+
404
+ #. Screenshot description.
405
+ msgid "Finish!"
406
+ msgstr ""
407
+
408
+ #. Screenshot description.
409
+ msgid "Step 3. Wordpress Staging site creation in progress"
410
+ msgstr ""
411
+
412
+ #. Screenshot description.
413
+ msgid "Step 2. Scanning your website for files and database tables"
414
+ msgstr ""
415
+
416
+ #. Screenshot description.
417
+ msgid "Step 1. Create new WordPress staging site"
418
+ msgstr ""
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.9
12
- Stable tag: 2.3.6
13
  Requires PHP: 5.3
14
 
15
  A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
@@ -146,6 +146,18 @@ https://wp-staging.com
146
 
147
  == Changelog ==
148
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  = 2.3.6 =
150
  * Fix: Add version number to css and js files to prevent caching issues
151
  * Fix: Wrong text domain in a few language strings
@@ -182,6 +194,6 @@ Complete changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-sta
182
 
183
  == Upgrade Notice ==
184
 
185
- = 2.3.6 =
186
  * New: Compatible to WordPress 4.9.8. Important fixes!
187
 
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.9
12
+ Stable tag: 2.3.7
13
  Requires PHP: 5.3
14
 
15
  A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
146
 
147
  == Changelog ==
148
 
149
+ = 2.3.7 =
150
+ * New: Increase cloning performance
151
+ * New: Show admin notice if php version and wordpress version do not meet requirements.
152
+ * New: Show error if there is not enough free diskspace
153
+ * New: Add resume function in case the cloning process interrupts
154
+ * New: Add italian translation
155
+ * New: Better looking admin notices
156
+ * Fix: Different scheme of siteurl and home leads to non available staging site. Show admin notice to ask user to fix that first before creating a staging site
157
+ * Fix: WP Staging welcome screen shown when any plugin is activated
158
+ * Fix: Lower default settings to 10000, cpu load low. File copy limit to 50
159
+
160
+
161
  = 2.3.6 =
162
  * Fix: Add version number to css and js files to prevent caching issues
163
  * Fix: Wrong text domain in a few language strings
194
 
195
  == Upgrade Notice ==
196
 
197
+ = 2.3.7 =
198
  * New: Compatible to WordPress 4.9.8. Important fixes!
199
 
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.3.6
11
  * Text Domain: wp-staging
12
  * Domain Path: /languages/
13
 
@@ -29,63 +29,92 @@
29
  * @category Core
30
  * @author René Hermenau, Ilgıt Yıldırım
31
  */
32
-
33
  // No Direct Access
34
- if (!defined("WPINC"))
35
- {
36
- die;
 
 
 
 
37
  }
38
 
39
- // Plugin Folder Path
40
  if( !defined( 'WPSTG_PLUGIN_DIR' ) ) {
41
- define( 'WPSTG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
42
  }
43
- // Plugin Folder URL
 
44
  if( !defined( 'WPSTG_PLUGIN_URL' ) ) {
45
- define( 'WPSTG_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
46
  }
47
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
48
 
49
  /**
50
  * Fix nonce check
51
- * https://core.trac.wordpress.org/ticket/41617#ticket
52
  * @param int $seconds
53
  * @return int
54
  */
55
- function wpstg_overwrite_nonce($seconds){
56
- return 86400;
57
- }
58
- add_filter('nonce_life', 'wpstg_overwrite_nonce', 99999);
 
59
 
60
  /**
61
  * Path to main WP Staging class
62
  * Make sure to not redeclare class in case free version has been installed previosly
63
  */
64
- if (!class_exists( 'WPStaging\WPStaging' )){
65
- require_once plugin_dir_path(__FILE__) . "apps/Core/WPStaging.php";
66
  }
67
 
68
- $wpStaging = \WPStaging\WPStaging::getInstance();
69
 
70
- /**
71
- * Load a few important WP globals into WPStaging class to make them available via dependancy injection
72
- */
73
 
 
 
 
74
  // Wordpress DB Object
75
- if (isset($wpdb))
76
- {
77
- $wpStaging->set("wpdb", $wpdb);
78
- }
79
 
80
  // WordPress Filter Object
81
- if (isset($wp_filter))
82
- {
83
- $wpStaging->set("wp_filter", function() use(&$wp_filter) {
84
- return $wp_filter;
85
- });
 
 
 
 
 
86
  }
87
 
88
  /**
89
- * Inititalize WPStaging
90
  */
91
- $wpStaging->run();
 
 
7
  * Author: WP-Staging
8
  * Author URI: https://wp-staging.com
9
  * Contributors: ReneHermi, ilgityildirim
10
+ * Version: 2.3.7
11
  * Text Domain: wp-staging
12
  * Domain Path: /languages/
13
 
29
  * @category Core
30
  * @author René Hermenau, Ilgıt Yıldırım
31
  */
 
32
  // No Direct Access
33
+ if( !defined( "WPINC" ) ) {
34
+ die;
35
+ }
36
+
37
+ // Slug
38
+ if( !defined( 'WPSTG_PLUGIN_SLUG' ) ) {
39
+ define( 'WPSTG_PLUGIN_SLUG', 'wp-staging' );
40
  }
41
 
42
+ // Folder Path
43
  if( !defined( 'WPSTG_PLUGIN_DIR' ) ) {
44
+ define( 'WPSTG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
45
  }
46
+
47
+ // Folder URL
48
  if( !defined( 'WPSTG_PLUGIN_URL' ) ) {
49
+ define( 'WPSTG_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
50
  }
51
 
52
+ // Version
53
+ if( !defined( 'WPSTGPRO_VERSION' ) ) {
54
+ define( 'WPSTGPRO_VERSION', '2.3.7' );
55
+ }
56
+
57
+ /**
58
+ * Check if system fullfils all requirements
59
+ */
60
+ if( !class_exists( 'Wpstg_Requirements_Check' ) ) {
61
+ include( dirname( __FILE__ ) . '/apps/Core/Utils/requirements-check.php' );
62
+ }
63
+ $plugin_requirements = new Wpstg_Requirements_Check( array(
64
+ 'title' => 'WP STAGING',
65
+ 'php' => '5.3',
66
+ 'wp' => '3.0',
67
+ 'file' => __FILE__,
68
+ ) );
69
 
70
  /**
71
  * Fix nonce check
72
+ * Bug: https://core.trac.wordpress.org/ticket/41617#ticket
73
  * @param int $seconds
74
  * @return int
75
  */
76
+ function wpstg_overwrite_nonce( $seconds ) {
77
+ return 86400;
78
+ }
79
+
80
+ add_filter( 'nonce_life', 'wpstg_overwrite_nonce', 99999 );
81
 
82
  /**
83
  * Path to main WP Staging class
84
  * Make sure to not redeclare class in case free version has been installed previosly
85
  */
86
+ if( !class_exists( 'WPStaging\WPStaging' ) ) {
87
+ require_once plugin_dir_path( __FILE__ ) . "apps/Core/WPStaging.php";
88
  }
89
 
90
+ if( $plugin_requirements->passes() ) {
91
 
92
+ $wpStaging = \WPStaging\WPStaging::getInstance();
 
 
93
 
94
+ /**
95
+ * Load a few important WP globals into WPStaging class to make them available via dependancy injection
96
+ */
97
  // Wordpress DB Object
98
+ if( isset( $wpdb ) ) {
99
+ $wpStaging->set( "wpdb", $wpdb );
100
+ }
 
101
 
102
  // WordPress Filter Object
103
+ if( isset( $wp_filter ) ) {
104
+ $wpStaging->set( "wp_filter", function() use(&$wp_filter) {
105
+ return $wp_filter;
106
+ } );
107
+ }
108
+
109
+ /**
110
+ * Inititalize WPStaging
111
+ */
112
+ $wpStaging->run();
113
  }
114
 
115
  /**
116
+ * Installation Hooks
117
  */
118
+ if( !class_exists( 'WPStaging\Install' ) ) {
119
+ require_once plugin_dir_path( __FILE__ ) . "/install.php";
120
+ }