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

Version Description

  • Fix: Disable the WP-Spamshield Plugin on staging site because it prevents login to staging site
  • Fix: Lower the memory consumption when cloning scan process is started
  • New: Show PHP user in system info log
Download this release

Release Info

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

Code changes from version 2.5.2 to 2.5.3

apps/Backend/Administrator.php CHANGED
@@ -238,7 +238,6 @@ class Administrator extends InjectionAware {
238
public function getToolsPage() {
239
// Tabs
240
$tabs = new Tabs( array(
241
-
242
"system_info" => __( "System Info", "wp-staging" ),
243
"import_export" => __( "Import/Export", "wp-staging" )
244
) );
@@ -641,7 +640,7 @@ class Administrator extends InjectionAware {
641
) {
642
wp_send_json( true );
643
}
644
- return wp_send_json(false);
645
}
646
647
/**
@@ -785,10 +784,15 @@ class Administrator extends InjectionAware {
785
786
787
// Can not connect to database
788
- $sql = "SHOW DATABASES LIKE '{$database}';";
789
- $results = $db->query( $sql );
790
- if( empty( $results ) ) {
791
- echo json_encode( array('errors' => " Database {$database} does not exist. You need to create it first. ") );
792
exit;
793
}
794
echo json_encode( array('success' => 'true') );
238
public function getToolsPage() {
239
// Tabs
240
$tabs = new Tabs( array(
241
"system_info" => __( "System Info", "wp-staging" ),
242
"import_export" => __( "Import/Export", "wp-staging" )
243
) );
640
) {
641
wp_send_json( true );
642
}
643
+ return wp_send_json( false );
644
}
645
646
/**
784
785
786
// Can not connect to database
787
+ // $sql = "SHOW DATABASES LIKE '{$database}';";
788
+ // $results = $db->query( $sql );
789
+ // if( empty( $results ) ) {
790
+ // echo json_encode( array('errors' => " Database {$database} does not exist. You need to create it first. ") );
791
+ // exit;
792
+ // }
793
+ $db->select( $database );
794
+ if( !$db->ready ) {
795
+ echo json_encode( array('errors' => "Error: Can't select {$database} [" . print_r( $db->error, true ) . "] Either it does not exist or you don't have privileges to access it. ") );
796
exit;
797
}
798
echo json_encode( array('success' => 'true') );
apps/Backend/Modules/Jobs/Cloning.php CHANGED
@@ -96,6 +96,7 @@ class Cloning extends Job {
96
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
97
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
98
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
99
);
100
101
$this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
@@ -271,7 +272,7 @@ class Cloning extends Job {
271
$sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
272
$tables = $this->db->get_results( $sql );
273
274
- // Prefix does not exists. We can use it
275
if( !$tables ) {
276
return $this->options->prefix;
277
}
96
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login',
97
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-super-cache',
98
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'peters-login-redirect',
99
+ \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wp-spamshield',
100
);
101
102
$this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
272
$sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
273
$tables = $this->db->get_results( $sql );
274
275
+ // Prefix does not exist. We can use it
276
if( !$tables ) {
277
return $this->options->prefix;
278
}
apps/Backend/Modules/Jobs/Data.php CHANGED
@@ -176,7 +176,7 @@ class Data extends JobExecutable {
176
*/
177
protected function isTable( $table ) {
178
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
179
- $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
180
return false;
181
}
182
return true;
176
*/
177
protected function isTable( $table ) {
178
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
179
+ $this->log( "Table {$table} does not exist", Logger::TYPE_ERROR );
180
return false;
181
}
182
return true;
apps/Backend/Modules/Jobs/Files.php CHANGED
@@ -224,6 +224,9 @@ class Files extends JobExecutable {
224
return $this->copyBig( $file, $destination, $this->settings->batchSize );
225
}
226
227
// Attempt to copy
228
if( !@copy( $file, $destination ) ) {
229
$errors = error_get_last();
@@ -250,10 +253,10 @@ class Files extends JobExecutable {
250
$uploads = wp_upload_dir();
251
252
// Get absolute upload dir from ABSPATH
253
- $uploadsAbsPath = trailingslashit($uploads['basedir']);
254
255
// Get absolute custom wp-content dir
256
- $wpContentDir = trailingslashit(WP_CONTENT_DIR);
257
258
// Check if there is a custom upload directory and do a search $ replace
259
$file = str_replace( $uploadsAbsPath, ABSPATH . 'wp-content/uploads/', $file, $count );
@@ -401,13 +404,10 @@ class Files extends JobExecutable {
401
if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
402
return false;
403
}
404
- // $directory = wpstg_replace_windows_directory_separator( $directory );
405
- // $directory = trailingslashit( $directory );
406
$directory = trailingslashit( $this->sanitizeDirectorySeparator( $directory ) );
407
408
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
409
- // $excludedDirectory = wpstg_replace_windows_directory_separator( $excludedDirectory );
410
- // $excludedDirectory = trailingslashit( $excludedDirectory );
411
$excludedDirectory = trailingslashit( $this->sanitizeDirectorySeparator( $excludedDirectory ) );
412
if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
413
return true;
224
return $this->copyBig( $file, $destination, $this->settings->batchSize );
225
}
226
227
+ $this->debugLog( "Try to copy: {$file} to {$destination}", Logger::TYPE_INFO );
228
+
229
+
230
// Attempt to copy
231
if( !@copy( $file, $destination ) ) {
232
$errors = error_get_last();
253
$uploads = wp_upload_dir();
254
255
// Get absolute upload dir from ABSPATH
256
+ $uploadsAbsPath = trailingslashit( $uploads['basedir'] );
257
258
// Get absolute custom wp-content dir
259
+ $wpContentDir = trailingslashit( WP_CONTENT_DIR );
260
261
// Check if there is a custom upload directory and do a search $ replace
262
$file = str_replace( $uploadsAbsPath, ABSPATH . 'wp-content/uploads/', $file, $count );
404
if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
405
return false;
406
}
407
+
408
$directory = trailingslashit( $this->sanitizeDirectorySeparator( $directory ) );
409
410
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
411
$excludedDirectory = trailingslashit( $this->sanitizeDirectorySeparator( $excludedDirectory ) );
412
if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
413
return true;
apps/Backend/Modules/Jobs/Multisite/Data.php CHANGED
@@ -171,7 +171,7 @@ class Data extends JobExecutable {
171
*/
172
protected function isTable( $table ) {
173
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
174
- $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
175
return false;
176
}
177
return true;
171
*/
172
protected function isTable( $table ) {
173
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
174
+ $this->log( "Table {$table} does not exist", Logger::TYPE_ERROR );
175
return false;
176
}
177
return true;
apps/Backend/Modules/Jobs/Multisite/DataExternal.php CHANGED
@@ -178,7 +178,7 @@ class DataExternal extends JobExecutable {
178
*/
179
protected function isTable( $table ) {
180
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
181
- $this->log( "Table {$table} does not exists", Logger::TYPE_ERROR );
182
return false;
183
}
184
return true;
178
*/
179
protected function isTable( $table ) {
180
if( $this->db->get_var( "SHOW TABLES LIKE '{$table}'" ) != $table ) {
181
+ $this->log( "Table {$table} does not exist", Logger::TYPE_ERROR );
182
return false;
183
}
184
return true;
apps/Backend/Modules/Jobs/Multisite/Database.php CHANGED
@@ -284,7 +284,7 @@ class Database extends JobExecutable {
284
return true;
285
}
286
287
- // Table does not exists
288
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
289
if( !$result || 0 === $result ) {
290
return true;
284
return true;
285
}
286
287
+ // Table does not exist
288
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
289
if( !$result || 0 === $result ) {
290
return true;
apps/Backend/Modules/Jobs/Multisite/DatabaseExternal.php CHANGED
@@ -310,7 +310,7 @@ class DatabaseExternal extends JobExecutable {
310
return true;
311
}
312
313
- // Table does not exists
314
$table = str_replace( $this->db->dbname . '.', null, $old );
315
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
316
if( !$result || 0 === $result ) {
310
return true;
311
}
312
313
+ // Table does not exist
314
$table = str_replace( $this->db->dbname . '.', null, $old );
315
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
316
if( !$result || 0 === $result ) {
apps/Backend/Modules/Jobs/Multisite/SearchReplace.php CHANGED
@@ -240,7 +240,7 @@ class SearchReplace extends JobExecutable {
240
*/
241
private function get_pages_in_table( $table ) {
242
243
- // Table does not exists
244
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
245
if( !$result || 0 === $result ) {
246
return 0;
@@ -699,7 +699,7 @@ class SearchReplace extends JobExecutable {
699
return true;
700
}
701
702
- // Table does not exists
703
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
704
if( !$result || 0 === $result ) {
705
return false;
240
*/
241
private function get_pages_in_table( $table ) {
242
243
+ // Table does not exist
244
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
245
if( !$result || 0 === $result ) {
246
return 0;
699
return true;
700
}
701
702
+ // Table does not exist
703
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
704
if( !$result || 0 === $result ) {
705
return false;
apps/Backend/Modules/Jobs/Multisite/SearchReplaceExternal.php CHANGED
@@ -248,7 +248,7 @@ class SearchReplaceExternal extends JobExecutable {
248
*/
249
private function get_pages_in_table( $table ) {
250
251
- // Table does not exists
252
$table = str_replace( $this->options->prefix . '.', null, $table );
253
$result = $this->productionDb->query( "SHOW TABLES LIKE '{$table}'" );
254
if( !$result || 0 === $result ) {
@@ -706,7 +706,7 @@ class SearchReplaceExternal extends JobExecutable {
706
return false;
707
}
708
709
- // Table does not exists
710
$result = $this->productionDb->query( "SHOW TABLES LIKE '{$old}'" );
711
if( !$result || 0 === $result ) {
712
return false;
248
*/
249
private function get_pages_in_table( $table ) {
250
251
+ // Table does not exist
252
$table = str_replace( $this->options->prefix . '.', null, $table );
253
$result = $this->productionDb->query( "SHOW TABLES LIKE '{$table}'" );
254
if( !$result || 0 === $result ) {
706
return false;
707
}
708
709
+ // Table does not exist
710
$result = $this->productionDb->query( "SHOW TABLES LIKE '{$old}'" );
711
if( !$result || 0 === $result ) {
712
return false;
apps/Backend/Modules/Jobs/Scan.php CHANGED
@@ -4,12 +4,13 @@ namespace WPStaging\Backend\Modules\Jobs;
4
5
// No Direct Access
6
if( !defined( "WPINC" ) ) {
7
- die;
8
}
9
10
use WPStaging\WPStaging;
11
use WPStaging\Utils\Directories;
12
use WPStaging\Backend\Optimizer\Optimizer;
13
14
/**
15
* Class Scan
@@ -17,409 +18,412 @@ use WPStaging\Backend\Optimizer\Optimizer;
17
*/
18
class Scan extends Job {
19
20
- /**
21
- * @var array
22
- */
23
- private $directories = array();
24
-
25
- /**
26
- * @var Directories
27
- */
28
- private $objDirectories;
29
-
30
- /**
31
- * Upon class initialization
32
- */
33
- protected function initialize() {
34
- $this->objDirectories = new Directories();
35
-
36
- // Database Tables
37
- $this->getTables();
38
-
39
- // Get directories
40
- $this->directories();
41
-
42
- // Install Optimizer
43
- $this->installOptimizer();
44
-
45
-
46
- $this->db = WPStaging::getInstance()->get( 'wpdb' );
47
- $this->prefix = $this->db->prefix;
48
- }
49
-
50
- /**
51
- * Start Module
52
- * @return $this
53
- */
54
- public function start() {
55
- // Basic Options
56
- $this->options->root = str_replace( array("\\", '/'), DIRECTORY_SEPARATOR, \WPStaging\WPStaging::getWPpath() );
57
- $this->options->existingClones = get_option( "wpstg_existing_clones_beta", array() );
58
- $this->options->current = null;
59
-
60
- if( isset( $_POST["clone"] ) && array_key_exists( $_POST["clone"], $this->options->existingClones ) ) {
61
- $this->options->current = $_POST["clone"];
62
- }
63
-
64
- // Tables
65
- //$this->options->excludedTables = array();
66
- $this->options->clonedTables = array();
67
-
68
- // Files
69
- $this->options->totalFiles = 0;
70
- $this->options->totalFileSize = 0;
71
- $this->options->copiedFiles = 0;
72
-
73
-
74
- // Directories
75
- $this->options->includedDirectories = array();
76
- $this->options->includedExtraDirectories = array();
77
- $this->options->excludedDirectories = array();
78
- $this->options->extraDirectories = array();
79
- $this->options->directoriesToCopy = array();
80
- $this->options->scannedDirectories = array();
81
-
82
- // Job
83
- $this->options->currentJob = "database";
84
- //$this->options->currentJob = "directories";
85
- $this->options->currentStep = 0;
86
- $this->options->totalSteps = 0;
87
-
88
- // Define mainJob to differentiate between cloning, updating and pushing
89
- $this->options->mainJob = 'cloning';
90
-
91
- // Delete previous cached files
92
- $this->cache->delete( "files_to_copy" );
93
- $this->cache->delete( "clone_options" );
94
-
95
- // Save options
96
- $this->saveOptions();
97
-
98
- return $this;
99
- }
100
-
101
- /**
102
- * Make sure the Optimizer mu plugin is installed before cloning or pushing
103
- */
104
- private function installOptimizer(){
105
- $optimizer = new Optimizer();
106
- $optimizer->installOptimizer();
107
- }
108
-
109
- /**
110
- * Format bytes into human readable form
111
- * @param int $bytes
112
- * @param int $precision
113
- * @return string
114
- */
115
- public function formatSize( $bytes, $precision = 2 ) {
116
- if( ( double ) $bytes < 1 ) {
117
- return '';
118
- }
119
-
120
- $units = array('B', "KB", "MB", "GB", "TB");
121
-
122
- $bytes = ( double ) $bytes;
123
- $base = log( $bytes ) / log( 1000 ); // 1024 would be for MiB KiB etc
124
- $pow = pow( 1000, $base - floor( $base ) ); // Same rule for 1000
125
-
126
- return round( $pow, $precision ) . ' ' . $units[( int ) floor( $base )];
127
- }
128
-
129
- /**
130
- * @param null|string $directories
131
- * @param bool $forceDisabled
132
- * @return string
133
- */
134
- public function directoryListing( $directories = null, $forceDisabled = false ) {
135
- if( null == $directories ) {
136
- $directories = $this->directories;
137
- }
138
-
139
- // Sort results
140
- uksort( $directories, 'strcasecmp' );
141
-
142
- $output = '';
143
- foreach ( $directories as $name => $directory ) {
144
- // Not a directory, possibly a symlink, therefore we will skip it
145
- if( !is_array( $directory ) ) {
146
- continue;
147
- }
148
-
149
- // Need to preserve keys so no array_shift()
150
- $data = reset( $directory );
151
- unset( $directory[key( $directory )] );
152
-
153
-
154
- $isChecked = (
155
- empty( $this->options->includedDirectories ) ||
156
- in_array( $data["path"], $this->options->includedDirectories )
157
- );
158
-
159
-
160
- // Include wp core folders and their sub dirs.
161
- // Exclude all other folders (default setting)
162
- $dataPath = isset( $data["path"] ) ? $data["path"] : '';
163
- $dataSize = isset( $data["size"] ) ? $data["size"] : '';
164
- $isDisabled = ($name !== 'wp-admin' &&
165
- $name !== 'wp-includes' &&
166
- $name !== 'wp-content') &&
167
- false === strpos( strrev( $dataPath ), strrev( "wp-admin" ) ) &&
168
- false === strpos( strrev( $dataPath ), strrev( "wp-includes" ) ) &&
169
- false === strpos( strrev( $dataPath ), strrev( "wp-content" ) ) ? true : false;
170
-
171
- // Extra class to differentiate between wp core and non core folders
172
- $class = !$isDisabled ? 'wpstg-root' : 'wpstg-extra';
173
-
174
- $output .= "<div class='wpstg-dir'>";
175
- $output .= "<input type='checkbox' class='wpstg-check-dir " . $class . "'";
176
-
177
- if( $isChecked && !$isDisabled && !$forceDisabled )
178
- $output .= " checked";
179
- //if ($forceDisabled || $isDisabled) $output .= " disabled";
180
-
181
- $output .= " name='selectedDirectories[]' value='{$dataPath}'>";
182
-
183
- $output .= "<a href='#' class='wpstg-expand-dirs ";
184
- if( !$isChecked || $isDisabled ) {
185
- $output .= " disabled";
186
- }
187
- $output .= "'>{$name}";
188
- $output .= "</a>";
189
- $output .= "<span class='wpstg-size-info'>{$this->formatSize( $dataSize )}</span>";
190
-
191
- if( !empty( $directory ) ) {
192
- $output .= "<div class='wpstg-dir wpstg-subdir'>";
193
- $output .= $this->directoryListing( $directory, $isDisabled );
194
- $output .= "</div>";
195
- }
196
-
197
- $output .= "</div>";
198
- }
199
-
200
- return $output;
201
- }
202
-
203
- /**
204
- * Checks if there is enough free disk space to create staging site
205
- * Returns null when can't run disk_free_space function one way or another
206
- * @return bool|null
207
- */
208
- public function hasFreeDiskSpace() {
209
- if( !function_exists( "disk_free_space" ) ) {
210
- return null;
211
- }
212
-
213
- $freeSpace = @disk_free_space( \WPStaging\WPStaging::getWPpath() );
214
-
215
- if( false === $freeSpace ) {
216
- $data = array(
217
- 'freespace' => false,
218
- 'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( \WPStaging\WPStaging::getWPpath() ) )
219
- );
220
- echo json_encode( $data );
221
- die();
222
- }
223
-
224
-
225
- $data = array(
226
- 'freespace' => $this->formatSize( $freeSpace ),
227
- 'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( \WPStaging\WPStaging::getWPpath() ) )
228
- );
229
230
- echo json_encode( $data );
231
- die();
232
- }
233
-
234
- /**
235
- * Get Database Tables
236
- */
237
- protected function getTables() {
238
- $wpDB = WPStaging::getInstance()->get( "wpdb" );
239
-
240
- if( strlen( $wpDB->prefix ) > 0 ) {
241
- //$prefix = str_replace('_', '', $wpDB->prefix);
242
- $sql = "SHOW TABLE STATUS LIKE '{$wpDB->prefix}%'";
243
- } else {
244
- $sql = "SHOW TABLE STATUS";
245
- }
246
-
247
-
248
- $tables = $wpDB->get_results( $sql );
249
-
250
- $currentTables = array();
251
-
252
- // Reset excluded Tables than loop through all tables
253
- $this->options->excludedTables = array();
254
- foreach ( $tables as $table ) {
255
-
256
- // Exclude WP Staging Tables
257
// if (0 === strpos($table->Name, "wp-staging"))
258
// {
259
// continue;
260
// }
261
- // Create array of unchecked tables
262
- if( !empty( $wpDB->prefix ) && 0 !== strpos( $table->Name, $wpDB->prefix ) ) {
263
- $this->options->excludedTables[] = $table->Name;
264
- }
265
-
266
-
267
- $currentTables[] = array(
268
- "name" => $table->Name,
269
- "size" => ($table->Data_length + $table->Index_length)
270
- );
271
- }
272
-
273
- $this->options->tables = json_decode( json_encode( $currentTables ) );
274
- }
275
-
276
- /**
277
- * Get directories and main meta data about'em recursively
278
- */
279
- protected function directories() {
280
- $directories = new \DirectoryIterator( \WPStaging\WPStaging::getWPpath() );
281
-
282
- foreach ( $directories as $directory ) {
283
- // Not a valid directory
284
- if( false === ($path = $this->getPath( $directory )) ) {
285
- continue;
286
- }
287
-
288
- $this->handleDirectory( $path );
289
-
290
- // Get Sub-directories
291
- $this->getSubDirectories( $directory->getRealPath() );
292
- }
293
-
294
- // Gather Plugins
295
- $this->getSubDirectories( WP_PLUGIN_DIR );
296
-
297
- // Gather Themes
298
- $this->getSubDirectories( WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "themes" );
299
-
300
- // Gather Default Uploads Folder
301
- //$this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "uploads");
302
- // Gather Custom Uploads Folder if there is one
303
- $this->getSubDirectories( $this->getUploadDir() );
304
- }
305
-
306
- /**
307
- * @param string $path
308
- */
309
- protected function getSubDirectories( $path ) {
310
-
311
- if( !is_readable( $path ) ) {
312
- return false;
313
- }
314
-
315
- $directories = new \DirectoryIterator( $path );
316
-
317
- foreach ( $directories as $directory ) {
318
- // Not a valid directory
319
- if( false === ($path = $this->getPath( $directory )) ) {
320
- continue;
321
- }
322
-
323
- $this->handleDirectory( $path );
324
- }
325
- }
326
-
327
- /**
328
- * Get Path from $directory
329
- * @param \SplFileInfo $directory
330
- * @return string|false
331
- */
332
- protected function getPath( $directory ) {
333
-
334
- /*
335
- * Do not follow root path like src/web/..
336
- * This must be done before \SplFileInfo->isDir() is used!
337
- * Prevents open base dir restriction fatal errors
338
- */
339
-
340
- if( strpos( $directory->getRealPath(), \WPStaging\WPStaging::getWPpath() ) !== 0 ) {
341
- return false;
342
- }
343
- $path = str_replace( \WPStaging\WPStaging::getWPpath(), null, $directory->getRealPath() );
344
-
345
- // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
346
- if( !$directory->isDir() || strlen( $path ) < 1 ) {
347
- return false;
348
- }
349
-
350
- return $path;
351
- }
352
-
353
- /**
354
- * Organizes $this->directories
355
- * @param string $path
356
- */
357
- protected function handleDirectory( $path ) {
358
- $directoryArray = explode( DIRECTORY_SEPARATOR, $path );
359
- $total = is_array( $directoryArray ) || $directoryArray instanceof Countable ? count( $directoryArray ) : 0;
360
-
361
- if( $total < 1 ) {
362
- return;
363
- }
364
-
365
- $total = $total - 1;
366
- $currentArray = &$this->directories;
367
-
368
- for ( $i = 0; $i <= $total; $i++ ) {
369
- if( !isset( $currentArray[$directoryArray[$i]] ) ) {
370
- $currentArray[$directoryArray[$i]] = array();
371
- }
372
-
373
- $currentArray = &$currentArray[$directoryArray[$i]];
374
-
375
- // Attach meta data to the end
376
- if( $i < $total ) {
377
- continue;
378
- }
379
-
380
- $fullPath = \WPStaging\WPStaging::getWPpath() . $path;
381
- $size = $this->getDirectorySize( $fullPath );
382
-
383
- $currentArray["metaData"] = array(
384
- "size" => $size,
385
- "path" => \WPStaging\WPStaging::getWPpath() . $path,
386
- );
387
- }
388
- }
389
-
390
- /**
391
- * Gets size of given directory
392
- * @param string $path
393
- * @return int|null
394
- */
395
- protected function getDirectorySize( $path ) {
396
- if( !isset( $this->settings->checkDirectorySize ) || '1' !== $this->settings->checkDirectorySize ) {
397
- return null;
398
- }
399
-
400
- return $this->objDirectories->size( $path );
401
- }
402
-
403
- /**
404
- * Get total size of a directory including all its subdirectories
405
- * @param string $dir
406
- * @return int
407
- */
408
- function getDirectorySizeInclSubdirs( $dir ) {
409
- $size = 0;
410
- foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
411
- $size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
412
- }
413
- return $size;
414
- }
415
-
416
- /**
417
- * Get relative WP uploads path
418
- * @return string
419
- */
420
- protected function getUploadDir() {
421
- $uploads = wp_upload_dir();
422
- return $uploads['basedir'];
423
- }
424
425
}
4
5
// No Direct Access
6
if( !defined( "WPINC" ) ) {
7
+ die;
8
}
9
10
use WPStaging\WPStaging;
11
use WPStaging\Utils\Directories;
12
use WPStaging\Backend\Optimizer\Optimizer;
13
+ use WPStaging\Iterators;
14
15
/**
16
* Class Scan
18
*/
19
class Scan extends Job {
20
21
+ /**
22
+ * @var array
23
+ */
24
+ private $directories = array();
25
+
26
+ /**
27
+ * @var Directories
28
+ */
29
+ private $objDirectories;
30
+
31
+ /**
32
+ * Upon class initialization
33
+ */
34
+ protected function initialize() {
35
+ $this->objDirectories = new Directories();
36
+
37
+ // Database Tables
38
+ $this->getTables();
39
+
40
+ // Get directories
41
+ $this->getDirectories();
42
+
43
+ // Install Optimizer
44
+ $this->installOptimizer();
45
+
46
+
47
+ $this->db = WPStaging::getInstance()->get( 'wpdb' );
48
+ $this->prefix = $this->db->prefix;
49
+ }
50
+
51
+ /**
52
+ * Start Module
53
+ * @return $this
54
+ */
55
+ public function start() {
56
+ // Basic Options
57
+ $this->options->root = str_replace( array("\\", '/'), DIRECTORY_SEPARATOR, \WPStaging\WPStaging::getWPpath() );
58
+ $this->options->existingClones = get_option( "wpstg_existing_clones_beta", array() );
59
+ $this->options->current = null;
60
+
61
+ if( isset( $_POST["clone"] ) && array_key_exists( $_POST["clone"], $this->options->existingClones ) ) {
62
+ $this->options->current = $_POST["clone"];
63
+ }
64
+
65
+ // Tables
66
+ //$this->options->excludedTables = array();
67
+ $this->options->clonedTables = array();
68
+
69
+ // Files
70
+ $this->options->totalFiles = 0;
71
+ $this->options->totalFileSize = 0;
72
+ $this->options->copiedFiles = 0;
73
+
74
+
75
+ // Directories
76
+ $this->options->includedDirectories = array();
77
+ $this->options->includedExtraDirectories = array();
78
+ $this->options->excludedDirectories = array();
79
+ $this->options->extraDirectories = array();
80
+ $this->options->directoriesToCopy = array();
81
+ $this->options->scannedDirectories = array();
82
+
83
+ // Job
84
+ $this->options->currentJob = "database";
85
+ //$this->options->currentJob = "directories";
86
+ $this->options->currentStep = 0;
87
+ $this->options->totalSteps = 0;
88
+
89
+ // Define mainJob to differentiate between cloning, updating and pushing
90
+ $this->options->mainJob = 'cloning';
91
+
92
+ // Delete previous cached files
93
+ $this->cache->delete( "files_to_copy" );
94
+ $this->cache->delete( "clone_options" );
95
+
96
+ // Save options
97
+ $this->saveOptions();
98
+
99
+ return $this;
100
+ }
101
+
102
+ /**
103
+ * Make sure the Optimizer mu plugin is installed before cloning or pushing
104
+ */
105
+ private function installOptimizer() {
106
+ $optimizer = new Optimizer();
107
+ $optimizer->installOptimizer();
108
+ }
109
+
110
+ /**
111
+ * Format bytes into human readable form
112
+ * @param int $bytes
113
+ * @param int $precision
114
+ * @return string
115
+ */
116
+ public function formatSize( $bytes, $precision = 2 ) {
117
+ if( ( double ) $bytes < 1 ) {
118
+ return '';
119
+ }
120
+
121
+ $units = array('B', "KB", "MB", "GB", "TB");
122
+
123
+ $bytes = ( double ) $bytes;
124
+ $base = log( $bytes ) / log( 1000 ); // 1024 would be for MiB KiB etc
125
+ $pow = pow( 1000, $base - floor( $base ) ); // Same rule for 1000
126
+
127
+ return round( $pow, $precision ) . ' ' . $units[( int ) floor( $base )];
128
+ }
129
+
130
+ /**
131
+ * @param null|string $directories
132
+ * @param bool $forceDisabled
133
+ * @return string
134
+ */
135
+ public function directoryListing( $directories = null, $forceDisabled = false ) {
136
+ if( null == $directories ) {
137
+ $directories = $this->directories;
138
+ }
139
+
140
+ // Sort results
141
+ uksort( $directories, 'strcasecmp' );
142
+
143
+ $output = '';
144
+ foreach ( $directories as $name => $directory ) {
145
+ // Not a directory, possibly a symlink, therefore we will skip it
146
+ if( !is_array( $directory ) ) {
147
+ continue;
148
+ }
149
+
150
+ // Need to preserve keys so no array_shift()
151
+ $data = reset( $directory );
152
+ unset( $directory[key( $directory )] );
153
+
154
+
155
+ $isChecked = (
156
+ empty( $this->options->includedDirectories ) ||
157
+ in_array( $data["path"], $this->options->includedDirectories )
158
+ );
159
+
160
+
161
+ // Include wp core folders and their sub dirs.
162
+ // Exclude all other folders (default setting)
163
+ $dataPath = isset( $data["path"] ) ? $data["path"] : '';
164
+ $dataSize = isset( $data["size"] ) ? $data["size"] : '';
165
+ $isDisabled = ($name !== 'wp-admin' &&
166
+ $name !== 'wp-includes' &&
167
+ $name !== 'wp-content') &&
168
+ false === strpos( strrev( $dataPath ), strrev( "wp-admin" ) ) &&
169
+ false === strpos( strrev( $dataPath ), strrev( "wp-includes" ) ) &&
170
+ false === strpos( strrev( $dataPath ), strrev( "wp-content" ) ) ? true : false;
171
+
172
+ // Extra class to differentiate between wp core and non core folders
173
+ $class = !$isDisabled ? 'wpstg-root' : 'wpstg-extra';
174
+
175
+ $output .= "<div class='wpstg-dir'>";
176
+ $output .= "<input type='checkbox' class='wpstg-check-dir " . $class . "'";
177
+
178
+ if( $isChecked && !$isDisabled && !$forceDisabled )
179
+ $output .= " checked";
180
+ //if ($forceDisabled || $isDisabled) $output .= " disabled";
181
+
182
+ $output .= " name='selectedDirectories[]' value='{$dataPath}'>";
183
+
184
+ $output .= "<a href='#' class='wpstg-expand-dirs ";
185
+ if( !$isChecked || $isDisabled ) {
186
+ $output .= " disabled";
187
+ }
188
+ $output .= "'>{$name}";
189
+ $output .= "</a>";
190
+ $output .= "<span class='wpstg-size-info'>{$this->formatSize( $dataSize )}</span>";
191
+
192
+ if( !empty( $directory ) ) {
193
+ $output .= "<div class='wpstg-dir wpstg-subdir'>";
194
+ $output .= $this->directoryListing( $directory, $isDisabled );
195
+ $output .= "</div>";
196
+ }
197
198
+ $output .= "</div>";
199
+ }
200
+
201
+ return $output;
202
+ }
203
+
204
+ /**
205
+ * Checks if there is enough free disk space to create staging site
206
+ * Returns null when can't run disk_free_space function one way or another
207
+ * @return bool|null
208
+ */
209
+ public function hasFreeDiskSpace() {
210
+ if( !function_exists( "disk_free_space" ) ) {
211
+ return null;
212
+ }
213
+
214
+ $freeSpace = @disk_free_space( \WPStaging\WPStaging::getWPpath() );
215
+
216
+ if( false === $freeSpace ) {
217
+ $data = array(
218
+ 'freespace' => false,
219
+ 'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( \WPStaging\WPStaging::getWPpath() ) )
220
+ );
221
+ echo json_encode( $data );
222
+ die();
223
+ }
224
+
225
+
226
+ $data = array(
227
+ 'freespace' => $this->formatSize( $freeSpace ),
228
+ 'usedspace' => $this->formatSize( $this->getDirectorySizeInclSubdirs( \WPStaging\WPStaging::getWPpath() ) )
229
+ );
230
+
231
+ echo json_encode( $data );
232
+ die();
233
+ }
234
+
235
+ /**
236
+ * Get Database Tables
237
+ */
238
+ protected function getTables() {
239
+ $wpDB = WPStaging::getInstance()->get( "wpdb" );
240
+
241
+ if( strlen( $wpDB->prefix ) > 0 ) {
242
+ //$prefix = str_replace('_', '', $wpDB->prefix);
243
+ $sql = "SHOW TABLE STATUS LIKE '{$wpDB->prefix}%'";
244
+ } else {
245
+ $sql = "SHOW TABLE STATUS";
246
+ }
247
+
248
+ $tables = $wpDB->get_results( $sql );
249
+
250
+ $currentTables = array();
251
+
252
+ // Reset excluded Tables than loop through all tables
253
+ $this->options->excludedTables = array();
254
+ foreach ( $tables as $table ) {
255
+
256
+ // Exclude WP Staging Tables
257
// if (0 === strpos($table->Name, "wp-staging"))
258
// {
259
// continue;
260
// }
261
+ // Create array of unchecked tables
262
+ if( !empty( $wpDB->prefix ) && 0 !== strpos( $table->Name, $wpDB->prefix ) ) {
263
+ $this->options->excludedTables[] = $table->Name;
264
+ }
265
+
266
+
267
+ $currentTables[] = array(
268
+ "name" => $table->Name,
269
+ "size" => ($table->Data_length + $table->Index_length)
270
+ );
271
+ }
272
+
273
+ $this->options->tables = json_decode( json_encode( $currentTables ) );
274
+ }
275
+
276
+ /**
277
+ * Get directories and main meta data about'em recursively
278
+ */
279
+ protected function getDirectories() {
280
+
281
+
282
+ //$directories = new \DirectoryIterator( \WPStaging\WPStaging::getWPpath() );
283
+ $directories = new Iterators\RecursiveDirectoryIterator( \WPStaging\WPStaging::getWPpath() );
284
+
285
+
286
+ foreach ( $directories as $directory ) {
287
+ // Not a valid directory
288
+ if( false === ($path = $this->getPath( $directory )) ) {
289
+ continue;
290
+ }
291
+
292
+ $this->handleDirectory( $path );
293
+
294
+ // Get Sub-directories
295
+ $this->getSubDirectories( $directory->getRealPath() );
296
+ }
297
+
298
+ // Gather Plugins
299
+ $this->getSubDirectories( WP_PLUGIN_DIR );
300
+
301
+ // Gather Themes
302
+ $this->getSubDirectories( WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "themes" );
303
+
304
+ // Gather Default Uploads Folder
305
+ //$this->getSubDirectories(WP_CONTENT_DIR . DIRECTORY_SEPARATOR . "uploads");
306
+ // Gather Custom Uploads Folder if there is one
307
+ $this->getSubDirectories( $this->getUploadDir() );
308
+ }
309
+
310
+ /**
311
+ * @param string $path
312
+ */
313
+ protected function getSubDirectories( $path ) {
314
+
315
+ if( !is_readable( $path ) ) {
316
+ return false;
317
+ }
318
+
319
+ $directories = new \DirectoryIterator( $path );
320
+
321
+ foreach ( $directories as $directory ) {
322
+ // Not a valid directory
323
+ if( false === ($path = $this->getPath( $directory )) ) {
324
+ continue;
325
+ }
326
+
327
+ $this->handleDirectory( $path );
328
+ }
329
+ }
330
+
331
+ /**
332
+ * Get Path from $directory
333
+ * @param \SplFileInfo $directory
334
+ * @return string|false
335
+ */
336
+ protected function getPath( $directory ) {
337
+
338
+ /*
339
+ * Do not follow root path like src/web/..
340
+ * This must be done before \SplFileInfo->isDir() is used!
341
+ * Prevents open base dir restriction fatal errors
342
+ */
343
+
344
+ if( strpos( $directory->getRealPath(), \WPStaging\WPStaging::getWPpath() ) !== 0 ) {
345
+ return false;
346
+ }
347
+ $path = str_replace( \WPStaging\WPStaging::getWPpath(), null, $directory->getRealPath() );
348
+
349
+ // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
350
+ if( !$directory->isDir() || strlen( $path ) < 1 ) {
351
+ return false;
352
+ }
353
+
354
+ return $path;
355
+ }
356
+
357
+ /**
358
+ * Organizes $this->directories
359
+ * @param string $path
360
+ */
361
+ protected function handleDirectory( $path ) {
362
+ $directoryArray = explode( DIRECTORY_SEPARATOR, $path );
363
+ $total = is_array( $directoryArray ) || $directoryArray instanceof Countable ? count( $directoryArray ) : 0;
364
+
365
+ if( $total < 1 ) {
366
+ return;
367
+ }
368
+
369
+ $total = $total - 1;
370
+ $currentArray = &$this->directories;
371
+
372
+ for ( $i = 0; $i <= $total; $i++ ) {
373
+ if( !isset( $currentArray[$directoryArray[$i]] ) ) {
374
+ $currentArray[$directoryArray[$i]] = array();
375
+ }
376
+
377
+ $currentArray = &$currentArray[$directoryArray[$i]];
378
+
379
+ // Attach meta data to the end
380
+ if( $i < $total ) {
381
+ continue;
382
+ }
383
+
384
+ $fullPath = \WPStaging\WPStaging::getWPpath() . $path;
385
+ $size = $this->getDirectorySize( $fullPath );
386
+
387
+ $currentArray["metaData"] = array(
388
+ "size" => $size,
389
+ "path" => \WPStaging\WPStaging::getWPpath() . $path,
390
+ );
391
+ }
392
+ }
393
+
394
+ /**
395
+ * Gets size of given directory
396
+ * @param string $path
397
+ * @return int|null
398
+ */
399
+ protected function getDirectorySize( $path ) {
400
+ if( !isset( $this->settings->checkDirectorySize ) || '1' !== $this->settings->checkDirectorySize ) {
401
+ return null;
402
+ }
403
+
404
+ return $this->objDirectories->size( $path );
405
+ }
406
+
407
+ /**
408
+ * Get total size of a directory including all its subdirectories
409
+ * @param string $dir
410
+ * @return int
411
+ */
412
+ function getDirectorySizeInclSubdirs( $dir ) {
413
+ $size = 0;
414
+ foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
415
+ $size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
416
+ }
417
+ return $size;
418
+ }
419
+
420
+ /**
421
+ * Get absolute WP uploads path e.g. /var/www/htdocs/example.com/wp-content/uploads/sites/1
422
+ * @return string
423
+ */
424
+ protected function getUploadDir() {
425
+ $uploads = wp_upload_dir();
426
+ return $uploads['basedir'];
427
+ }
428
429
}
apps/Backend/Modules/Jobs/SearchReplace.php CHANGED
@@ -237,7 +237,7 @@ class SearchReplace extends JobExecutable {
237
*/
238
private function get_pages_in_table( $table ) {
239
240
- // Table does not exists
241
$table = str_replace( $this->options->prefix . '.', null, $table );
242
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
243
if( !$result || 0 === $result ) {
@@ -664,7 +664,7 @@ class SearchReplace extends JobExecutable {
664
return false;
665
}
666
667
- // Table does not exists
668
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
669
if( !$result || 0 === $result ) {
670
return false;
237
*/
238
private function get_pages_in_table( $table ) {
239
240
+ // Table does not exist
241
$table = str_replace( $this->options->prefix . '.', null, $table );
242
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
243
if( !$result || 0 === $result ) {
664
return false;
665
}
666
667
+ // Table does not exist
668
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
669
if( !$result || 0 === $result ) {
670
return false;
apps/Backend/Modules/SystemInfo.php CHANGED
@@ -428,7 +428,7 @@ class SystemInfo extends InjectionAware {
428
$output .= $this->info( "Upload Max Filesize:", ini_get( "upload_max_filesize" ) );
429
$output .= $this->info( "Time Limit:", ini_get( "max_execution_time" ) );
430
$output .= $this->info( "Max Input Vars:", ini_get( "max_input_vars" ) );
431
- //$output .= $this->info( "PHP User:", $this->getPHPUser() );
432
433
$displayErrors = ini_get( "display_errors" );
434
$output .= $this->info( "Display Errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A" );
@@ -444,7 +444,7 @@ class SystemInfo extends InjectionAware {
444
445
$user = '';
446
447
- if( extension_loaded( 'posix' ) ) {
448
$file = WPSTG_PLUGIN_DIR . 'wp-staging.php';
449
$user = posix_getpwuid( fileowner( $file ) );
450
return isset($user['name']) ? $user['name'] : 'can not detect php user name';
428
$output .= $this->info( "Upload Max Filesize:", ini_get( "upload_max_filesize" ) );
429
$output .= $this->info( "Time Limit:", ini_get( "max_execution_time" ) );
430
$output .= $this->info( "Max Input Vars:", ini_get( "max_input_vars" ) );
431
+ $output .= $this->info( "PHP User:", $this->getPHPUser() );
432
433
$displayErrors = ini_get( "display_errors" );
434
$output .= $this->info( "Display Errors:", ($displayErrors) ? "On ({$displayErrors})" : "N/A" );
444
445
$user = '';
446
447
+ if( extension_loaded( 'posix' ) && function_exists('posix_getpwuid') ) {
448
$file = WPSTG_PLUGIN_DIR . 'wp-staging.php';
449
$user = posix_getpwuid( fileowner( $file ) );
450
return isset($user['name']) ? $user['name'] : 'can not detect php user name';
apps/Backend/views/_includes/messages/cache-directory-permission-problem.php CHANGED
@@ -2,6 +2,6 @@
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}cache"?> is not write and/or readable.
4
<br>
5
- Check if the folder <strong><?php echo "{$varsDirectory}cache"?></strong> exists! File permissions should be chmod 755 or 777.
6
</p>
7
</div>
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}cache"?> is not write and/or readable.
4
<br>
5
+ Check if the folder <strong><?php echo "{$varsDirectory}cache"?></strong> exists! Folder permissions should be chmod 755 or higher.
6
</p>
7
</div>
apps/Backend/views/_includes/messages/logs-directory-permission-problem.php CHANGED
@@ -2,6 +2,6 @@
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}logs"?> is not write and/or readable.
4
<br>
5
- Check if the folder <strong><?php echo "{$varsDirectory}logs"?></strong> exists! File permissions should be chmod 755 or 777.
6
</p>
7
</div>
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}logs"?> is not write and/or readable.
4
<br>
5
+ Check if the folder <strong><?php echo "{$varsDirectory}logs"?></strong> exists! Folder permissions should be chmod 755 or higher.
6
</p>
7
</div>
apps/Backend/views/_includes/messages/uploads-cache-directory-permission-problem.php CHANGED
@@ -5,6 +5,6 @@
5
is not write and/or readable.
6
<br>
7
Check if the folder <strong><?php echo \WPStaging\WPStaging::getContentDir()?></strong> exists!
8
- File permissions should be chmod 755 or 777.
9
</p>
10
</div>
5
is not write and/or readable.
6
<br>
7
Check if the folder <strong><?php echo \WPStaging\WPStaging::getContentDir()?></strong> exists!
8
+ Folder permissions should be chmod 755 or higher.
9
</p>
10
</div>
apps/Backend/views/_includes/messages/vars-directory-permission-problem.php CHANGED
@@ -2,6 +2,6 @@
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}"?> is not write and/or readable.
4
<br>
5
- Check if the folder <strong><?php echo "{$varsDirectory}"?></strong> exists! File permissions should be chmod 755 or 777.
6
</p>
7
</div>
2
<p>
3
<strong>WP Staging Folder Permission error: </strong> <?php echo "{$varsDirectory}"?> is not write and/or readable.
4
<br>
5
+ Check if the folder <strong><?php echo "{$varsDirectory}"?></strong> exists! Folder permissions should be chmod 755 or 777.
6
</p>
7
</div>
apps/Core/WPStaging.php CHANGED
@@ -29,7 +29,7 @@ final class WPStaging {
29
/**
30
* Plugin version
31
*/
32
- const VERSION = "2.5.2";
33
34
/**
35
* Plugin name
29
/**
30
* Plugin version
31
*/
32
+ const VERSION = "2.5.3";
33
34
/**
35
* Plugin name
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: 5.1
12
- Stable tag: 2.5.2
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,11 @@ https://wp-staging.com
146
147
== Changelog ==
148
149
= 2.5.2 =
150
* New: Tested up to WordPress 5.1.1
151
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: 5.1
12
+ Stable tag: 2.5.3
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.5.3 =
150
+ * Fix: Disable the WP-Spamshield Plugin on staging site because it prevents login to staging site
151
+ * Fix: Lower the memory consumption when cloning scan process is started
152
+ * New: Show PHP user in system info log
153
+
154
= 2.5.2 =
155
* New: Tested up to WordPress 5.1.1
156
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.5.2
11
* Text Domain: wp-staging
12
* Domain Path: /languages/
13
@@ -51,7 +51,7 @@ if( !defined( 'WPSTG_PLUGIN_URL' ) ) {
51
52
// Version
53
if( !defined( 'WPSTG_VERSION' ) ) {
54
- define( 'WPSTG_VERSION', '2.5.2' );
55
}
56
57
// Must use version of the optimizer
7
* Author: WP-Staging
8
* Author URI: https://wp-staging.com
9
* Contributors: ReneHermi, ilgityildirim
10
+ * Version: 2.5.3
11
* Text Domain: wp-staging
12
* Domain Path: /languages/
13
51
52
// Version
53
if( !defined( 'WPSTG_VERSION' ) ) {
54
+ define( 'WPSTG_VERSION', '2.5.3' );
55
}
56
57
// Must use version of the optimizer