Version Description
- New: Compatible to WP 5.0.0 Gutenberg
- New: Increase file scanning process performance
- New: Preview for external database cloning
- New: Add delay between requests setting to prevent timeouts on rate limited servers
New: Try again automatically cloning process if ajax request has been killed due to server ressource limit error
Fix: Error when removing heartbeat api
Fix: remove ? parameter from staging site
Fix: Do not load theme while WP Staging is running. Prevents processing interruption if there are fatal errors in the theme
Fix: When cloning has been canceled page needs to be reloaded before beeing able to clone again
Fix: Under rare circumstances plugins are disabled when wp staging runs.
Fix: Prevent error 503 (firewall/performance timeout) by adding post parameter to the ajax url
Fix: Adding automatic resume function to the ajax processing to prevent cloning and pushing interruptions due to hitting server ressource or network glitches.
Fix: Selected folders are not excluded under Windows IIS server
Fix: Windows IIS server compatibilility issues resolved
Release Info
Developer | ReneHermi |
Plugin | WP Staging – DB & File Duplicator & Migration |
Version | 2.4.0 |
Comparing to | |
See all releases |
Code changes from version 2.3.9 to 2.4.0
- apps/Backend/Administrator.php +8 -13
- apps/Backend/Modules/Jobs/Cloning.php +377 -271
- apps/Backend/Modules/Jobs/Data.php +141 -63
- apps/Backend/Modules/Jobs/Delete.php +11 -1
- apps/Backend/Modules/Jobs/Directories.php +18 -58
- apps/Backend/Modules/Jobs/Files.php +381 -343
- apps/Backend/Modules/Jobs/Finish.php +98 -58
- apps/Backend/Modules/Jobs/Job.php +1 -81
- apps/Backend/Modules/Jobs/Multisite/Data.php +937 -894
- apps/Backend/Modules/Jobs/Multisite/DataExternal.php +1041 -988
- apps/Backend/Modules/Jobs/Multisite/Database.php +112 -65
- apps/Backend/Modules/Jobs/Multisite/DatabaseExternal.php +118 -57
- apps/Backend/Modules/Jobs/Multisite/Directories.php +8 -4
- apps/Backend/Modules/Jobs/Multisite/Files.php +407 -359
- apps/Backend/Modules/Jobs/Multisite/Finish.php +101 -59
- apps/Backend/Modules/Jobs/Multisite/SearchReplace.php +761 -717
- apps/Backend/Modules/Jobs/Multisite/SearchReplaceExternal.php +793 -672
- apps/Backend/Modules/Jobs/SearchReplace.php +710 -636
- apps/Backend/Modules/Jobs/Updating.php +299 -250
- apps/Backend/Modules/SystemInfo.php +1 -2
- apps/Backend/Modules/Views/Forms/Settings.php +0 -10
- apps/Backend/Optimizer/blank-theme/functions.php +7 -0
- apps/Backend/Optimizer/wp-staging-optimizer.php +88 -14
- apps/Backend/public/css/wpstg-admin.css +261 -262
- apps/Backend/public/js/wpstg-admin.js +64 -34
- apps/Backend/views/_includes/header.php +2 -2
- apps/Backend/views/clone/ajax/custom-directory.php +36 -0
- apps/Backend/views/clone/ajax/delete-confirmation.php +2 -2
- apps/Backend/views/clone/ajax/external-database.php +6 -8
- apps/Backend/views/clone/ajax/scan.php +54 -59
- apps/Backend/views/settings/main-settings.php +219 -235
- apps/Core/DTO/Settings.php +83 -74
- apps/Core/Utils/Strings.php +41 -32
- apps/Core/Utils/functions.php +75 -0
- apps/Core/WPStaging.php +434 -403
- apps/Frontend/Frontend.php +1 -21
- apps/Frontend/loginForm.php +252 -250
- readme.txt +23 -3
- wp-staging.php +2 -2
@@ -7,27 +7,21 @@ if( !defined( "WPINC" ) ) {
|
|
7 |
die;
|
8 |
}
|
9 |
|
|
|
10 |
use WPStaging\Backend\Modules\Jobs\Cancel;
|
11 |
use WPStaging\Backend\Modules\Jobs\CancelUpdate;
|
12 |
use WPStaging\Backend\Modules\Jobs\Cloning;
|
13 |
use WPStaging\Backend\Modules\Jobs\Updating;
|
14 |
-
use WPStaging\Backend\Modules\Jobs\Data;
|
15 |
-
use WPStaging\Backend\Modules\Jobs\Database;
|
16 |
use WPStaging\Backend\Modules\Jobs\Delete;
|
17 |
-
use WPStaging\Backend\Modules\Jobs\Files;
|
18 |
use WPStaging\Backend\Modules\Jobs\Scan;
|
19 |
use WPStaging\Backend\Modules\Jobs\Logs;
|
20 |
-
#use WPStaging\Backend\Modules\Optimizer;
|
21 |
use WPStaging\Backend\Modules\SystemInfo;
|
22 |
use WPStaging\Backend\Modules\Views\Tabs\Tabs;
|
23 |
use WPStaging\Backend\Notices\Notices;
|
24 |
use WPStaging\DI\InjectionAware;
|
25 |
use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
|
26 |
-
use WPStaging\Backend\Activation;
|
27 |
-
use WPStaging\WPStaging;
|
28 |
-
use WPStaging\Backend\Pro\Modules\Jobs\Processing;
|
29 |
-
use WPStaging\Backend\Pro\Licensing;
|
30 |
use WPStaging\Utils\Report;
|
|
|
31 |
|
32 |
/**
|
33 |
* Class Administrator
|
@@ -95,7 +89,8 @@ class Administrator extends InjectionAware {
|
|
95 |
$loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
|
96 |
$loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
|
97 |
$loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
|
98 |
-
$loader->addAction( "
|
|
|
99 |
$loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
|
100 |
$loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
|
101 |
$loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
|
@@ -141,8 +136,6 @@ class Administrator extends InjectionAware {
|
|
141 |
|
142 |
add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wp-staging" ), "updated" );
|
143 |
|
144 |
-
// Return sanitized data
|
145 |
-
//return $sanitized;
|
146 |
return apply_filters( "wpstg-settings", $sanitized, $data );
|
147 |
}
|
148 |
|
@@ -380,6 +373,8 @@ class Administrator extends InjectionAware {
|
|
380 |
// Get license data
|
381 |
$license = get_option( 'wpstg_license_status' );
|
382 |
|
|
|
|
|
383 |
|
384 |
if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
|
385 |
require_once "{$this->path}Pro/views/single-overview-pro.php";
|
@@ -450,7 +445,7 @@ class Administrator extends InjectionAware {
|
|
450 |
$cloning = new Updating();
|
451 |
|
452 |
if( !$cloning->save() ) {
|
453 |
-
wp_die('can not save clone data');
|
454 |
}
|
455 |
|
456 |
require_once "{$this->path}views/clone/ajax/update.php";
|
@@ -467,7 +462,7 @@ class Administrator extends InjectionAware {
|
|
467 |
$cloning = new Cloning();
|
468 |
|
469 |
if( !$cloning->save() ) {
|
470 |
-
wp_die('can not save clone data');
|
471 |
}
|
472 |
|
473 |
require_once "{$this->path}views/clone/ajax/start.php";
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
+
use WPStaging\WPStaging;
|
11 |
use WPStaging\Backend\Modules\Jobs\Cancel;
|
12 |
use WPStaging\Backend\Modules\Jobs\CancelUpdate;
|
13 |
use WPStaging\Backend\Modules\Jobs\Cloning;
|
14 |
use WPStaging\Backend\Modules\Jobs\Updating;
|
|
|
|
|
15 |
use WPStaging\Backend\Modules\Jobs\Delete;
|
|
|
16 |
use WPStaging\Backend\Modules\Jobs\Scan;
|
17 |
use WPStaging\Backend\Modules\Jobs\Logs;
|
|
|
18 |
use WPStaging\Backend\Modules\SystemInfo;
|
19 |
use WPStaging\Backend\Modules\Views\Tabs\Tabs;
|
20 |
use WPStaging\Backend\Notices\Notices;
|
21 |
use WPStaging\DI\InjectionAware;
|
22 |
use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
|
|
|
|
|
|
|
|
|
23 |
use WPStaging\Utils\Report;
|
24 |
+
use WPStaging\Backend\Activation;
|
25 |
|
26 |
/**
|
27 |
* Class Administrator
|
89 |
$loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
|
90 |
$loader->addAction( "wp_ajax_wpstg_update", $this, "ajaxUpdateProcess" );
|
91 |
$loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
|
92 |
+
$loader->addAction( "wp_ajax_wpstg_processing", $this, "ajaxCloneDatabase" );
|
93 |
+
$loader->addAction( "wp_ajax_wpstg_database_connect", $this, "ajaxDatabaseConnect" );
|
94 |
$loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
|
95 |
$loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
|
96 |
$loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
|
136 |
|
137 |
add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wp-staging" ), "updated" );
|
138 |
|
|
|
|
|
139 |
return apply_filters( "wpstg-settings", $sanitized, $data );
|
140 |
}
|
141 |
|
373 |
// Get license data
|
374 |
$license = get_option( 'wpstg_license_status' );
|
375 |
|
376 |
+
// Get db
|
377 |
+
$db = WPStaging::getInstance()->get( 'wpdb' );
|
378 |
|
379 |
if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
|
380 |
require_once "{$this->path}Pro/views/single-overview-pro.php";
|
445 |
$cloning = new Updating();
|
446 |
|
447 |
if( !$cloning->save() ) {
|
448 |
+
wp_die( 'can not save clone data' );
|
449 |
}
|
450 |
|
451 |
require_once "{$this->path}views/clone/ajax/update.php";
|
462 |
$cloning = new Cloning();
|
463 |
|
464 |
if( !$cloning->save() ) {
|
465 |
+
wp_die( 'can not save clone data' );
|
466 |
}
|
467 |
|
468 |
require_once "{$this->path}views/clone/ajax/start.php";
|
@@ -4,6 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs;
|
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
|
6 |
use WPStaging\WPStaging;
|
|
|
7 |
|
8 |
/**
|
9 |
* Class Cloning
|
@@ -11,276 +12,381 @@ use WPStaging\WPStaging;
|
|
11 |
*/
|
12 |
class Cloning extends Job {
|
13 |
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
//
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
$
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
}
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
$
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
$
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
return $this->
|
239 |
-
}
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
285 |
|
286 |
}
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
|
6 |
use WPStaging\WPStaging;
|
7 |
+
use WPStaging\Utils\Helper;
|
8 |
|
9 |
/**
|
10 |
* Class Cloning
|
12 |
*/
|
13 |
class Cloning extends Job {
|
14 |
|
15 |
+
/**
|
16 |
+
* Initialize is called in \Job
|
17 |
+
*/
|
18 |
+
public function initialize() {
|
19 |
+
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* Save Chosen Cloning Settings
|
24 |
+
* @return bool
|
25 |
+
*/
|
26 |
+
public function save() {
|
27 |
+
if( !isset( $_POST ) || !isset( $_POST["cloneID"] ) ) {
|
28 |
+
return false;
|
29 |
+
}
|
30 |
+
|
31 |
+
// Delete files to copy listing
|
32 |
+
$this->cache->delete( "files_to_copy" );
|
33 |
+
|
34 |
+
// Generate Options
|
35 |
+
// Clone
|
36 |
+
$this->options->clone = $_POST["cloneID"];
|
37 |
+
$this->options->cloneDirectoryName = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
|
38 |
+
$this->options->cloneNumber = 1;
|
39 |
+
$this->options->prefix = $this->setStagingPrefix();
|
40 |
+
$this->options->includedDirectories = array();
|
41 |
+
$this->options->excludedDirectories = array();
|
42 |
+
$this->options->extraDirectories = array();
|
43 |
+
$this->options->excludedFiles = array(
|
44 |
+
'.htaccess',
|
45 |
+
'.DS_Store',
|
46 |
+
'.git',
|
47 |
+
'.svn',
|
48 |
+
'.tmp',
|
49 |
+
'desktop.ini',
|
50 |
+
'.gitignore',
|
51 |
+
'.log',
|
52 |
+
'web.config'
|
53 |
+
);
|
54 |
+
$this->options->excludedFilesFullPath = array(
|
55 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'db.php',
|
56 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
|
57 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
|
58 |
+
);
|
59 |
+
$this->options->currentStep = 0;
|
60 |
+
|
61 |
+
// Job
|
62 |
+
$this->options->job = new \stdClass();
|
63 |
+
|
64 |
+
// Check if clone data already exists and use that one
|
65 |
+
if( isset( $this->options->existingClones[$this->options->clone] ) ) {
|
66 |
+
|
67 |
+
$this->options->cloneNumber = $this->options->existingClones[$this->options->clone]->number;
|
68 |
+
|
69 |
+
$this->options->prefix = isset( $this->options->existingClones[$this->options->clone]->prefix ) ?
|
70 |
+
$this->options->existingClones[$this->options->clone]->prefix :
|
71 |
+
$this->setStagingPrefix();
|
72 |
+
}
|
73 |
+
// Clone does not exist but there are other clones in db
|
74 |
+
// Get data and increment it
|
75 |
+
elseif( !empty( $this->options->existingClones ) ) {
|
76 |
+
$this->options->cloneNumber = count( $this->options->existingClones ) + 1;
|
77 |
+
$this->options->prefix = $this->setStagingPrefix();
|
78 |
+
}
|
79 |
+
|
80 |
+
// Included Tables
|
81 |
+
if( isset( $_POST["includedTables"] ) && is_array( $_POST["includedTables"] ) ) {
|
82 |
+
$this->options->tables = $_POST["includedTables"];
|
83 |
+
} else {
|
84 |
+
$this->options->tables = array();
|
85 |
+
}
|
86 |
+
|
87 |
+
// Excluded Directories
|
88 |
+
if( isset( $_POST["excludedDirectories"] ) && is_array( $_POST["excludedDirectories"] ) ) {
|
89 |
+
$this->options->excludedDirectories = $_POST["excludedDirectories"];
|
90 |
+
}
|
91 |
+
|
92 |
+
// Excluded Directories TOTAL
|
93 |
+
// Do not copy these folders and plugins
|
94 |
+
$excludedDirectories = array(
|
95 |
+
\WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
|
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 );
|
102 |
+
|
103 |
+
array_unshift( $this->options->directoriesToCopy, \WPStaging\WPStaging::getWPpath() );
|
104 |
+
|
105 |
+
// Included Directories
|
106 |
+
if( isset( $_POST["includedDirectories"] ) && is_array( $_POST["includedDirectories"] ) ) {
|
107 |
+
$this->options->includedDirectories = $_POST["includedDirectories"];
|
108 |
+
}
|
109 |
+
|
110 |
+
// Extra Directories
|
111 |
+
if( isset( $_POST["extraDirectories"] ) && !empty( $_POST["extraDirectories"] ) ) {
|
112 |
+
$this->options->extraDirectories = $_POST["extraDirectories"];
|
113 |
+
}
|
114 |
+
|
115 |
+
// Directories to Copy
|
116 |
+
$this->options->directoriesToCopy = array_merge(
|
117 |
+
$this->options->includedDirectories, $this->options->extraDirectories
|
118 |
+
);
|
119 |
+
|
120 |
+
|
121 |
+
$this->options->databaseServer = 'localhost';
|
122 |
+
if( isset( $_POST["databaseServer"] ) && !empty( $_POST["databaseServer"] ) ) {
|
123 |
+
$this->options->databaseServer = $_POST["databaseServer"];
|
124 |
+
}
|
125 |
+
$this->options->databaseUser = '';
|
126 |
+
if( isset( $_POST["databaseUser"] ) && !empty( $_POST["databaseUser"] ) ) {
|
127 |
+
$this->options->databaseUser = $_POST["databaseUser"];
|
128 |
+
}
|
129 |
+
$this->options->databasePassword = '';
|
130 |
+
if( isset( $_POST["databasePassword"] ) && !empty( $_POST["databasePassword"] ) ) {
|
131 |
+
$this->options->databasePassword = $_POST["databasePassword"];
|
132 |
+
}
|
133 |
+
$this->options->databaseDatabase = '';
|
134 |
+
if( isset( $_POST["databaseDatabase"] ) && !empty( $_POST["databaseDatabase"] ) ) {
|
135 |
+
$this->options->databaseDatabase = $_POST["databaseDatabase"];
|
136 |
+
}
|
137 |
+
$this->options->databasePrefix = '';
|
138 |
+
if( isset( $_POST["databasePrefix"] ) && !empty( $_POST["databasePrefix"] ) ) {
|
139 |
+
$this->options->databasePrefix = $this->sanitizePrefix( $_POST["databasePrefix"] );
|
140 |
+
}
|
141 |
+
$this->options->cloneDir = '';
|
142 |
+
if( isset( $_POST["cloneDir"] ) && !empty( $_POST["cloneDir"] ) ) {
|
143 |
+
$this->options->cloneDir = trailingslashit( $_POST["cloneDir"] );
|
144 |
+
}
|
145 |
+
$this->options->cloneHostname = '';
|
146 |
+
if( isset( $_POST["cloneHostname"] ) && !empty( $_POST["cloneHostname"] ) ) {
|
147 |
+
$this->options->cloneHostname = $_POST["cloneHostname"];
|
148 |
+
}
|
149 |
+
|
150 |
+
$this->options->destinationHostname = $this->getDestinationHostname();
|
151 |
+
$this->options->destinationDir = $this->getDestinationDir();
|
152 |
+
|
153 |
+
$helper = new Helper();
|
154 |
+
$this->options->homeHostname = $helper->get_home_url_without_scheme();
|
155 |
+
|
156 |
+
return $this->saveOptions();
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Return target hostname
|
161 |
+
* @return string
|
162 |
+
*/
|
163 |
+
private function getDestinationHostname() {
|
164 |
+
if( empty( $this->options->cloneHostname ) ) {
|
165 |
+
$helper = new Helper();
|
166 |
+
return $helper->get_home_url_without_scheme();
|
167 |
+
}
|
168 |
+
return $this->getHostnameWithoutScheme( $this->options->cloneHostname );
|
169 |
+
}
|
170 |
+
|
171 |
+
/**
|
172 |
+
* Return Hostname without scheme
|
173 |
+
* @param string $str
|
174 |
+
* @return string
|
175 |
+
*/
|
176 |
+
private function getHostnameWithoutScheme( $string ) {
|
177 |
+
return preg_replace( '#^https?://#', '', rtrim( $string, '/' ) );
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Get Destination Directory including staging subdirectory
|
182 |
+
* @return type
|
183 |
+
*/
|
184 |
+
private function getDestinationDir() {
|
185 |
+
// No custom clone dir or clone dir equals abspath of main wordpress site
|
186 |
+
if( empty( $this->options->cloneDir ) || $this->options->cloneDir == (string)\WPStaging\WPStaging::getWPpath()) {
|
187 |
+
return trailingslashit( \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName );
|
188 |
+
}
|
189 |
+
//return trailingslashit($this->options->cloneDir . $this->options->cloneDirectoryName);
|
190 |
+
return trailingslashit( $this->options->cloneDir );
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Check if WP is installed in subdir
|
195 |
+
* @return boolean
|
196 |
+
*/
|
197 |
+
// private function isSubDir() {
|
198 |
+
// // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
199 |
+
// // This is happening much more often than you would expect
|
200 |
+
// $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
201 |
+
// $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
202 |
+
//
|
203 |
+
// if( $home !== $siteurl ) {
|
204 |
+
// return true;
|
205 |
+
// }
|
206 |
+
// return false;
|
207 |
+
// }
|
208 |
+
|
209 |
+
/**
|
210 |
+
* Get the install sub directory if WP is installed in sub directory or return empty string
|
211 |
+
* Result contains a trailingslash
|
212 |
+
* @return string
|
213 |
+
*/
|
214 |
+
// private function getSubDir() {
|
215 |
+
//
|
216 |
+
// if(!$this->isSubDir()){
|
217 |
+
// return '';
|
218 |
+
// }
|
219 |
+
//
|
220 |
+
// $home = get_option( 'home' );
|
221 |
+
// $siteurl = get_option( 'siteurl' );
|
222 |
+
//
|
223 |
+
// if( empty( $home ) || empty( $siteurl ) ) {
|
224 |
+
// return '';
|
225 |
+
// }
|
226 |
+
//
|
227 |
+
// $dir = str_replace( $home, '', $siteurl );
|
228 |
+
// return trailingslashit($dir);
|
229 |
+
// }
|
230 |
+
|
231 |
+
/**
|
232 |
+
* Get Destination Directory
|
233 |
+
* @return type
|
234 |
+
*/
|
235 |
+
// private function getDestinationRoot() {
|
236 |
+
// if( empty( $this->options->cloneDir ) ) {
|
237 |
+
// return \WPStaging\WPStaging::getWPpath();
|
238 |
+
// }
|
239 |
+
// return $this->options->cloneDir;
|
240 |
+
// }
|
241 |
+
|
242 |
+
/**
|
243 |
+
* Make sure prefix contains appending underscore
|
244 |
+
*
|
245 |
+
* @param string $string
|
246 |
+
* @return string
|
247 |
+
*/
|
248 |
+
private function sanitizePrefix( $string ) {
|
249 |
+
$lastCharacter = substr( $string, -1 );
|
250 |
+
if( $lastCharacter === '_' ) {
|
251 |
+
return $string;
|
252 |
+
}
|
253 |
+
return $string . '_';
|
254 |
+
}
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Create a new staging prefix which does not already exists in database
|
258 |
+
*/
|
259 |
+
private function setStagingPrefix() {
|
260 |
+
|
261 |
+
// Get & find a new prefix that does not already exist in database.
|
262 |
+
// Loop through up to 1000 different possible prefixes should be enough here;)
|
263 |
+
for ( $i = 0; $i <= 10000; $i++ ) {
|
264 |
+
$this->options->prefix = isset( $this->options->existingClones ) ?
|
265 |
+
'wpstg' . (count( $this->options->existingClones ) + $i) . '_' :
|
266 |
+
'wpstg' . $i . '_';
|
267 |
+
|
268 |
+
$sql = "SHOW TABLE STATUS LIKE '{$this->options->prefix}%'";
|
269 |
+
$tables = $this->db->get_results( $sql );
|
270 |
+
|
271 |
+
// Prefix does not exists. We can use it
|
272 |
+
if( !$tables ) {
|
273 |
+
return $this->options->prefix;
|
274 |
+
}
|
275 |
+
}
|
276 |
+
$this->returnException( "Fatal Error: Can not create staging prefix. '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
|
277 |
+
wp_die( "Fatal Error: Can not create staging prefix. Prefix '{$this->options->prefix}' already exists! Stopping for security reasons. Contact support@wp-staging.com" );
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Check if potential new prefix of staging site would be identical with live site.
|
282 |
+
* @return boolean
|
283 |
+
*/
|
284 |
+
private function isPrefixIdentical() {
|
285 |
+
$db = WPStaging::getInstance()->get( "wpdb" );
|
286 |
+
|
287 |
+
$livePrefix = $db->prefix;
|
288 |
+
$stagingPrefix = $this->options->prefix;
|
289 |
+
|
290 |
+
if( $livePrefix == $stagingPrefix ) {
|
291 |
+
return true;
|
292 |
+
}
|
293 |
+
return false;
|
294 |
+
}
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Start the cloning job
|
298 |
+
*/
|
299 |
+
public function start() {
|
300 |
+
if( null === $this->options->currentJob ) {
|
301 |
+
$this->log( "Cloning job for {$this->options->clone} finished" );
|
302 |
+
return true;
|
303 |
+
}
|
304 |
+
|
305 |
+
$methodName = "job" . ucwords( $this->options->currentJob );
|
306 |
+
|
307 |
+
if( !method_exists( $this, $methodName ) ) {
|
308 |
+
$this->log( "Can't execute job; Job's method {$methodName} is not found" );
|
309 |
+
throw new JobNotFoundException( $methodName );
|
310 |
+
}
|
311 |
+
|
312 |
+
// Call the job
|
313 |
+
//$this->log("execute job: Job's method {$methodName}");
|
314 |
+
return $this->{$methodName}();
|
315 |
+
}
|
316 |
+
|
317 |
+
/**
|
318 |
+
* @param object $response
|
319 |
+
* @param string $nextJob
|
320 |
+
* @return object
|
321 |
+
*/
|
322 |
+
private function handleJobResponse( $response, $nextJob ) {
|
323 |
+
// Job is not done
|
324 |
+
if( true !== $response->status ) {
|
325 |
+
return $response;
|
326 |
+
}
|
327 |
+
|
328 |
+
$this->options->currentJob = $nextJob;
|
329 |
+
$this->options->currentStep = 0;
|
330 |
+
$this->options->totalSteps = 0;
|
331 |
+
|
332 |
+
// Save options
|
333 |
+
$this->saveOptions();
|
334 |
+
|
335 |
+
return $response;
|
336 |
+
}
|
337 |
+
|
338 |
+
/**
|
339 |
+
* Clone Database
|
340 |
+
* @return object
|
341 |
+
*/
|
342 |
+
public function jobDatabase() {
|
343 |
+
$database = new Database();
|
344 |
+
return $this->handleJobResponse( $database->start(), "SearchReplace" );
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Search & Replace
|
349 |
+
* @return object
|
350 |
+
*/
|
351 |
+
public function jobSearchReplace() {
|
352 |
+
$searchReplace = new SearchReplace();
|
353 |
+
return $this->handleJobResponse( $searchReplace->start(), "directories" );
|
354 |
+
}
|
355 |
+
|
356 |
+
/**
|
357 |
+
* Get All Files From Selected Directories Recursively Into a File
|
358 |
+
* @return object
|
359 |
+
*/
|
360 |
+
public function jobDirectories() {
|
361 |
+
$directories = new Directories();
|
362 |
+
return $this->handleJobResponse( $directories->start(), "files" );
|
363 |
+
}
|
364 |
+
|
365 |
+
/**
|
366 |
+
* Copy Files
|
367 |
+
* @return object
|
368 |
+
*/
|
369 |
+
public function jobFiles() {
|
370 |
+
$files = new Files();
|
371 |
+
return $this->handleJobResponse( $files->start(), "data" );
|
372 |
+
}
|
373 |
+
|
374 |
+
/**
|
375 |
+
* Replace Data
|
376 |
+
* @return object
|
377 |
+
*/
|
378 |
+
public function jobData() {
|
379 |
+
$data = new Data();
|
380 |
+
return $this->handleJobResponse( $data->start(), "finish" );
|
381 |
+
}
|
382 |
+
|
383 |
+
/**
|
384 |
+
* Save Clone Data
|
385 |
+
* @return object
|
386 |
+
*/
|
387 |
+
public function jobFinish() {
|
388 |
+
$finish = new Finish();
|
389 |
+
return $this->handleJobResponse( $finish->start(), '' );
|
390 |
+
}
|
391 |
|
392 |
}
|
@@ -50,11 +50,9 @@ class Data extends JobExecutable {
|
|
50 |
|
51 |
$this->getTables();
|
52 |
|
53 |
-
|
54 |
-
|
55 |
$this->homeUrl = $helper->get_home_url();
|
56 |
|
57 |
-
|
58 |
// Fix current step
|
59 |
if( 0 == $this->options->currentStep ) {
|
60 |
$this->options->currentStep = 0;
|
@@ -65,7 +63,7 @@ class Data extends JobExecutable {
|
|
65 |
* Get a list of tables to copy
|
66 |
*/
|
67 |
private function getTables() {
|
68 |
-
$strings
|
69 |
$this->tables = array();
|
70 |
foreach ( $this->options->tables as $table ) {
|
71 |
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
|
@@ -77,7 +75,7 @@ class Data extends JobExecutable {
|
|
77 |
* @return void
|
78 |
*/
|
79 |
protected function calculateTotalSteps() {
|
80 |
-
|
81 |
}
|
82 |
|
83 |
/**
|
@@ -183,22 +181,6 @@ class Data extends JobExecutable {
|
|
183 |
return true;
|
184 |
}
|
185 |
|
186 |
-
/**
|
187 |
-
* Get the install sub directory if WP is installed in sub directory
|
188 |
-
* @return string
|
189 |
-
*/
|
190 |
-
protected function getSubDir() {
|
191 |
-
$home = get_option( 'home' );
|
192 |
-
$siteurl = get_option( 'siteurl' );
|
193 |
-
|
194 |
-
if( empty( $home ) || empty( $siteurl ) ) {
|
195 |
-
return '/';
|
196 |
-
}
|
197 |
-
|
198 |
-
$dir = str_replace( $home, '', $siteurl );
|
199 |
-
return '/' . str_replace( '/', '', $dir ) . '/';
|
200 |
-
}
|
201 |
-
|
202 |
/**
|
203 |
* Copy wp-config.php if it is located outside of root one level up
|
204 |
* @todo Needs some more testing before it will be released
|
@@ -211,7 +193,7 @@ class Data extends JobExecutable {
|
|
211 |
|
212 |
$source = $dir . 'wp-config.php';
|
213 |
|
214 |
-
|
215 |
|
216 |
|
217 |
// Do not do anything
|
@@ -258,28 +240,36 @@ class Data extends JobExecutable {
|
|
258 |
}
|
259 |
|
260 |
// Installed in sub-directory
|
261 |
-
if( $this->isSubDir() ) {
|
262 |
-
$this->log( "Preparing Data Step1: Updating siteurl and homeurl to " .
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
263 |
// Replace URLs
|
264 |
$result = $this->db->query(
|
265 |
$this->db->prepare(
|
266 |
-
|
267 |
)
|
268 |
);
|
269 |
-
|
270 |
-
$this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->homeUrl, "/" ) . '/' . $this->options->cloneDirectoryName );
|
271 |
-
// Replace URLs
|
272 |
-
$result = $this->db->query(
|
273 |
-
$this->db->prepare(
|
274 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->homeUrl . '/' . $this->options->cloneDirectoryName
|
275 |
-
)
|
276 |
-
);
|
277 |
-
}
|
278 |
|
279 |
|
280 |
// All good
|
281 |
-
|
282 |
-
$this->log( "Preparing Data Step1: Successfull", Logger::TYPE_INFO );
|
283 |
return true;
|
284 |
}
|
285 |
|
@@ -306,6 +296,11 @@ class Data extends JobExecutable {
|
|
306 |
return true;
|
307 |
}
|
308 |
|
|
|
|
|
|
|
|
|
|
|
309 |
$delete = $this->db->query(
|
310 |
$this->db->prepare(
|
311 |
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
|
@@ -321,7 +316,6 @@ class Data extends JobExecutable {
|
|
321 |
)
|
322 |
);
|
323 |
//}
|
324 |
-
|
325 |
// All good
|
326 |
if( $insert ) {
|
327 |
$this->log( "Preparing Data Step2: Successfull", Logger::TYPE_INFO );
|
@@ -394,7 +388,7 @@ class Data extends JobExecutable {
|
|
394 |
|
395 |
if( !$update ) {
|
396 |
$this->log( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
|
397 |
-
|
398 |
return false;
|
399 |
}
|
400 |
|
@@ -408,7 +402,7 @@ class Data extends JobExecutable {
|
|
408 |
* @return bool
|
409 |
*/
|
410 |
protected function step5() {
|
411 |
-
|
412 |
|
413 |
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
|
414 |
if( false === ($content = file_get_contents( $path )) ) {
|
@@ -420,7 +414,7 @@ class Data extends JobExecutable {
|
|
420 |
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
|
421 |
|
422 |
// Replace URLs
|
423 |
-
|
424 |
|
425 |
if( false === @file_put_contents( $path, $content ) ) {
|
426 |
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
|
@@ -444,7 +438,7 @@ class Data extends JobExecutable {
|
|
444 |
return true;
|
445 |
}
|
446 |
|
447 |
-
|
448 |
|
449 |
if( false === ($content = file_get_contents( $path )) ) {
|
450 |
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
|
@@ -476,7 +470,7 @@ class Data extends JobExecutable {
|
|
476 |
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
477 |
return false;
|
478 |
}
|
479 |
-
|
480 |
return true;
|
481 |
}
|
482 |
|
@@ -507,7 +501,7 @@ class Data extends JobExecutable {
|
|
507 |
|
508 |
// All good
|
509 |
if( $result ) {
|
510 |
-
|
511 |
return true;
|
512 |
}
|
513 |
|
@@ -542,7 +536,7 @@ class Data extends JobExecutable {
|
|
542 |
|
543 |
// All good
|
544 |
if( $result ) {
|
545 |
-
|
546 |
return true;
|
547 |
}
|
548 |
|
@@ -576,7 +570,7 @@ class Data extends JobExecutable {
|
|
576 |
|
577 |
// All good
|
578 |
if( $result ) {
|
579 |
-
|
580 |
return true;
|
581 |
}
|
582 |
|
@@ -589,7 +583,7 @@ class Data extends JobExecutable {
|
|
589 |
* @return bool
|
590 |
*/
|
591 |
protected function step10() {
|
592 |
-
|
593 |
|
594 |
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
595 |
|
@@ -622,7 +616,7 @@ class Data extends JobExecutable {
|
|
622 |
$this->log( "Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR );
|
623 |
return false;
|
624 |
}
|
625 |
-
|
626 |
return true;
|
627 |
}
|
628 |
|
@@ -631,7 +625,7 @@ class Data extends JobExecutable {
|
|
631 |
* @return bool
|
632 |
*/
|
633 |
protected function step11() {
|
634 |
-
|
635 |
|
636 |
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
|
637 |
|
@@ -665,11 +659,77 @@ class Data extends JobExecutable {
|
|
665 |
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
666 |
return false;
|
667 |
}
|
668 |
-
|
669 |
return true;
|
670 |
}
|
671 |
|
672 |
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
673 |
* Update Table Prefix in wp_options
|
674 |
* @return bool
|
675 |
*/
|
@@ -687,10 +747,9 @@ class Data extends JobExecutable {
|
|
687 |
return true;
|
688 |
}
|
689 |
|
690 |
-
|
691 |
-
|
692 |
-
$this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
|
693 |
|
|
|
694 |
// Filter the rows below. Do not update them!
|
695 |
$filters = array(
|
696 |
'wp_mail_smtp',
|
@@ -712,11 +771,11 @@ class Data extends JobExecutable {
|
|
712 |
);
|
713 |
|
714 |
if( !$updateOptions ) {
|
715 |
-
|
716 |
$this->returnException( " Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
717 |
return false;
|
718 |
}
|
719 |
-
|
720 |
return true;
|
721 |
}
|
722 |
|
@@ -735,13 +794,13 @@ class Data extends JobExecutable {
|
|
735 |
$newUploadPath = $this->getNewUploadPath();
|
736 |
|
737 |
if( false === $newUploadPath ) {
|
738 |
-
|
739 |
return true;
|
740 |
}
|
741 |
|
742 |
// Skip - Table is not selected or updated
|
743 |
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
744 |
-
|
745 |
return true;
|
746 |
}
|
747 |
|
@@ -759,7 +818,7 @@ class Data extends JobExecutable {
|
|
759 |
$this->log( "Preparing Data Step13: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
760 |
return true;
|
761 |
}
|
762 |
-
|
763 |
return true;
|
764 |
}
|
765 |
|
@@ -768,7 +827,7 @@ class Data extends JobExecutable {
|
|
768 |
* @return bool
|
769 |
*/
|
770 |
protected function step14() {
|
771 |
-
|
772 |
|
773 |
$this->log( "Preparing Data Step14: Set WP_CACHE in wp-config.php to false" );
|
774 |
|
@@ -801,7 +860,7 @@ class Data extends JobExecutable {
|
|
801 |
$this->log( "Preparing Data Step14: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
|
802 |
return false;
|
803 |
}
|
804 |
-
|
805 |
return true;
|
806 |
}
|
807 |
|
@@ -814,7 +873,7 @@ class Data extends JobExecutable {
|
|
814 |
|
815 |
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
|
816 |
|
817 |
-
|
818 |
|
819 |
return $newUploadPath;
|
820 |
}
|
@@ -824,11 +883,14 @@ class Data extends JobExecutable {
|
|
824 |
* @return string
|
825 |
*/
|
826 |
protected function getStagingSiteUrl() {
|
|
|
|
|
|
|
827 |
if( $this->isSubDir() ) {
|
828 |
-
|
829 |
}
|
830 |
|
831 |
-
|
832 |
}
|
833 |
|
834 |
/**
|
@@ -839,7 +901,7 @@ class Data extends JobExecutable {
|
|
839 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
840 |
// This is happening much more often than you would expect
|
841 |
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
842 |
-
|
843 |
|
844 |
if( $home !== $siteurl ) {
|
845 |
return true;
|
@@ -847,4 +909,20 @@ class Data extends JobExecutable {
|
|
847 |
return false;
|
848 |
}
|
849 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
850 |
}
|
50 |
|
51 |
$this->getTables();
|
52 |
|
53 |
+
$helper = new Helper();
|
|
|
54 |
$this->homeUrl = $helper->get_home_url();
|
55 |
|
|
|
56 |
// Fix current step
|
57 |
if( 0 == $this->options->currentStep ) {
|
58 |
$this->options->currentStep = 0;
|
63 |
* Get a list of tables to copy
|
64 |
*/
|
65 |
private function getTables() {
|
66 |
+
$strings = new Strings();
|
67 |
$this->tables = array();
|
68 |
foreach ( $this->options->tables as $table ) {
|
69 |
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->db->prefix, null, $table );
|
75 |
* @return void
|
76 |
*/
|
77 |
protected function calculateTotalSteps() {
|
78 |
+
$this->options->totalSteps = 15;
|
79 |
}
|
80 |
|
81 |
/**
|
181 |
return true;
|
182 |
}
|
183 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
184 |
/**
|
185 |
* Copy wp-config.php if it is located outside of root one level up
|
186 |
* @todo Needs some more testing before it will be released
|
193 |
|
194 |
$source = $dir . 'wp-config.php';
|
195 |
|
196 |
+
$destination = $this->options->destinationDir . 'wp-config.php';
|
197 |
|
198 |
|
199 |
// Do not do anything
|
240 |
}
|
241 |
|
242 |
// Installed in sub-directory
|
243 |
+
// if( $this->isSubDir() ) {
|
244 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
|
245 |
+
// // Replace URLs
|
246 |
+
// $result = $this->db->query(
|
247 |
+
// $this->db->prepare(
|
248 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
249 |
+
// )
|
250 |
+
// );
|
251 |
+
// } else {
|
252 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
|
253 |
+
// // Replace URLs
|
254 |
+
// $result = $this->db->query(
|
255 |
+
// $this->db->prepare(
|
256 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
257 |
+
// )
|
258 |
+
// );
|
259 |
+
// }
|
260 |
+
|
261 |
+
$this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
|
262 |
// Replace URLs
|
263 |
$result = $this->db->query(
|
264 |
$this->db->prepare(
|
265 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
266 |
)
|
267 |
);
|
268 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
269 |
|
270 |
|
271 |
// All good
|
272 |
+
if( $result ) {
|
|
|
273 |
return true;
|
274 |
}
|
275 |
|
296 |
return true;
|
297 |
}
|
298 |
|
299 |
+
// $result = $this->db->query(
|
300 |
+
// $this->db->prepare(
|
301 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'", "true"
|
302 |
+
// )
|
303 |
+
// );
|
304 |
$delete = $this->db->query(
|
305 |
$this->db->prepare(
|
306 |
"DELETE FROM `{$this->prefix}options` WHERE `option_name` = %s;", 'wpstg_is_staging_site'
|
316 |
)
|
317 |
);
|
318 |
//}
|
|
|
319 |
// All good
|
320 |
if( $insert ) {
|
321 |
$this->log( "Preparing Data Step2: Successfull", Logger::TYPE_INFO );
|
388 |
|
389 |
if( !$update ) {
|
390 |
$this->log( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
|
391 |
+
$this->returnException( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}" );
|
392 |
return false;
|
393 |
}
|
394 |
|
402 |
* @return bool
|
403 |
*/
|
404 |
protected function step5() {
|
405 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
406 |
|
407 |
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
|
408 |
if( false === ($content = file_get_contents( $path )) ) {
|
414 |
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
|
415 |
|
416 |
// Replace URLs
|
417 |
+
$content = str_replace( $this->homeUrl, $this->getStagingSiteUrl(), $content );
|
418 |
|
419 |
if( false === @file_put_contents( $path, $content ) ) {
|
420 |
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
|
438 |
return true;
|
439 |
}
|
440 |
|
441 |
+
$path = $this->options->destinationDir . "index.php";
|
442 |
|
443 |
if( false === ($content = file_get_contents( $path )) ) {
|
444 |
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
|
470 |
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
471 |
return false;
|
472 |
}
|
473 |
+
$this->Log( "Preparing Data Step 6: Finished successfully" );
|
474 |
return true;
|
475 |
}
|
476 |
|
501 |
|
502 |
// All good
|
503 |
if( $result ) {
|
504 |
+
$this->Log( "Preparing Data Step7: Finished successfully" );
|
505 |
return true;
|
506 |
}
|
507 |
|
536 |
|
537 |
// All good
|
538 |
if( $result ) {
|
539 |
+
$this->Log( "Preparing Data Step8: Finished successfully" );
|
540 |
return true;
|
541 |
}
|
542 |
|
570 |
|
571 |
// All good
|
572 |
if( $result ) {
|
573 |
+
$this->Log( "Preparing Data Step9: Finished successfully" );
|
574 |
return true;
|
575 |
}
|
576 |
|
583 |
* @return bool
|
584 |
*/
|
585 |
protected function step10() {
|
586 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
587 |
|
588 |
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
589 |
|
616 |
$this->log( "Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR );
|
617 |
return false;
|
618 |
}
|
619 |
+
$this->Log( "Preparing Data Step 10: Finished successfully" );
|
620 |
return true;
|
621 |
}
|
622 |
|
625 |
* @return bool
|
626 |
*/
|
627 |
protected function step11() {
|
628 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
629 |
|
630 |
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
|
631 |
|
659 |
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
660 |
return false;
|
661 |
}
|
662 |
+
$this->Log( "Preparing Data Step 11: Finished successfully" );
|
663 |
return true;
|
664 |
}
|
665 |
|
666 |
/**
|
667 |
+
* Set true WP_DEBUG & WP_DEBUG_DISPLAY in wp-config.php
|
668 |
+
* @return bool
|
669 |
+
*/
|
670 |
+
// protected function step12() {
|
671 |
+
// $path = $this->getAbsDestination() . $this->options->cloneDirectoryName . "/wp-config.php";
|
672 |
+
//
|
673 |
+
// $this->log( "Preparing Data Step12: Set WP_DEBUG to true in wp-config.php." );
|
674 |
+
//
|
675 |
+
// if( false === ($content = file_get_contents( $path )) ) {
|
676 |
+
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
677 |
+
// return false;
|
678 |
+
// }
|
679 |
+
//
|
680 |
+
//
|
681 |
+
// // Get WP_DEBUG from wp-config.php
|
682 |
+
// preg_match( "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/", $content, $matches );
|
683 |
+
//
|
684 |
+
// // Found it!
|
685 |
+
// if( !empty( $matches[1] ) ) {
|
686 |
+
// $matches[1];
|
687 |
+
//
|
688 |
+
// $pattern = "/define\s*\(\s*'WP_DEBUG'\s*,\s*(.*)\s*\);/";
|
689 |
+
//
|
690 |
+
// $replace = "define('WP_DEBUG',true); // " . $matches[1];
|
691 |
+
// $replace.= " // Changed by WP-Staging";
|
692 |
+
//
|
693 |
+
// if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
694 |
+
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
|
695 |
+
// return false;
|
696 |
+
// }
|
697 |
+
// } else {
|
698 |
+
// $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
|
699 |
+
// }
|
700 |
+
//
|
701 |
+
//
|
702 |
+
//
|
703 |
+
// // Get WP_DEBUG_DISPLAY
|
704 |
+
// preg_match( "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/", $content, $matches );
|
705 |
+
//
|
706 |
+
// // Found it!
|
707 |
+
// if( !empty( $matches[1] ) ) {
|
708 |
+
// $matches[1];
|
709 |
+
//
|
710 |
+
// $pattern = "/define\s*\(\s*'WP_DEBUG_DISPLAY'\s*,\s*(.*)\s*\);/";
|
711 |
+
//
|
712 |
+
// $replace = "define('WP_DEBUG_DISPLAY',true); // " . $matches[1];
|
713 |
+
// $replace.= " // Changed by WP-Staging";
|
714 |
+
//
|
715 |
+
// if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
716 |
+
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG", Logger::TYPE_ERROR );
|
717 |
+
// return false;
|
718 |
+
// }
|
719 |
+
// } else {
|
720 |
+
// $this->log( "Preparing Data Step12: WP_DEBUG not defined in wp-config.php. Skip it." );
|
721 |
+
// }
|
722 |
+
//
|
723 |
+
//
|
724 |
+
// if( false === @file_put_contents( $path, $content ) ) {
|
725 |
+
// $this->log( "Preparing Data Step12: Failed to update WP_DEBUG. Can't save content in wp-config.php", Logger::TYPE_ERROR );
|
726 |
+
// return false;
|
727 |
+
// }
|
728 |
+
// $this->Log( "Preparing Data: Finished Step 12 successfully" );
|
729 |
+
// return true;
|
730 |
+
// }
|
731 |
+
|
732 |
+
/**
|
733 |
* Update Table Prefix in wp_options
|
734 |
* @return bool
|
735 |
*/
|
747 |
return true;
|
748 |
}
|
749 |
|
750 |
+
$notice = !empty( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
|
|
|
|
|
751 |
|
752 |
+
//$this->log( "Updating option_name in {$this->prefix}options. {$notice}" );
|
753 |
// Filter the rows below. Do not update them!
|
754 |
$filters = array(
|
755 |
'wp_mail_smtp',
|
771 |
);
|
772 |
|
773 |
if( !$updateOptions ) {
|
774 |
+
$this->log( "Preparing Data Step12: Failed to update option_name in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR );
|
775 |
$this->returnException( " Preparing Data Step12: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
776 |
return false;
|
777 |
}
|
778 |
+
$this->Log( "Preparing Data Step 12: Finished successfully" );
|
779 |
return true;
|
780 |
}
|
781 |
|
794 |
$newUploadPath = $this->getNewUploadPath();
|
795 |
|
796 |
if( false === $newUploadPath ) {
|
797 |
+
$this->log( "Preparing Data Step13: Skipped" );
|
798 |
return true;
|
799 |
}
|
800 |
|
801 |
// Skip - Table is not selected or updated
|
802 |
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
803 |
+
$this->log( "Preparing Data Step13: Skipped" );
|
804 |
return true;
|
805 |
}
|
806 |
|
818 |
$this->log( "Preparing Data Step13: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
819 |
return true;
|
820 |
}
|
821 |
+
$this->Log( "Preparing Data Step 13: Finished successfully" );
|
822 |
return true;
|
823 |
}
|
824 |
|
827 |
* @return bool
|
828 |
*/
|
829 |
protected function step14() {
|
830 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
831 |
|
832 |
$this->log( "Preparing Data Step14: Set WP_CACHE in wp-config.php to false" );
|
833 |
|
860 |
$this->log( "Preparing Data Step14: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
|
861 |
return false;
|
862 |
}
|
863 |
+
$this->Log( "Preparing Data Step 14: Finished successfully" );
|
864 |
return true;
|
865 |
}
|
866 |
|
873 |
|
874 |
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
|
875 |
|
876 |
+
$newUploadPath = $this->options->destinationDir . $customSlug;
|
877 |
|
878 |
return $newUploadPath;
|
879 |
}
|
883 |
* @return string
|
884 |
*/
|
885 |
protected function getStagingSiteUrl() {
|
886 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
887 |
+
return $this->options->cloneHostname;
|
888 |
+
}
|
889 |
if( $this->isSubDir() ) {
|
890 |
+
return trailingslashit( $this->homeUrl ) . trailingslashit( $this->getSubDir() ) . $this->options->cloneDirectoryName;
|
891 |
}
|
892 |
|
893 |
+
return trailingslashit( $this->homeUrl ) . $this->options->cloneDirectoryName;
|
894 |
}
|
895 |
|
896 |
/**
|
901 |
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
902 |
// This is happening much more often than you would expect
|
903 |
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
904 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
905 |
|
906 |
if( $home !== $siteurl ) {
|
907 |
return true;
|
909 |
return false;
|
910 |
}
|
911 |
|
912 |
+
/**
|
913 |
+
* Get the install sub directory if WP is installed in sub directory
|
914 |
+
* @return string
|
915 |
+
*/
|
916 |
+
protected function getSubDir() {
|
917 |
+
$home = get_option( 'home' );
|
918 |
+
$siteurl = get_option( 'siteurl' );
|
919 |
+
|
920 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
921 |
+
return '';
|
922 |
+
}
|
923 |
+
|
924 |
+
$dir = str_replace( $home, '', $siteurl );
|
925 |
+
return str_replace( '/', '', $dir );
|
926 |
+
}
|
927 |
+
|
928 |
}
|
@@ -38,12 +38,18 @@ class Delete extends Job {
|
|
38 |
* @var object
|
39 |
*/
|
40 |
public $wpdb;
|
|
|
|
|
|
|
|
|
|
|
41 |
private $isExternal;
|
42 |
|
|
|
|
|
43 |
public function __construct( $isExternal = false ) {
|
44 |
parent::__construct();
|
45 |
$this->isExternal = $isExternal;
|
46 |
-
//$this->wpdb = WPStaging::getInstance()->get("wpdb");
|
47 |
}
|
48 |
|
49 |
/**
|
@@ -74,6 +80,10 @@ class Delete extends Job {
|
|
74 |
return new \wpdb( $this->clone->databaseUser, $this->clone->databasePassword, $this->clone->databaseDatabase, $this->clone->databaseServer );
|
75 |
}
|
76 |
|
|
|
|
|
|
|
|
|
77 |
public function getDbName() {
|
78 |
return $this->wpdb->dbname;
|
79 |
}
|
38 |
* @var object
|
39 |
*/
|
40 |
public $wpdb;
|
41 |
+
|
42 |
+
/**
|
43 |
+
*
|
44 |
+
* @var bool
|
45 |
+
*/
|
46 |
private $isExternal;
|
47 |
|
48 |
+
|
49 |
+
|
50 |
public function __construct( $isExternal = false ) {
|
51 |
parent::__construct();
|
52 |
$this->isExternal = $isExternal;
|
|
|
53 |
}
|
54 |
|
55 |
/**
|
80 |
return new \wpdb( $this->clone->databaseUser, $this->clone->databasePassword, $this->clone->databaseDatabase, $this->clone->databaseServer );
|
81 |
}
|
82 |
|
83 |
+
/**
|
84 |
+
* Date database name
|
85 |
+
* @return type
|
86 |
+
*/
|
87 |
public function getDbName() {
|
88 |
return $this->wpdb->dbname;
|
89 |
}
|
@@ -68,8 +68,6 @@ class Directories extends JobExecutable {
|
|
68 |
return ( object ) $this->response;
|
69 |
}
|
70 |
|
71 |
-
|
72 |
-
|
73 |
/**
|
74 |
* Step 0
|
75 |
* Get WP Root files
|
@@ -94,14 +92,13 @@ class Directories extends JobExecutable {
|
|
94 |
if( $this->write( $files, $iterator->getFilename() . PHP_EOL ) ) {
|
95 |
$this->options->totalFiles++;
|
96 |
|
97 |
-
//
|
98 |
-
|
99 |
}
|
100 |
}
|
101 |
}
|
102 |
} catch ( \Exception $e ) {
|
103 |
$this->returnException( 'Error: ' . $e->getMessage() );
|
104 |
-
//throw new \Exception('Out of disk space.');
|
105 |
} catch ( \Exception $e ) {
|
106 |
// Skip bad file permissions
|
107 |
}
|
@@ -118,7 +115,7 @@ class Directories extends JobExecutable {
|
|
118 |
|
119 |
// Skip it
|
120 |
if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
|
121 |
-
|
122 |
return true;
|
123 |
}
|
124 |
// open file handle
|
@@ -127,9 +124,7 @@ class Directories extends JobExecutable {
|
|
127 |
$excludeWpContent = array(
|
128 |
'cache',
|
129 |
'wps-hide-login',
|
130 |
-
|
131 |
-
'nbproject',
|
132 |
-
'.idea'
|
133 |
);
|
134 |
|
135 |
try {
|
@@ -153,8 +148,8 @@ class Directories extends JobExecutable {
|
|
153 |
if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
154 |
$this->options->totalFiles++;
|
155 |
|
156 |
-
//
|
157 |
-
|
158 |
}
|
159 |
}
|
160 |
}
|
@@ -179,7 +174,7 @@ class Directories extends JobExecutable {
|
|
179 |
|
180 |
// Skip it
|
181 |
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
|
182 |
-
|
183 |
return true;
|
184 |
}
|
185 |
|
@@ -205,8 +200,8 @@ class Directories extends JobExecutable {
|
|
205 |
if( $this->write( $files, 'wp-includes' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
206 |
$this->options->totalFiles++;
|
207 |
|
208 |
-
//
|
209 |
-
|
210 |
}
|
211 |
}
|
212 |
}
|
@@ -231,7 +226,7 @@ class Directories extends JobExecutable {
|
|
231 |
|
232 |
// Skip it
|
233 |
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
|
234 |
-
|
235 |
return true;
|
236 |
}
|
237 |
|
@@ -256,8 +251,8 @@ class Directories extends JobExecutable {
|
|
256 |
if( $item->isFile() ) {
|
257 |
if( $this->write( $files, 'wp-admin' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
258 |
$this->options->totalFiles++;
|
259 |
-
//
|
260 |
-
|
261 |
}
|
262 |
}
|
263 |
}
|
@@ -280,6 +275,9 @@ class Directories extends JobExecutable {
|
|
280 |
*/
|
281 |
private function getExtraFiles( $folder ) {
|
282 |
|
|
|
|
|
|
|
283 |
|
284 |
// open file handle and attach data to end of file
|
285 |
$files = $this->open( $this->filename, 'a' );
|
@@ -318,8 +316,8 @@ class Directories extends JobExecutable {
|
|
318 |
//if( $this->write( $files, $strings->getLastElemAfterString( '/', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
319 |
if( $this->write( $files, str_replace( \WPStaging\WPStaging::getWPpath(), '', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
320 |
$this->options->totalFiles++;
|
321 |
-
//
|
322 |
-
|
323 |
}
|
324 |
}
|
325 |
}
|
@@ -332,43 +330,6 @@ class Directories extends JobExecutable {
|
|
332 |
// close the file handler
|
333 |
$this->close( $files );
|
334 |
return true;
|
335 |
-
|
336 |
-
|
337 |
-
// Skip it
|
338 |
-
// if ($this->isDirectoryExcluded(ABSPATH)){
|
339 |
-
// return true;
|
340 |
-
// }
|
341 |
-
// // open file handle
|
342 |
-
// $files = $this->open($this->filename, 'a');
|
343 |
-
//
|
344 |
-
//
|
345 |
-
// try {
|
346 |
-
//
|
347 |
-
// // Iterate over wp root directory
|
348 |
-
// $iterator = new \DirectoryIterator(ABSPATH);
|
349 |
-
//
|
350 |
-
// $this->log( "Scanning ".ABSPATH." for its sub-directories and files" );
|
351 |
-
//
|
352 |
-
// // Write path line
|
353 |
-
// foreach ($iterator as $item) {
|
354 |
-
// if (!$item->isDot() && $item->isFile()) {
|
355 |
-
// if ($this->write($files, $iterator->getFilename() . PHP_EOL)) {
|
356 |
-
// $this->options->totalFiles++;
|
357 |
-
//
|
358 |
-
// // Add current file size
|
359 |
-
// $this->options->totalFileSize += $iterator->getSize();
|
360 |
-
// }
|
361 |
-
// }
|
362 |
-
// }
|
363 |
-
// } catch (\Exception $e) {
|
364 |
-
// $this->returnException('Error: ' . $e->getMessage());
|
365 |
-
// //throw new \Exception('Out of disk space.');
|
366 |
-
// } catch (\Exception $e) {
|
367 |
-
// // Skip bad file permissions
|
368 |
-
// }
|
369 |
-
//
|
370 |
-
// $this->close($files);
|
371 |
-
// return true;
|
372 |
}
|
373 |
|
374 |
/**
|
@@ -513,7 +474,6 @@ class Directories extends JobExecutable {
|
|
513 |
$this->files = explode( PHP_EOL, $this->files );
|
514 |
}
|
515 |
|
516 |
-
|
517 |
/**
|
518 |
* Replace forward slash with current directory separator
|
519 |
*
|
@@ -535,7 +495,7 @@ class Directories extends JobExecutable {
|
|
535 |
$directory = $this->sanitizeDirectorySeparator( $directory );
|
536 |
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
|
537 |
$excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
|
538 |
-
|
539 |
return true;
|
540 |
}
|
541 |
}
|
68 |
return ( object ) $this->response;
|
69 |
}
|
70 |
|
|
|
|
|
71 |
/**
|
72 |
* Step 0
|
73 |
* Get WP Root files
|
92 |
if( $this->write( $files, $iterator->getFilename() . PHP_EOL ) ) {
|
93 |
$this->options->totalFiles++;
|
94 |
|
95 |
+
// Too much cpu time
|
96 |
+
//$this->options->totalFileSize += $iterator->getSize();
|
97 |
}
|
98 |
}
|
99 |
}
|
100 |
} catch ( \Exception $e ) {
|
101 |
$this->returnException( 'Error: ' . $e->getMessage() );
|
|
|
102 |
} catch ( \Exception $e ) {
|
103 |
// Skip bad file permissions
|
104 |
}
|
115 |
|
116 |
// Skip it
|
117 |
if( $this->isDirectoryExcluded( WP_CONTENT_DIR ) ) {
|
118 |
+
$this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-content' . DIRECTORY_SEPARATOR );
|
119 |
return true;
|
120 |
}
|
121 |
// open file handle
|
124 |
$excludeWpContent = array(
|
125 |
'cache',
|
126 |
'wps-hide-login',
|
127 |
+
'node_modules'
|
|
|
|
|
128 |
);
|
129 |
|
130 |
try {
|
148 |
if( $this->write( $files, 'wp-content' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
149 |
$this->options->totalFiles++;
|
150 |
|
151 |
+
// Too much cpu time
|
152 |
+
//$this->options->totalFileSize += $iterator->getSize();
|
153 |
}
|
154 |
}
|
155 |
}
|
174 |
|
175 |
// Skip it
|
176 |
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR ) ) {
|
177 |
+
$this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-includes' . DIRECTORY_SEPARATOR );
|
178 |
return true;
|
179 |
}
|
180 |
|
200 |
if( $this->write( $files, 'wp-includes' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
201 |
$this->options->totalFiles++;
|
202 |
|
203 |
+
// Too much cpu time
|
204 |
+
//$this->options->totalFileSize += $iterator->getSize();
|
205 |
}
|
206 |
}
|
207 |
}
|
226 |
|
227 |
// Skip it
|
228 |
if( $this->isDirectoryExcluded( \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR ) ) {
|
229 |
+
$this->log( "Skip " . \WPStaging\WPStaging::getWPpath() . 'wp-admin' . DIRECTORY_SEPARATOR );
|
230 |
return true;
|
231 |
}
|
232 |
|
251 |
if( $item->isFile() ) {
|
252 |
if( $this->write( $files, 'wp-admin' . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
253 |
$this->options->totalFiles++;
|
254 |
+
// Too much cpu time
|
255 |
+
//$this->options->totalFileSize += $iterator->getSize();
|
256 |
}
|
257 |
}
|
258 |
}
|
275 |
*/
|
276 |
private function getExtraFiles( $folder ) {
|
277 |
|
278 |
+
if( !is_dir( $folder ) ) {
|
279 |
+
return true;
|
280 |
+
}
|
281 |
|
282 |
// open file handle and attach data to end of file
|
283 |
$files = $this->open( $this->filename, 'a' );
|
316 |
//if( $this->write( $files, $strings->getLastElemAfterString( '/', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
317 |
if( $this->write( $files, str_replace( \WPStaging\WPStaging::getWPpath(), '', $folder ) . DIRECTORY_SEPARATOR . $iterator->getSubPathName() . PHP_EOL ) ) {
|
318 |
$this->options->totalFiles++;
|
319 |
+
// Too much cpu time
|
320 |
+
//$this->options->totalFileSize += $iterator->getSize();
|
321 |
}
|
322 |
}
|
323 |
}
|
330 |
// close the file handler
|
331 |
$this->close( $files );
|
332 |
return true;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
}
|
334 |
|
335 |
/**
|
474 |
$this->files = explode( PHP_EOL, $this->files );
|
475 |
}
|
476 |
|
|
|
477 |
/**
|
478 |
* Replace forward slash with current directory separator
|
479 |
*
|
495 |
$directory = $this->sanitizeDirectorySeparator( $directory );
|
496 |
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
|
497 |
$excludedDirectory = $this->sanitizeDirectorySeparator( $excludedDirectory );
|
498 |
+
if( strpos( trailingslashit( $directory ), trailingslashit( $excludedDirectory ) ) === 0 ) {
|
499 |
return true;
|
500 |
}
|
501 |
}
|
@@ -7,7 +7,7 @@ use WPStaging\WPStaging;
|
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
if( !defined( "WPINC" ) ) {
|
10 |
-
|
11 |
}
|
12 |
|
13 |
/**
|
@@ -16,352 +16,390 @@ if( !defined( "WPINC" ) ) {
|
|
16 |
*/
|
17 |
class Files extends JobExecutable {
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
}
|
135 |
-
|
136 |
-
return true;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Checks Whether There is Any Job to Execute or Not
|
141 |
-
* @return bool
|
142 |
-
*/
|
143 |
-
private function isFinished() {
|
144 |
-
return (
|
145 |
-
$this->options->currentStep > $this->options->totalSteps ||
|
146 |
-
$this->options->copiedFiles >= $this->options->totalFiles
|
147 |
-
);
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* @param string $file
|
152 |
-
* @return bool
|
153 |
-
*/
|
154 |
-
private function copyFile( $file ) {
|
155 |
-
$file = trim( \WPStaging\WPStaging::getWPpath() . $file );
|
156 |
-
|
157 |
-
$directory = dirname( $file );
|
158 |
-
|
159 |
-
// Directory is excluded
|
160 |
-
if( $this->isDirectoryExcluded( $directory ) ) {
|
161 |
-
$this->debugLog( "Directory Excluded: {$file}", Logger::TYPE_INFO );
|
162 |
-
return false;
|
163 |
-
}
|
164 |
-
|
165 |
-
// File is excluded
|
166 |
-
if( $this->isFileExcluded( $file ) ) {
|
167 |
-
$this->debugLog( "File excluded: {$file}", Logger::TYPE_INFO );
|
168 |
-
return false;
|
169 |
-
}
|
170 |
-
|
171 |
-
// Path + File is excluded
|
172 |
-
if( $this->isFileExcludedFullPath( $file ) ) {
|
173 |
-
$this->debugLog( "File Excluded Full Path: {$file}", Logger::TYPE_INFO );
|
174 |
-
return false;
|
175 |
-
}
|
176 |
-
|
177 |
-
|
178 |
-
// Invalid file, skipping it as if succeeded
|
179 |
-
if( !is_file( $file ) ) {
|
180 |
-
$this->debugLog( "Not a file {$file}" );
|
181 |
-
return true;
|
182 |
-
}
|
183 |
-
|
184 |
-
// Get file size
|
185 |
-
$fileSize = filesize( $file );
|
186 |
-
// File is over maximum allowed file size (8MB)
|
187 |
-
if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
|
188 |
-
$this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
|
189 |
-
return false;
|
190 |
-
}
|
191 |
-
// Invalid file, skipping it as if succeeded
|
192 |
-
if( !is_readable( $file ) ) {
|
193 |
-
$this->log( "Can't read file {$file}" );
|
194 |
-
return true;
|
195 |
-
}
|
196 |
-
|
197 |
-
// Failed to get destination
|
198 |
-
if( false === ($destination = $this->getDestination( $file )) ) {
|
199 |
-
$this->log( "Can't get the destination of {$file}" );
|
200 |
-
return false;
|
201 |
-
}
|
202 |
-
|
203 |
-
// File is over batch size
|
204 |
-
if( $fileSize >= $this->settings->batchSize ) {
|
205 |
-
$this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
|
206 |
-
return $this->copyBig( $file, $destination, $this->settings->batchSize );
|
207 |
-
}
|
208 |
-
|
209 |
-
// Attempt to copy
|
210 |
-
if( !@copy( $file, $destination ) ) {
|
211 |
-
$errors = error_get_last();
|
212 |
-
$this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
|
213 |
-
return false;
|
214 |
-
}
|
215 |
-
|
216 |
-
return true;
|
217 |
-
|
218 |
-
// Good old PHP
|
219 |
-
//return $this->copy($file, $destination);
|
220 |
-
}
|
221 |
-
|
222 |
-
/**
|
223 |
-
* Gets destination file and checks if the directory exists, if it does not attempts to create it.
|
224 |
-
* If creating destination directory fails, it returns false, gives destination full path otherwise
|
225 |
-
* @param string $file
|
226 |
-
* @return bool|string
|
227 |
-
*/
|
228 |
-
private function getDestination( $file ) {
|
229 |
-
$relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
|
230 |
-
$destinationPath = $this->destination . $relativePath;
|
231 |
-
$destinationDirectory = dirname( $destinationPath );
|
232 |
-
|
233 |
-
if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, 0755, true ) ) {
|
234 |
-
$this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
|
235 |
-
return false;
|
236 |
-
}
|
237 |
-
|
238 |
-
return $destinationPath;
|
239 |
-
}
|
240 |
-
|
241 |
-
/**
|
242 |
-
* Copy bigger files than $this->settings->batchSize
|
243 |
-
* @param string $src
|
244 |
-
* @param string $dst
|
245 |
-
* @param int $buffersize
|
246 |
-
* @return boolean
|
247 |
-
*/
|
248 |
-
private function copyBig( $src, $dst, $buffersize ) {
|
249 |
-
$src = fopen( $src, 'r' );
|
250 |
-
$dest = fopen( $dst, 'w' );
|
251 |
-
|
252 |
-
// Try first method:
|
253 |
-
while ( !feof( $src ) ) {
|
254 |
-
if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
|
255 |
-
$error = true;
|
256 |
-
}
|
257 |
-
}
|
258 |
-
// Try second method if first one failed
|
259 |
-
if( isset( $error ) && ($error === true) ) {
|
260 |
-
while ( !feof( $src ) ) {
|
261 |
-
if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
|
262 |
-
$this->log( "Can not copy big file; {$src} -> {$dest}" );
|
263 |
-
fclose( $src );
|
264 |
-
fclose( $dest );
|
265 |
-
return false;
|
266 |
}
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
306 |
return true;
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
return true;
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
/**
|
351 |
-
* Check if directory is an extra directory and should be copied
|
352 |
-
* @param string $directory
|
353 |
-
* @return boolean
|
354 |
-
*/
|
355 |
-
private function isExtraDirectory( $directory ) {
|
356 |
-
$directory = $this->sanitizeDirectorySeparator( $directory );
|
357 |
-
|
358 |
-
foreach ( $this->options->extraDirectories as $extraDirectory ) {
|
359 |
-
if( strpos( $directory, $this->sanitizeDirectorySeparator( $extraDirectory ) ) === 0 ) {
|
360 |
return true;
|
361 |
-
|
362 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
363 |
|
364 |
-
|
365 |
-
|
366 |
|
367 |
}
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
if( !defined( "WPINC" ) ) {
|
10 |
+
die;
|
11 |
}
|
12 |
|
13 |
/**
|
16 |
*/
|
17 |
class Files extends JobExecutable {
|
18 |
|
19 |
+
/**
|
20 |
+
* @var \SplFileObject
|
21 |
+
*/
|
22 |
+
private $file;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var int
|
26 |
+
*/
|
27 |
+
private $maxFilesPerRun;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
private $destination;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Initialization
|
36 |
+
*/
|
37 |
+
public function initialize() {
|
38 |
+
|
39 |
+
$this->destination = $this->options->destinationDir;
|
40 |
+
|
41 |
+
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
42 |
+
|
43 |
+
if( is_file( $filePath ) ) {
|
44 |
+
$this->file = new \SplFileObject( $filePath, 'r' );
|
45 |
+
}
|
46 |
+
|
47 |
+
// Informational logs
|
48 |
+
if( 0 == $this->options->currentStep ) {
|
49 |
+
$this->log( "Copying files..." );
|
50 |
+
}
|
51 |
+
|
52 |
+
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
53 |
+
$this->maxFilesPerRun = $this->settings->fileLimit;
|
54 |
+
//$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
59 |
+
* @return void
|
60 |
+
*/
|
61 |
+
protected function calculateTotalSteps() {
|
62 |
+
$this->options->totalSteps = ceil( $this->options->totalFiles / $this->maxFilesPerRun );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Execute the Current Step
|
67 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
68 |
+
* @return bool
|
69 |
+
*/
|
70 |
+
protected function execute() {
|
71 |
+
// Finished
|
72 |
+
if( $this->isFinished() ) {
|
73 |
+
$this->log( "Copying files finished" );
|
74 |
+
$this->prepareResponse( true, false );
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
// Get files and copy'em
|
79 |
+
if( !$this->getFilesAndCopy() ) {
|
80 |
+
$this->prepareResponse( false, false );
|
81 |
+
return false;
|
82 |
+
}
|
83 |
+
|
84 |
+
// Prepare and return response
|
85 |
+
$this->prepareResponse();
|
86 |
+
|
87 |
+
// Not finished
|
88 |
+
return true;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get files and copy
|
93 |
+
* @return bool
|
94 |
+
*/
|
95 |
+
private function getFilesAndCopy() {
|
96 |
+
// Over limits threshold
|
97 |
+
if( $this->isOverThreshold() ) {
|
98 |
+
// Prepare response and save current progress
|
99 |
+
$this->prepareResponse( false, false );
|
100 |
+
$this->saveOptions();
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
// Go to last copied line and than to next one
|
105 |
+
//if ($this->options->copiedFiles != 0) {
|
106 |
+
if( isset( $this->options->copiedFiles ) && $this->options->copiedFiles != 0 ) {
|
107 |
+
$this->file->seek( $this->options->copiedFiles - 1 );
|
108 |
+
}
|
109 |
+
|
110 |
+
$this->file->setFlags( \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD );
|
111 |
+
|
112 |
+
// Start time
|
113 |
+
//$start = microtime( true );
|
114 |
+
// Loop x files at a time
|
115 |
+
//$this->maxFilesPerRun = 300;
|
116 |
+
for ( $i = 0; $i < $this->maxFilesPerRun; $i++ ) {
|
117 |
+
|
118 |
+
// Reached timeout
|
119 |
+
// if( ( $timeout = apply_filters( 'wpstg_job_timeout', 10 ) ) ) {
|
120 |
+
// if( ( \microtime( true ) - $start ) > $timeout ) {
|
121 |
+
// // Prepare response and save current progress
|
122 |
+
// $this->prepareResponse( false, true );
|
123 |
+
// $this->saveOptions();
|
124 |
+
// return false;
|
125 |
+
// }
|
126 |
+
// }
|
127 |
+
// Increment copied files
|
128 |
+
// Do this anytime to make sure to not stuck in the same step / files
|
129 |
+
$this->options->copiedFiles++;
|
130 |
+
|
131 |
+
// End of file
|
132 |
+
if( $this->file->eof() ) {
|
133 |
+
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
+
|
136 |
+
$file = $this->file->fgets();
|
137 |
+
|
138 |
+
// if( false !== strpos( $file, 'index.php' ) ) {
|
139 |
+
// $test = $file;
|
140 |
+
// }
|
141 |
+
$this->copyFile( $file );
|
142 |
+
}
|
143 |
+
|
144 |
+
|
145 |
+
|
146 |
+
$totalFiles = $this->options->copiedFiles;
|
147 |
+
// Log this only every 50 entries to keep the log small and to not block the rendering browser
|
148 |
+
if( $this->options->copiedFiles % 50 == 0 ) {
|
149 |
+
$this->log( "Total {$totalFiles} files processed" );
|
150 |
+
}
|
151 |
+
|
152 |
+
return true;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Checks Whether There is Any Job to Execute or Not
|
157 |
+
* @return bool
|
158 |
+
*/
|
159 |
+
private function isFinished() {
|
160 |
+
return (
|
161 |
+
$this->options->currentStep > $this->options->totalSteps ||
|
162 |
+
$this->options->copiedFiles >= $this->options->totalFiles
|
163 |
+
);
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* @param string $file
|
168 |
+
* @return bool
|
169 |
+
*/
|
170 |
+
private function copyFile( $file ) {
|
171 |
+
|
172 |
+
$file = trim( \WPStaging\WPStaging::getWPpath() . $file );
|
173 |
+
|
174 |
+
$directory = dirname( $file );
|
175 |
+
|
176 |
+
// Directory is excluded
|
177 |
+
if( $this->isDirectoryExcluded( $directory ) ) {
|
178 |
+
$this->debugLog( "Skipping directory by rule: {$file}", Logger::TYPE_INFO );
|
179 |
+
return false;
|
180 |
+
}
|
181 |
+
|
182 |
+
// File is excluded
|
183 |
+
if( $this->isFileExcluded( $file ) ) {
|
184 |
+
$this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
// Path + File is excluded
|
188 |
+
if( $this->isFileExcludedFullPath( $file ) ) {
|
189 |
+
$this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
190 |
+
return false;
|
191 |
+
}
|
192 |
+
|
193 |
+
// Invalid file, skipping it as if succeeded
|
194 |
+
if( !is_file( $file ) ) {
|
195 |
+
$this->log( "File doesn't exist {$file}", Logger::TYPE_WARNING );
|
196 |
+
return true;
|
197 |
+
}
|
198 |
+
// Invalid file, skipping it as if succeeded
|
199 |
+
if( !is_readable( $file ) ) {
|
200 |
+
$this->log( "Can't read file {$file}", Logger::TYPE_WARNING );
|
201 |
return true;
|
202 |
+
}
|
203 |
+
|
204 |
+
|
205 |
+
// Get file size
|
206 |
+
$fileSize = filesize( $file );
|
207 |
+
|
208 |
+
// File is over maximum allowed file size (8MB)
|
209 |
+
if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
|
210 |
+
$this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
|
211 |
+
return false;
|
212 |
+
}
|
213 |
+
|
214 |
+
// Failed to get destination
|
215 |
+
if( false === ($destination = $this->getDestination( $file )) ) {
|
216 |
+
$this->log( "Can't get the destination of {$file}", Logger::TYPE_WARNING );
|
217 |
+
return false;
|
218 |
+
}
|
219 |
+
|
220 |
+
// File is over batch size
|
221 |
+
if( $fileSize >= $this->settings->batchSize ) {
|
222 |
+
$this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
|
223 |
+
return $this->copyBig( $file, $destination, $this->settings->batchSize );
|
224 |
+
}
|
225 |
+
|
226 |
+
// Attempt to copy
|
227 |
+
if( !@copy( $file, $destination ) ) {
|
228 |
+
$errors = error_get_last();
|
229 |
+
$this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
|
230 |
+
return false;
|
231 |
+
}
|
232 |
+
|
233 |
+
// Set file permissions
|
234 |
+
@chmod( $destination, wpstg_get_permissions_for_file() );
|
235 |
+
|
236 |
+
$this->setDirPermissions( $destination );
|
237 |
+
|
238 |
+
return true;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Set directory permissions
|
243 |
+
* @param type $file
|
244 |
+
* @return boolean
|
245 |
+
*/
|
246 |
+
private function setDirPermissions( $file ) {
|
247 |
+
$dir = dirname( $file );
|
248 |
+
if( is_dir( $dir ) ) {
|
249 |
+
@chmod( $dir, wpstg_get_permissions_for_directory() );
|
250 |
+
}
|
251 |
+
return false;
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Gets destination file and checks if the directory exists, if it does not attempts to create it.
|
256 |
+
* If creating destination directory fails, it returns false, gives destination full path otherwise
|
257 |
+
* @param string $file
|
258 |
+
* @return bool|string
|
259 |
+
*/
|
260 |
+
private function getDestination( $file ) {
|
261 |
+
|
262 |
+
$relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
|
263 |
+
$destinationPath = $this->destination . $relativePath;
|
264 |
+
$destinationDirectory = dirname( $destinationPath );
|
265 |
+
|
266 |
+
if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, wpstg_get_permissions_for_directory(), true ) ) {
|
267 |
+
$this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
|
268 |
+
return false;
|
269 |
+
}
|
270 |
+
|
271 |
+
return $this->sanitizeDirectorySeparator( $destinationPath );
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Copy bigger files than $this->settings->batchSize
|
276 |
+
* @param string $src
|
277 |
+
* @param string $dst
|
278 |
+
* @param int $buffersize
|
279 |
+
* @return boolean
|
280 |
+
*/
|
281 |
+
private function copyBig( $src, $dst, $buffersize ) {
|
282 |
+
$src = fopen( $src, 'r' );
|
283 |
+
$dest = fopen( $dst, 'w' );
|
284 |
+
|
285 |
+
// Try first method:
|
286 |
+
while ( !feof( $src ) ) {
|
287 |
+
if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
|
288 |
+
$error = true;
|
289 |
+
}
|
290 |
+
}
|
291 |
+
// Try second method if first one failed
|
292 |
+
if( isset( $error ) && ($error === true) ) {
|
293 |
+
while ( !feof( $src ) ) {
|
294 |
+
if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
|
295 |
+
$this->log( "Can not copy file; {$src} -> {$dest}" );
|
296 |
+
fclose( $src );
|
297 |
+
fclose( $dest );
|
298 |
+
return false;
|
299 |
+
}
|
300 |
+
}
|
301 |
+
}
|
302 |
+
// Close any open handler
|
303 |
+
fclose( $src );
|
304 |
+
fclose( $dest );
|
305 |
+
return true;
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Check if certain file is excluded from copying process
|
310 |
+
*
|
311 |
+
* @param string $file filename including ending without full path
|
312 |
+
* @return boolean
|
313 |
+
*/
|
314 |
+
private function isFileExcluded( $file ) {
|
315 |
+
// If file name exists
|
316 |
+
if( in_array( basename( $file ), $this->options->excludedFiles ) ) {
|
317 |
return true;
|
318 |
+
}
|
319 |
+
|
320 |
+
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
321 |
+
// because if the updating process fails, the staging site would not be accessable any longer
|
322 |
+
if( isset( $this->options->mainJob ) && $this->options->mainJob == "updating" && stripos( strrev( $file ), strrev( "wp-config.php" ) ) === 0 ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
323 |
return true;
|
324 |
+
}
|
325 |
+
|
326 |
+
|
327 |
+
return false;
|
328 |
+
}
|
329 |
+
|
330 |
+
/**
|
331 |
+
* Check if certain file is excluded from copying process
|
332 |
+
*
|
333 |
+
* @param string $file filename including ending + (part) path e.g wp-content/db.php
|
334 |
+
* @return boolean
|
335 |
+
*/
|
336 |
+
private function isFileExcludedFullPath( $file ) {
|
337 |
+
// If path + file exists
|
338 |
+
foreach ( $this->options->excludedFilesFullPath as $excludedFile ) {
|
339 |
+
if( false !== strpos( $file, $excludedFile ) ) {
|
340 |
+
return true;
|
341 |
+
}
|
342 |
+
}
|
343 |
+
|
344 |
+
return false;
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* Replace backward slash with forward slash directory separator
|
349 |
+
* Windows Compatibility Fix
|
350 |
+
*
|
351 |
+
* @param string $path Path
|
352 |
+
* @return string
|
353 |
+
*/
|
354 |
+
private function sanitizeDirectorySeparator( $path ) {
|
355 |
+
//$string = str_replace( '\\', '/', $path );
|
356 |
+
//$string = str_replace( "/", "\\", $path );
|
357 |
+
//return str_replace( '\\\\', '\\', $string );
|
358 |
+
//return preg_replace( '/[\\\\]+/', '\\\\\\\\', $string );
|
359 |
+
return preg_replace( '/[\\\\]+/', '/', $path );
|
360 |
+
}
|
361 |
+
|
362 |
+
/**
|
363 |
+
* Check if directory is excluded from copying
|
364 |
+
* @param string $directory
|
365 |
+
* @return bool
|
366 |
+
*/
|
367 |
+
private function isDirectoryExcluded( $directory ) {
|
368 |
+
// Make sure that wp-staging-pro directory / plugin is never excluded
|
369 |
+
if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
|
370 |
+
return false;
|
371 |
+
}
|
372 |
+
// $directory = wpstg_replace_windows_directory_separator( $directory );
|
373 |
+
// $directory = trailingslashit( $directory );
|
374 |
+
$directory = trailingslashit( $this->sanitizeDirectorySeparator( $directory ) );
|
375 |
+
|
376 |
+
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
|
377 |
+
// $excludedDirectory = wpstg_replace_windows_directory_separator( $excludedDirectory );
|
378 |
+
// $excludedDirectory = trailingslashit( $excludedDirectory );
|
379 |
+
$excludedDirectory = trailingslashit( $this->sanitizeDirectorySeparator( $excludedDirectory ) );
|
380 |
+
if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
|
381 |
+
return true;
|
382 |
+
}
|
383 |
+
}
|
384 |
+
|
385 |
+
return false;
|
386 |
+
}
|
387 |
+
|
388 |
+
/**
|
389 |
+
* Check if directory is an extra directory and should be copied
|
390 |
+
* @param string $directory
|
391 |
+
* @return boolean
|
392 |
+
*/
|
393 |
+
private function isExtraDirectory( $directory ) {
|
394 |
+
$directory = $this->sanitizeDirectorySeparator( $directory );
|
395 |
+
|
396 |
+
foreach ( $this->options->extraDirectories as $extraDirectory ) {
|
397 |
+
if( strpos( $directory, $this->sanitizeDirectorySeparator( $extraDirectory ) ) === 0 ) {
|
398 |
+
return true;
|
399 |
+
}
|
400 |
+
}
|
401 |
|
402 |
+
return false;
|
403 |
+
}
|
404 |
|
405 |
}
|
@@ -1,16 +1,15 @@
|
|
1 |
<?php
|
|
|
2 |
namespace WPStaging\Backend\Modules\Jobs;
|
3 |
|
4 |
use WPStaging\WPStaging;
|
5 |
|
6 |
-
//error_reporting( E_ALL );
|
7 |
-
|
8 |
/**
|
9 |
* Class Finish
|
10 |
* @package WPStaging\Backend\Modules\Jobs
|
11 |
*/
|
12 |
-
class Finish extends Job
|
13 |
-
|
14 |
/**
|
15 |
* Clone Key
|
16 |
* @var string
|
@@ -21,97 +20,138 @@ class Finish extends Job
|
|
21 |
* Start Module
|
22 |
* @return object
|
23 |
*/
|
24 |
-
public function start()
|
25 |
-
{
|
26 |
// sanitize the clone name before saving
|
27 |
-
$this->clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
28 |
-
|
29 |
// Delete Cache Files
|
30 |
$this->deleteCacheFiles();
|
31 |
|
32 |
// Prepare clone records & save scanned directories for delete job later
|
33 |
$this->prepareCloneDataRecords();
|
34 |
|
35 |
-
|
36 |
$return = array(
|
37 |
-
"directoryName"
|
38 |
-
"path"
|
39 |
-
"url"
|
40 |
-
"number"
|
41 |
-
"version"
|
42 |
-
"status"
|
43 |
-
"prefix"
|
44 |
-
"last_msg"
|
45 |
-
"job"
|
46 |
-
"percentage"
|
47 |
-
|
48 |
);
|
49 |
-
|
50 |
//$this->flush();
|
51 |
|
52 |
-
return (object) $return;
|
53 |
}
|
54 |
|
55 |
/**
|
56 |
* Delete Cache Files
|
57 |
*/
|
58 |
-
protected function deleteCacheFiles()
|
59 |
-
|
60 |
-
$this->log("Finish: Deleting clone job's cache files...");
|
61 |
|
62 |
// Clean cache files
|
63 |
-
$this->cache->delete("clone_options");
|
64 |
-
$this->cache->delete("files_to_copy");
|
65 |
|
66 |
-
$this->log("Finish: Clone job's cache files have been deleted!");
|
67 |
}
|
68 |
-
|
69 |
-
|
70 |
* Prepare clone records
|
71 |
* @return bool
|
72 |
*/
|
73 |
-
protected function prepareCloneDataRecords()
|
74 |
-
{
|
75 |
// Check if clones still exist
|
76 |
-
$this->log("Finish: Verifying existing clones...");
|
77 |
|
78 |
// Clone data already exists
|
79 |
-
if
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
$this->log("Finish: The job finished!");
|
84 |
return true;
|
85 |
}
|
86 |
|
87 |
// Save new clone data
|
88 |
-
$this->log("Finish: {$this->options->clone}'s clone job's data is not in database, generating data");
|
89 |
-
|
90 |
// sanitize the clone name before saving
|
91 |
//$clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
92 |
-
|
93 |
$this->options->existingClones[$this->clone] = array(
|
94 |
-
"directoryName"
|
95 |
-
"path"
|
96 |
-
"url"
|
97 |
-
"number"
|
98 |
-
"version"
|
99 |
-
"status"
|
100 |
-
"prefix"
|
101 |
-
"datetime"
|
102 |
-
"databaseUser"
|
103 |
-
"databasePassword"
|
104 |
-
"databaseDatabase"
|
105 |
-
"databaseServer"
|
106 |
-
"databasePrefix"
|
107 |
);
|
108 |
|
109 |
-
if
|
110 |
-
|
111 |
-
$this->log("Finish: Failed to save {$this->options->clone}'s clone job data to database'");
|
112 |
return false;
|
113 |
}
|
114 |
|
115 |
return true;
|
116 |
}
|
117 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
+
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
use WPStaging\WPStaging;
|
6 |
|
|
|
|
|
7 |
/**
|
8 |
* Class Finish
|
9 |
* @package WPStaging\Backend\Modules\Jobs
|
10 |
*/
|
11 |
+
class Finish extends Job {
|
12 |
+
|
13 |
/**
|
14 |
* Clone Key
|
15 |
* @var string
|
20 |
* Start Module
|
21 |
* @return object
|
22 |
*/
|
23 |
+
public function start() {
|
|
|
24 |
// sanitize the clone name before saving
|
25 |
+
$this->clone = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
|
26 |
+
|
27 |
// Delete Cache Files
|
28 |
$this->deleteCacheFiles();
|
29 |
|
30 |
// Prepare clone records & save scanned directories for delete job later
|
31 |
$this->prepareCloneDataRecords();
|
32 |
|
|
|
33 |
$return = array(
|
34 |
+
"directoryName" => $this->options->cloneDirectoryName,
|
35 |
+
"path" => trailingslashit( $this->options->destinationDir ),
|
36 |
+
"url" => $this->getDestinationUrl(),
|
37 |
+
"number" => $this->options->cloneNumber,
|
38 |
+
"version" => \WPStaging\WPStaging::VERSION,
|
39 |
+
"status" => 'finished',
|
40 |
+
"prefix" => $this->options->prefix,
|
41 |
+
"last_msg" => $this->logger->getLastLogMsg(),
|
42 |
+
"job" => $this->options->currentJob,
|
43 |
+
"percentage" => 100
|
|
|
44 |
);
|
45 |
+
|
46 |
//$this->flush();
|
47 |
|
48 |
+
return ( object ) $return;
|
49 |
}
|
50 |
|
51 |
/**
|
52 |
* Delete Cache Files
|
53 |
*/
|
54 |
+
protected function deleteCacheFiles() {
|
55 |
+
$this->log( "Finish: Deleting clone job's cache files..." );
|
|
|
56 |
|
57 |
// Clean cache files
|
58 |
+
$this->cache->delete( "clone_options" );
|
59 |
+
$this->cache->delete( "files_to_copy" );
|
60 |
|
61 |
+
$this->log( "Finish: Clone job's cache files have been deleted!" );
|
62 |
}
|
63 |
+
|
64 |
+
/**
|
65 |
* Prepare clone records
|
66 |
* @return bool
|
67 |
*/
|
68 |
+
protected function prepareCloneDataRecords() {
|
|
|
69 |
// Check if clones still exist
|
70 |
+
$this->log( "Finish: Verifying existing clones..." );
|
71 |
|
72 |
// Clone data already exists
|
73 |
+
if( isset( $this->options->existingClones[$this->options->clone] ) ) {
|
74 |
+
$this->options->existingClones[$this->options->clone]['datetime'] = time();
|
75 |
+
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
76 |
+
$this->log( "Finish: The job finished!" );
|
|
|
77 |
return true;
|
78 |
}
|
79 |
|
80 |
// Save new clone data
|
81 |
+
$this->log( "Finish: {$this->options->clone}'s clone job's data is not in database, generating data" );
|
82 |
+
|
83 |
// sanitize the clone name before saving
|
84 |
//$clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
85 |
+
|
86 |
$this->options->existingClones[$this->clone] = array(
|
87 |
+
"directoryName" => $this->options->cloneDirectoryName,
|
88 |
+
"path" => trailingslashit( $this->options->destinationDir ),
|
89 |
+
"url" => $this->getDestinationUrl(),
|
90 |
+
"number" => $this->options->cloneNumber,
|
91 |
+
"version" => \WPStaging\WPStaging::VERSION,
|
92 |
+
"status" => false,
|
93 |
+
"prefix" => $this->options->prefix,
|
94 |
+
"datetime" => time(),
|
95 |
+
"databaseUser" => $this->options->databaseUser,
|
96 |
+
"databasePassword" => $this->options->databasePassword,
|
97 |
+
"databaseDatabase" => $this->options->databaseDatabase,
|
98 |
+
"databaseServer" => $this->options->databaseServer,
|
99 |
+
"databasePrefix" => $this->options->databasePrefix
|
100 |
);
|
101 |
|
102 |
+
if( false === update_option( "wpstg_existing_clones_beta", $this->options->existingClones ) ) {
|
103 |
+
$this->log( "Finish: Failed to save {$this->options->clone}'s clone job data to database'" );
|
|
|
104 |
return false;
|
105 |
}
|
106 |
|
107 |
return true;
|
108 |
}
|
109 |
+
|
110 |
+
/**
|
111 |
+
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
112 |
+
* @return type
|
113 |
+
*/
|
114 |
+
private function getDestinationUrl() {
|
115 |
+
|
116 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
117 |
+
return $this->options->cloneHostname;
|
118 |
+
}
|
119 |
+
|
120 |
+
// if( isSubDir ) {
|
121 |
+
// return trailingslashit( get_site_url() ) . trailingslashit($this->getSubDir()) . $this->options->cloneDirectoryName;
|
122 |
+
// }
|
123 |
+
return trailingslashit( get_site_url() ) . $this->options->cloneDirectoryName;
|
124 |
+
}
|
125 |
+
|
126 |
+
/**
|
127 |
+
* Check if WP is installed in subdir
|
128 |
+
* @return boolean
|
129 |
+
*/
|
130 |
+
// private function isSubDir() {
|
131 |
+
// // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
132 |
+
// // This is happening much more often than you would expect
|
133 |
+
// $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
134 |
+
// $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
135 |
+
//
|
136 |
+
// if( $home !== $siteurl ) {
|
137 |
+
// return true;
|
138 |
+
// }
|
139 |
+
// return false;
|
140 |
+
// }
|
141 |
+
|
142 |
+
/**
|
143 |
+
* Get the install sub directory if WP is installed in sub directory
|
144 |
+
* @return string
|
145 |
+
*/
|
146 |
+
// private function getSubDir() {
|
147 |
+
// $home = get_option( 'home' );
|
148 |
+
// $siteurl = get_option( 'siteurl' );
|
149 |
+
//
|
150 |
+
// if( empty( $home ) || empty( $siteurl ) ) {
|
151 |
+
// return '';
|
152 |
+
// }
|
153 |
+
//
|
154 |
+
// $dir = str_replace( $home, '', $siteurl );
|
155 |
+
// return str_replace( '/', '', $dir );
|
156 |
+
// }
|
157 |
+
}
|
@@ -124,13 +124,8 @@ abstract class Job implements JobInterface {
|
|
124 |
$this->multisiteHomeDomain = $multisite->getHomeDomain();
|
125 |
$this->multisiteDomainWithoutScheme = $multisite->getHomeDomainWithoutScheme();
|
126 |
|
127 |
-
|
128 |
-
$this->maxExecutionTime = ( int ) 30;
|
129 |
|
130 |
-
// if ($this->maxExecutionTime < 1 || $this->maxExecutionTime > 30)
|
131 |
-
// {
|
132 |
-
// $this->maxExecutionTime = 30;
|
133 |
-
// }
|
134 |
// Services
|
135 |
$this->cache = new Cache( -1, \WPStaging\WPStaging::getContentDir() );
|
136 |
$this->logger = WPStaging::getInstance()->get( "logger" );
|
@@ -351,81 +346,6 @@ abstract class Job implements JobInterface {
|
|
351 |
return false;
|
352 |
}
|
353 |
|
354 |
-
/**
|
355 |
-
* Attempt to reset memory
|
356 |
-
* @return bool
|
357 |
-
* memory
|
358 |
-
*/
|
359 |
-
// protected function resetMemory()
|
360 |
-
// {
|
361 |
-
// $newMemoryLimit = $this->maxMemoryLimit * 2;
|
362 |
-
//
|
363 |
-
// // Failed to set
|
364 |
-
// if (false === ini_set("memory_limit", $this->formatBytes($newMemoryLimit)))
|
365 |
-
// {
|
366 |
-
// $this->log('Can not free some memory', Logger::TYPE_CRITICAL);
|
367 |
-
// return false;
|
368 |
-
// }
|
369 |
-
//
|
370 |
-
// // Double checking
|
371 |
-
// $newMemoryLimit = $this->getMemoryInBytes(@ini_get("memory_limit"));
|
372 |
-
// if ($newMemoryLimit <= $this->maxMemoryLimit)
|
373 |
-
// {
|
374 |
-
// return false;
|
375 |
-
// }
|
376 |
-
//
|
377 |
-
// // Set the new Maximum memory limit
|
378 |
-
// $this->maxMemoryLimit = $newMemoryLimit;
|
379 |
-
//
|
380 |
-
// // Calculate threshold limit
|
381 |
-
// $this->memoryLimit = $newMemoryLimit * self::MAX_MEMORY_RATIO;
|
382 |
-
//
|
383 |
-
// return true;
|
384 |
-
// }
|
385 |
-
|
386 |
-
/**
|
387 |
-
* Attempt to reset time
|
388 |
-
* @return bool
|
389 |
-
*
|
390 |
-
* @deprecated since version 2.0.0
|
391 |
-
|
392 |
-
*/
|
393 |
-
// protected function resetTime()
|
394 |
-
// {
|
395 |
-
// // Attempt to reset timeout
|
396 |
-
// if (!@set_time_limit($this->maxExecutionTime))
|
397 |
-
// {
|
398 |
-
// return false;
|
399 |
-
// }
|
400 |
-
//
|
401 |
-
// // Increase execution limit
|
402 |
-
// $this->executionLimit = $this->executionLimit * 2;
|
403 |
-
//
|
404 |
-
// return true;
|
405 |
-
// }
|
406 |
-
|
407 |
-
/**
|
408 |
-
* Reset time limit and memory
|
409 |
-
* @return bool
|
410 |
-
*
|
411 |
-
* @deprecated since version 2.0.0
|
412 |
-
*/
|
413 |
-
// protected function reset()
|
414 |
-
// {
|
415 |
-
// // Attempt to reset time
|
416 |
-
// if (!$this->resetTime())
|
417 |
-
// {
|
418 |
-
// return false;
|
419 |
-
// }
|
420 |
-
//
|
421 |
-
// // Attempt to reset memory
|
422 |
-
// if (!$this->resetMemory())
|
423 |
-
// {
|
424 |
-
// return false;
|
425 |
-
// }
|
426 |
-
//
|
427 |
-
// return true;
|
428 |
-
// }
|
429 |
|
430 |
/**
|
431 |
* Checks if calls are over recursion limit
|
124 |
$this->multisiteHomeDomain = $multisite->getHomeDomain();
|
125 |
$this->multisiteDomainWithoutScheme = $multisite->getHomeDomainWithoutScheme();
|
126 |
|
127 |
+
$this->maxExecutionTime = ( int ) 10;
|
|
|
128 |
|
|
|
|
|
|
|
|
|
129 |
// Services
|
130 |
$this->cache = new Cache( -1, \WPStaging\WPStaging::getContentDir() );
|
131 |
$this->logger = WPStaging::getInstance()->get( "logger" );
|
346 |
return false;
|
347 |
}
|
348 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
349 |
|
350 |
/**
|
351 |
* Checks if calls are over recursion limit
|
@@ -4,7 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
@@ -20,947 +20,990 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
20 |
*/
|
21 |
class Data extends JobExecutable {
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
205 |
$errors = error_get_last();
|
206 |
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
207 |
return true;
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
$this->
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
-
|
437 |
-
|
438 |
-
|
439 |
-
|
440 |
-
|
441 |
-
|
442 |
-
}
|
443 |
-
|
444 |
-
if( false === @file_put_contents( $path, $content ) ) {
|
445 |
-
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
446 |
-
return false;
|
447 |
-
}
|
448 |
-
$this->Log( "Preparing Data: Finished Step 6 successfully" );
|
449 |
-
return true;
|
450 |
-
}
|
451 |
-
|
452 |
-
/**
|
453 |
-
* Update wpstg_rmpermalinks_executed
|
454 |
-
* @return bool
|
455 |
-
*/
|
456 |
-
protected function step7() {
|
457 |
-
|
458 |
-
$this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
|
459 |
-
|
460 |
-
// Skip - Table does not exist
|
461 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
462 |
-
return true;
|
463 |
-
}
|
464 |
-
|
465 |
-
// Skip - Table is not selected or updated
|
466 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
467 |
-
$this->log( "Preparing Data Step7: Skipping" );
|
468 |
-
return true;
|
469 |
-
}
|
470 |
-
|
471 |
-
$result = $this->db->query(
|
472 |
-
$this->db->prepare(
|
473 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'", ' '
|
474 |
-
)
|
475 |
-
);
|
476 |
-
|
477 |
-
// All good
|
478 |
-
if( $result ) {
|
479 |
-
$this->Log( "Preparing Data Step7: Finished Step 7 successfully" );
|
480 |
-
return true;
|
481 |
-
}
|
482 |
-
|
483 |
-
$this->log( "Failed to update wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_WARNING );
|
484 |
-
return true;
|
485 |
-
}
|
486 |
-
|
487 |
-
/**
|
488 |
-
* Update permalink_structure
|
489 |
-
* @return bool
|
490 |
-
*/
|
491 |
-
protected function step8() {
|
492 |
-
|
493 |
-
$this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
|
494 |
-
|
495 |
-
// Skip - Table does not exist
|
496 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
497 |
-
return true;
|
498 |
-
}
|
499 |
-
|
500 |
-
// Skip - Table is not selected or updated
|
501 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
502 |
-
$this->log( "Preparing Data Step8: Skipping" );
|
503 |
-
return true;
|
504 |
-
}
|
505 |
-
|
506 |
-
$result = $this->db->query(
|
507 |
-
$this->db->prepare(
|
508 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
|
509 |
-
)
|
510 |
-
);
|
511 |
-
|
512 |
-
// All good
|
513 |
-
if( $result ) {
|
514 |
-
$this->Log( "Preparing Data Step8: Finished Step 8 successfully" );
|
515 |
-
return true;
|
516 |
-
}
|
517 |
-
|
518 |
-
$this->log( "Failed to update permalink_structure in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
519 |
-
return true;
|
520 |
-
}
|
521 |
-
|
522 |
-
/**
|
523 |
-
* Update blog_public option to not allow staging site to be indexed by search engines
|
524 |
-
* @return bool
|
525 |
-
*/
|
526 |
-
protected function step9() {
|
527 |
-
|
528 |
-
$this->log( "Preparing Data Step9: Set staging site to noindex" );
|
529 |
-
|
530 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
531 |
-
return true;
|
532 |
-
}
|
533 |
-
|
534 |
-
// Skip - Table is not selected or updated
|
535 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
536 |
-
$this->log( "Preparing Data Step9: Skipping" );
|
537 |
-
return true;
|
538 |
-
}
|
539 |
-
|
540 |
-
$result = $this->db->query(
|
541 |
-
$this->db->prepare(
|
542 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
|
543 |
-
)
|
544 |
-
);
|
545 |
-
|
546 |
-
// All good
|
547 |
-
if( $result ) {
|
548 |
-
$this->Log( "Preparing Data Step9: Finished Step 9 successfully" );
|
549 |
-
return true;
|
550 |
-
}
|
551 |
-
|
552 |
-
$this->log( "Can not update staging site to noindex. Possible already done!", Logger::TYPE_WARNING );
|
553 |
-
return true;
|
554 |
-
}
|
555 |
-
|
556 |
-
/**
|
557 |
-
* Update WP_HOME in wp-config.php
|
558 |
-
* @return bool
|
559 |
-
*/
|
560 |
-
protected function step10() {
|
561 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
562 |
-
|
563 |
-
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
564 |
-
|
565 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
566 |
-
$this->log( "Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
567 |
-
return false;
|
568 |
-
}
|
569 |
-
|
570 |
-
|
571 |
-
// Get WP_HOME from wp-config.php
|
572 |
-
preg_match( "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
573 |
-
|
574 |
-
if( !empty( $matches[1] ) ) {
|
575 |
-
$matches[1];
|
576 |
-
|
577 |
-
$pattern = "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/";
|
578 |
-
|
579 |
-
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
580 |
-
$replace.= " // Changed by WP-Staging";
|
581 |
-
|
582 |
-
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
583 |
$this->log( "Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR );
|
584 |
return false;
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
589 |
|
590 |
-
if( false === @file_put_contents( $path, $content ) ) {
|
591 |
-
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
592 |
-
return false;
|
593 |
-
}
|
594 |
-
$this->Log( "Preparing Data: Finished Step 11 successfully" );
|
595 |
-
return true;
|
596 |
-
}
|
597 |
|
598 |
-
|
599 |
-
|
600 |
-
* @return bool
|
601 |
-
*/
|
602 |
-
protected function step11() {
|
603 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
604 |
|
605 |
-
|
|
|
606 |
|
607 |
-
|
608 |
-
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
609 |
-
return false;
|
610 |
-
}
|
611 |
|
|
|
|
|
612 |
|
613 |
-
|
614 |
-
|
|
|
|
|
|
|
|
|
|
|
615 |
|
616 |
-
|
617 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
618 |
|
619 |
-
$pattern = "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/";
|
620 |
|
621 |
-
|
622 |
-
|
623 |
|
624 |
-
|
625 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
626 |
return false;
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
631 |
|
|
|
|
|
632 |
|
633 |
-
|
634 |
-
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
635 |
-
return false;
|
636 |
-
}
|
637 |
-
$this->Log( "Preparing Data: Finished Step 11 successfully" );
|
638 |
-
return true;
|
639 |
-
}
|
640 |
|
641 |
-
|
642 |
-
|
643 |
-
* @return bool
|
644 |
-
*/
|
645 |
-
protected function step12() {
|
646 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
647 |
|
648 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
649 |
|
650 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
651 |
-
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
652 |
-
return false;
|
653 |
-
}
|
654 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
655 |
|
656 |
-
// Get WP_SITEURL from wp-config.php
|
657 |
-
preg_match( "/define\s*\(\s*'WP_ALLOW_MULTISITE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
658 |
|
659 |
-
|
660 |
-
|
661 |
|
662 |
-
|
|
|
663 |
|
664 |
-
|
665 |
-
$replace.= " // Changed by WP-Staging";
|
666 |
|
667 |
-
|
668 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
669 |
return false;
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
|
|
|
|
|
|
|
|
|
|
|
675 |
|
676 |
-
if( false === @file_put_contents( $path, $content ) ) {
|
677 |
-
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
678 |
-
return false;
|
679 |
-
}
|
680 |
-
$this->Log( "Preparing Data: Finished Step 12 successfully" );
|
681 |
-
return true;
|
682 |
-
}
|
683 |
|
684 |
-
|
685 |
-
* Update MULTISITE constant in wp-config.php
|
686 |
-
* @return bool
|
687 |
-
*/
|
688 |
-
protected function step13() {
|
689 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
690 |
|
691 |
-
|
|
|
|
|
|
|
|
|
692 |
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
|
|
697 |
|
|
|
|
|
698 |
|
699 |
-
|
700 |
-
|
|
|
|
|
|
|
|
|
701 |
|
702 |
-
|
703 |
-
|
|
|
|
|
704 |
|
705 |
-
|
|
|
706 |
|
707 |
-
|
708 |
-
$replace.= " // Changed by WP-Staging";
|
709 |
|
710 |
-
|
711 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
712 |
return false;
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
if( false === @file_put_contents( $path, $content ) ) {
|
720 |
-
$this->log( "Preparing Data Step13: Failed to update MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
721 |
-
return false;
|
722 |
-
}
|
723 |
-
$this->Log( "Preparing Data: Finished Step 13 successfully" );
|
724 |
-
return true;
|
725 |
-
}
|
726 |
-
|
727 |
-
/**
|
728 |
-
* Get active_sitewide_plugins from wp_sitemeta and active_plugins from subsite
|
729 |
-
* Merge both arrays and copy them to the staging site into active_plugins
|
730 |
-
*/
|
731 |
-
protected function step14() {
|
732 |
-
|
733 |
-
|
734 |
-
$this->log( "Data Crunching Step 14: Updating active_plugins" );
|
735 |
-
|
736 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
737 |
-
$this->log( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
738 |
-
$this->returnException( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
739 |
-
return false;
|
740 |
-
}
|
741 |
-
|
742 |
-
// Skip - Table is not selected or updated
|
743 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
744 |
-
$this->log( "Preparing Data Step14: Skipping" );
|
745 |
-
return true;
|
746 |
-
}
|
747 |
-
|
748 |
-
// Get active_plugins value from sub site options table
|
749 |
-
$active_plugins = $this->db->get_var( "SELECT option_value FROM {$this->db->prefix}options WHERE option_name = 'active_plugins' " );
|
750 |
-
|
751 |
-
if( !$active_plugins ) {
|
752 |
-
$this->log( "Data Crunching Step 14: Option active_plugins are empty " );
|
753 |
-
$active_plugins = array();
|
754 |
-
}
|
755 |
-
// Get active_sitewide_plugins value from main multisite wp_sitemeta table
|
756 |
-
$active_sitewide_plugins = $this->db->get_var( "SELECT meta_value FROM {$this->db->base_prefix}sitemeta WHERE meta_key = 'active_sitewide_plugins' " );
|
757 |
-
|
758 |
-
if( !$active_sitewide_plugins ) {
|
759 |
-
$this->log( "Data Crunching Step 14: Options {$this->db->base_prefix}active_sitewide_plugins is empty " );
|
760 |
-
$active_sitewide_plugins = array();
|
761 |
-
}
|
762 |
-
|
763 |
-
$active_sitewide_plugins = unserialize( $active_sitewide_plugins );
|
764 |
-
$active_plugins = unserialize( $active_plugins );
|
765 |
-
|
766 |
-
$all_plugins = array_merge( $active_plugins, array_keys( $active_sitewide_plugins ) );
|
767 |
-
|
768 |
-
sort( $all_plugins );
|
769 |
-
|
770 |
-
|
771 |
-
// Update active_plugins
|
772 |
-
$update = $this->db->query(
|
773 |
-
"UPDATE {$this->prefix}options SET option_value = '" . serialize( $all_plugins ) . "' WHERE option_name = 'active_plugins'"
|
774 |
-
);
|
775 |
-
|
776 |
-
if( false === $update ) {
|
777 |
-
$this->log( "Data Crunching Step 14: Can not update option active_plugins in {$this->prefix}options", Logger::TYPE_WARNING );
|
778 |
-
return false;
|
779 |
-
}
|
780 |
-
|
781 |
-
$this->log( "Data Crunching Step 14: Successfull!" );
|
782 |
-
return true;
|
783 |
-
}
|
784 |
-
|
785 |
-
/**
|
786 |
-
* Update Table Prefix in wp_options
|
787 |
-
* @return bool
|
788 |
-
*/
|
789 |
-
protected function step15() {
|
790 |
-
$this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options." );
|
791 |
-
|
792 |
-
// Skip - Table does not exist
|
793 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
794 |
-
return true;
|
795 |
-
}
|
796 |
-
|
797 |
-
// Skip - Table is not selected or updated
|
798 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
799 |
-
$this->log( "Preparing Data Step4: Skipping" );
|
800 |
-
return true;
|
801 |
-
}
|
802 |
-
|
803 |
-
|
804 |
-
$this->log( "Updating db option_names in {$this->prefix}options. " );
|
805 |
-
|
806 |
-
// Filter the rows below. Do not update them!
|
807 |
-
$filters = array(
|
808 |
-
'wp_mail_smtp',
|
809 |
-
'wp_mail_smtp_version',
|
810 |
-
'wp_mail_smtp_debug',
|
811 |
-
);
|
812 |
-
|
813 |
-
$filters = apply_filters( 'wpstg_data_excl_rows', $filters );
|
814 |
-
|
815 |
-
$where = "";
|
816 |
-
foreach ( $filters as $filter ) {
|
817 |
-
$where .= " AND option_name <> '" . $filter . "'";
|
818 |
-
}
|
819 |
-
|
820 |
-
$updateOptions = $this->db->query(
|
821 |
-
$this->db->prepare(
|
822 |
-
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
823 |
-
)
|
824 |
-
);
|
825 |
-
|
826 |
-
if( !$updateOptions ) {
|
827 |
-
$this->log( "Preparing Data Step15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR );
|
828 |
-
$this->returnException( "Data Crunching Step 15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
829 |
-
return false;
|
830 |
-
}
|
831 |
|
832 |
-
|
833 |
-
|
834 |
-
|
835 |
-
|
836 |
-
|
837 |
-
|
838 |
-
*/
|
839 |
-
protected function step16() {
|
840 |
-
$this->log( "Preparing Data Step16: Updating upload_path {$this->prefix}options." );
|
841 |
-
|
842 |
-
// Skip - Table does not exist
|
843 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
844 |
-
return true;
|
845 |
-
}
|
846 |
-
|
847 |
-
$newUploadPath = $this->getNewUploadPath();
|
848 |
-
|
849 |
-
if( false === $newUploadPath ) {
|
850 |
-
$this->log( "Preparing Data Step16: Skipping" );
|
851 |
-
return true;
|
852 |
-
}
|
853 |
-
|
854 |
-
// Skip - Table is not selected or updated
|
855 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
856 |
-
$this->log( "Preparing Data Step16: Skipping" );
|
857 |
-
return true;
|
858 |
-
}
|
859 |
|
860 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
861 |
|
862 |
-
|
863 |
|
864 |
-
|
865 |
-
|
866 |
-
|
867 |
-
|
868 |
-
);
|
869 |
-
|
870 |
-
if( !$updateOptions ) {
|
871 |
-
$this->log( "Preparing Data Step16: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
872 |
-
return true;
|
873 |
-
}
|
874 |
-
$this->Log( "Preparing Data: Finished Step 16 successfully" );
|
875 |
-
return true;
|
876 |
-
}
|
877 |
-
|
878 |
-
/**
|
879 |
-
* Update WP_CACHE in wp-config.php
|
880 |
-
* @return bool
|
881 |
-
*/
|
882 |
-
protected function step17() {
|
883 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
884 |
-
|
885 |
-
$this->log( "Preparing Data Step17: Set WP_CACHE in wp-config.php to false" );
|
886 |
-
|
887 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
888 |
-
$this->log( "Preparing Data Step17: Failed to update WP_CACHE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
889 |
-
return false;
|
890 |
-
}
|
891 |
|
|
|
|
|
|
|
|
|
|
|
892 |
|
893 |
-
|
894 |
-
preg_match( "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
895 |
-
|
896 |
-
if( !empty( $matches[1] ) ) {
|
897 |
-
$matches[1];
|
898 |
-
|
899 |
-
$pattern = "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/";
|
900 |
|
901 |
-
|
902 |
-
$replace.= " // Changed by WP-Staging";
|
903 |
|
904 |
-
|
905 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
906 |
return false;
|
907 |
-
|
908 |
-
|
909 |
-
|
910 |
-
|
911 |
-
|
912 |
-
|
913 |
-
|
914 |
-
|
915 |
-
|
916 |
-
|
917 |
-
|
918 |
-
|
919 |
-
|
920 |
-
|
921 |
-
|
922 |
-
|
923 |
-
|
924 |
-
|
925 |
-
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
|
933 |
-
|
934 |
-
|
935 |
-
|
936 |
-
|
937 |
-
|
938 |
-
|
939 |
-
|
940 |
-
|
941 |
-
|
942 |
-
|
943 |
-
|
944 |
-
|
945 |
-
|
946 |
-
|
947 |
-
|
948 |
-
|
949 |
-
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
|
955 |
-
|
956 |
-
|
957 |
-
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
965 |
|
966 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
20 |
*/
|
21 |
class Data extends JobExecutable {
|
22 |
|
23 |
+
/**
|
24 |
+
* @var \wpdb
|
25 |
+
*/
|
26 |
+
private $db;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
private $prefix;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Tables e.g wpstg3_options
|
35 |
+
* @var array
|
36 |
+
*/
|
37 |
+
private $tables;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Initialize
|
41 |
+
*/
|
42 |
+
public function initialize() {
|
43 |
+
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
44 |
+
|
45 |
+
$this->prefix = $this->options->prefix;
|
46 |
+
|
47 |
+
$this->getTables();
|
48 |
+
|
49 |
+
// Fix current step
|
50 |
+
if( 0 == $this->options->currentStep ) {
|
51 |
+
$this->options->currentStep = 0;
|
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 = 18;
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Start Module
|
79 |
+
* @return object
|
80 |
+
*/
|
81 |
+
public function start() {
|
82 |
+
// Execute steps
|
83 |
+
$this->run();
|
84 |
+
|
85 |
+
// Save option, progress
|
86 |
+
$this->saveOptions();
|
87 |
+
|
88 |
+
return ( object ) $this->response;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Execute the Current Step
|
93 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
94 |
+
* @return bool
|
95 |
+
*/
|
96 |
+
protected function execute() {
|
97 |
+
// Fatal error. Let this happen never and break here immediately
|
98 |
+
if( $this->isRoot() ) {
|
99 |
+
return false;
|
100 |
+
}
|
101 |
+
|
102 |
+
// Over limits threshold
|
103 |
+
if( $this->isOverThreshold() ) {
|
104 |
+
// Prepare response and save current progress
|
105 |
+
$this->prepareResponse( false, false );
|
106 |
+
$this->saveOptions();
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
|
110 |
+
// No more steps, finished
|
111 |
+
if( $this->isFinished() ) {
|
112 |
+
$this->prepareResponse( true, false );
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
|
116 |
+
// Execute step
|
117 |
+
$stepMethodName = "step" . $this->options->currentStep;
|
118 |
+
if( !$this->{$stepMethodName}() ) {
|
119 |
+
$this->prepareResponse( false, false );
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
+
// Prepare Response
|
124 |
+
$this->prepareResponse();
|
125 |
+
|
126 |
+
// Not finished
|
127 |
+
return true;
|
128 |
+
}
|
129 |
+
|
130 |
+
/**
|
131 |
+
* Checks Whether There is Any Job to Execute or Not
|
132 |
+
* @return bool
|
133 |
+
*/
|
134 |
+
protected function isFinished() {
|
135 |
+
return (
|
136 |
+
$this->options->currentStep > $this->options->totalSteps ||
|
137 |
+
!method_exists( $this, "step" . $this->options->currentStep )
|
138 |
+
);
|
139 |
+
}
|
140 |
+
|
141 |
+
/**
|
142 |
+
* Check if current operation is done on the root folder or on the live DB
|
143 |
+
* @return boolean
|
144 |
+
*/
|
145 |
+
protected function isRoot() {
|
146 |
+
|
147 |
+
// Prefix is the same as the one of live site
|
148 |
+
//$wpdb = WPStaging::getInstance()->get( "wpdb" );
|
149 |
+
if( $this->db->prefix === $this->prefix ) {
|
150 |
+
return true;
|
151 |
+
}
|
152 |
+
|
153 |
+
// CloneName is empty
|
154 |
+
$name = ( array ) $this->options->cloneDirectoryName;
|
155 |
+
if( empty( $name ) ) {
|
156 |
+
return true;
|
157 |
+
}
|
158 |
+
|
159 |
+
// Live domain === Staging domain
|
160 |
+
if( $this->multisiteHomeDomain . $this->options->cloneDirectoryName === $this->multisiteHomeDomain ) {
|
161 |
+
return true;
|
162 |
+
}
|
163 |
+
|
164 |
+
return false;
|
165 |
+
}
|
166 |
+
|
167 |
+
/**
|
168 |
+
* Check if table exists
|
169 |
+
* @param string $table
|
170 |
+
* @return boolean
|
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;
|
178 |
+
}
|
179 |
+
|
180 |
+
/**
|
181 |
+
* Return absolute destination path
|
182 |
+
* @return string
|
183 |
+
*/
|
184 |
+
// private function getAbsDestination() {
|
185 |
+
// if( empty( $this->options->cloneDir ) ) {
|
186 |
+
// return \WPStaging\WPStaging::getWPpath();
|
187 |
+
// }
|
188 |
+
// return trailingslashit( $this->options->cloneDir );
|
189 |
+
// }
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Copy wp-config.php if it is located outside of root one level up
|
193 |
+
* @todo Needs some more testing before it will be released
|
194 |
+
* @return boolean
|
195 |
+
*/
|
196 |
+
protected function step0() {
|
197 |
+
$this->log( "Preparing Data Step0: Check if wp-config.php is located in root path", Logger::TYPE_INFO );
|
198 |
+
|
199 |
+
$dir = trailingslashit( dirname( ABSPATH ) );
|
200 |
+
|
201 |
+
$source = $dir . 'wp-config.php';
|
202 |
+
|
203 |
+
$destination = $this->options->destinationDir . 'wp-config.php';
|
204 |
+
|
205 |
+
|
206 |
+
// Do not do anything
|
207 |
+
if( (!is_file( $source ) && !is_link( $source )) || is_file( $destination ) ) {
|
208 |
+
$this->log( "Preparing Data Step0: Skip it", Logger::TYPE_INFO );
|
209 |
+
return true;
|
210 |
+
}
|
211 |
+
|
212 |
+
// Copy target of a symbolic link
|
213 |
+
if( is_link( $source ) ) {
|
214 |
+
$this->log( "Preparing Data Step0: Symbolic link found...", Logger::TYPE_INFO );
|
215 |
+
if( !@copy( readlink( $source ), $destination ) ) {
|
216 |
+
$errors = error_get_last();
|
217 |
+
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
218 |
+
return true;
|
219 |
+
}
|
220 |
+
}
|
221 |
+
|
222 |
+
// Copy file wp-config.php
|
223 |
+
if( !@copy( $source, $destination ) ) {
|
224 |
$errors = error_get_last();
|
225 |
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
226 |
return true;
|
227 |
+
}
|
228 |
+
$this->log( "Preparing Data Step0: Successfull", Logger::TYPE_INFO );
|
229 |
+
return true;
|
230 |
+
}
|
231 |
+
|
232 |
+
/**
|
233 |
+
* Replace "siteurl" and "home"
|
234 |
+
* @return bool
|
235 |
+
*/
|
236 |
+
protected function step1() {
|
237 |
+
$this->log( "Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
|
238 |
+
|
239 |
+
// Skip - Table does not exist
|
240 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
241 |
+
return true;
|
242 |
+
}
|
243 |
+
// Skip - Table is not selected or updated
|
244 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
245 |
+
$this->log( "Preparing Data Step1: Skipping" );
|
246 |
+
return true;
|
247 |
+
}
|
248 |
+
|
249 |
+
// Installed in sub-directory
|
250 |
+
// if( $this->isSubDir() ) {
|
251 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName );
|
252 |
+
// // Replace URLs
|
253 |
+
// $result = $this->db->query(
|
254 |
+
// $this->db->prepare(
|
255 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName
|
256 |
+
// )
|
257 |
+
// );
|
258 |
+
// } else
|
259 |
+
// {
|
260 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName );
|
261 |
+
// // Replace URLs
|
262 |
+
// $result = $this->db->query(
|
263 |
+
// $this->db->prepare(
|
264 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName
|
265 |
+
// )
|
266 |
+
// );
|
267 |
+
// }
|
268 |
+
|
269 |
+
$this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
|
270 |
+
// Replace URLs
|
271 |
+
$result = $this->db->query(
|
272 |
+
$this->db->prepare(
|
273 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
274 |
+
)
|
275 |
+
);
|
276 |
+
|
277 |
+
|
278 |
+
|
279 |
+
// All good
|
280 |
+
if( $result ) {
|
281 |
+
return true;
|
282 |
+
}
|
283 |
+
|
284 |
+
$this->log( "Preparing Data Step1: Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
285 |
+
return false;
|
286 |
+
}
|
287 |
+
|
288 |
+
/**
|
289 |
+
* Update "wpstg_is_staging_site"
|
290 |
+
* @return bool
|
291 |
+
*/
|
292 |
+
protected function step2() {
|
293 |
+
|
294 |
+
$this->log( "Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
|
295 |
+
|
296 |
+
// Skip - Table does not exist
|
297 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
298 |
+
return true;
|
299 |
+
}
|
300 |
+
// Skip - Table is not selected or updated
|
301 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
302 |
+
$this->log( "Preparing Data Step2: Skipping" );
|
303 |
+
return true;
|
304 |
+
}
|
305 |
+
|
306 |
+
$result = $this->db->query(
|
307 |
+
$this->db->prepare(
|
308 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'", "true"
|
309 |
+
)
|
310 |
+
);
|
311 |
+
|
312 |
+
// No errors but no option name such as wpstg_is_staging_site
|
313 |
+
if( '' === $this->db->last_error && 0 == $result ) {
|
314 |
+
$result = $this->db->query(
|
315 |
+
$this->db->prepare(
|
316 |
+
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)", "true"
|
317 |
+
)
|
318 |
+
);
|
319 |
+
}
|
320 |
+
|
321 |
+
// All good
|
322 |
+
if( $result ) {
|
323 |
+
return true;
|
324 |
+
}
|
325 |
+
|
326 |
+
$this->log( "Preparing Data Step2: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
327 |
+
return false;
|
328 |
+
}
|
329 |
+
|
330 |
+
/**
|
331 |
+
* Update rewrite_rules
|
332 |
+
* @return bool
|
333 |
+
*/
|
334 |
+
protected function step3() {
|
335 |
+
|
336 |
+
$this->log( "Preparing Data Step3: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}" );
|
337 |
+
|
338 |
+
// Skip - Table does not exist
|
339 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
340 |
+
return true;
|
341 |
+
}
|
342 |
+
|
343 |
+
// Skip - Table is not selected or updated
|
344 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
345 |
+
$this->log( "Preparing Data Step3: Skipping" );
|
346 |
+
return true;
|
347 |
+
}
|
348 |
+
|
349 |
+
$result = $this->db->query(
|
350 |
+
$this->db->prepare(
|
351 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'", ' '
|
352 |
+
)
|
353 |
+
);
|
354 |
+
|
355 |
+
// All good
|
356 |
+
if( $result ) {
|
357 |
+
return true;
|
358 |
+
}
|
359 |
+
|
360 |
+
$this->log( "Preparing Data Step3: Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
361 |
+
return true;
|
362 |
+
}
|
363 |
+
|
364 |
+
/**
|
365 |
+
* Update Table Prefix in wp_usermeta and wp_options
|
366 |
+
* @return bool
|
367 |
+
*/
|
368 |
+
protected function step4() {
|
369 |
+
$this->log( "Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. {$this->db->last_error}" );
|
370 |
+
|
371 |
+
// Skip - Table does not exist
|
372 |
+
if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
|
373 |
+
return true;
|
374 |
+
}
|
375 |
+
|
376 |
+
// Skip - Table is not selected or updated
|
377 |
+
if( !in_array( $this->prefix . 'usermeta', $this->tables ) ) {
|
378 |
+
$this->log( "Preparing Data Step4: Skipping" );
|
379 |
+
return true;
|
380 |
+
}
|
381 |
+
|
382 |
+
$update = $this->db->query(
|
383 |
+
$this->db->prepare(
|
384 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
385 |
+
)
|
386 |
+
);
|
387 |
+
|
388 |
+
if( !$update ) {
|
389 |
+
$this->log( "Preparing Data Step4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_ERROR );
|
390 |
+
$this->returnException( "Data Crunching Step 4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}" );
|
391 |
+
return false;
|
392 |
+
}
|
393 |
+
return true;
|
394 |
+
}
|
395 |
+
|
396 |
+
/**
|
397 |
+
* Update $table_prefix in wp-config.php
|
398 |
+
* @return bool
|
399 |
+
*/
|
400 |
+
protected function step5() {
|
401 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
402 |
+
|
403 |
+
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
|
404 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
405 |
+
$this->log( "Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR );
|
406 |
+
return false;
|
407 |
+
}
|
408 |
+
|
409 |
+
// Replace table prefix
|
410 |
+
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
|
411 |
+
|
412 |
+
// Replace URLs
|
413 |
+
$content = str_replace( $this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content );
|
414 |
+
|
415 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
416 |
+
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
|
417 |
+
return false;
|
418 |
+
}
|
419 |
+
|
420 |
+
return true;
|
421 |
+
}
|
422 |
+
|
423 |
+
/**
|
424 |
+
* Reset index.php to original file
|
425 |
+
* This is needed if live site is located in subfolder
|
426 |
+
* Check first if main wordpress is used in subfolder and index.php in parent directory
|
427 |
+
* @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
|
428 |
+
* @return bool
|
429 |
+
*/
|
430 |
+
protected function step6() {
|
431 |
+
|
432 |
+
if( !$this->isSubDir() ) {
|
433 |
+
$this->debugLog( "Preparing Data Step6: WP installation is not in a subdirectory! All good, skipping this step" );
|
434 |
+
return true;
|
435 |
+
}
|
436 |
+
|
437 |
+
$path = $this->options->destinationDir . "index.php";
|
438 |
+
|
439 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
440 |
+
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
|
441 |
+
return false;
|
442 |
+
}
|
443 |
+
|
444 |
+
|
445 |
+
if( !preg_match( "/(require(.*)wp-blog-header.php' \);)/", $content, $matches ) ) {
|
446 |
+
$this->log(
|
447 |
+
"Preparing Data Step6: Failed to reset index.php for sub directory; wp-blog-header.php is missing", Logger::TYPE_ERROR
|
448 |
+
);
|
449 |
+
return false;
|
450 |
+
}
|
451 |
+
$this->log( "Preparing Data: WP installation is in a subdirectory. Progressing..." );
|
452 |
+
|
453 |
+
$pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
|
454 |
+
|
455 |
+
$replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
|
456 |
+
$replace.= " // Changed by WP-Staging";
|
457 |
+
|
458 |
+
|
459 |
+
|
460 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
461 |
$this->log( "Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR );
|
462 |
return false;
|
463 |
+
}
|
464 |
+
|
465 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
466 |
+
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
467 |
+
return false;
|
468 |
+
}
|
469 |
+
$this->Log( "Preparing Data: Finished Step 6 successfully" );
|
470 |
+
return true;
|
471 |
+
}
|
472 |
+
|
473 |
+
/**
|
474 |
+
* Update wpstg_rmpermalinks_executed
|
475 |
+
* @return bool
|
476 |
+
*/
|
477 |
+
protected function step7() {
|
478 |
+
|
479 |
+
$this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
|
480 |
+
|
481 |
+
// Skip - Table does not exist
|
482 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
483 |
+
return true;
|
484 |
+
}
|
485 |
+
|
486 |
+
// Skip - Table is not selected or updated
|
487 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
488 |
+
$this->log( "Preparing Data Step7: Skipping" );
|
489 |
+
return true;
|
490 |
+
}
|
491 |
+
|
492 |
+
$result = $this->db->query(
|
493 |
+
$this->db->prepare(
|
494 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'", ' '
|
495 |
+
)
|
496 |
+
);
|
497 |
+
|
498 |
+
// All good
|
499 |
+
if( $result ) {
|
500 |
+
$this->Log( "Preparing Data Step7: Finished Step 7 successfully" );
|
501 |
+
return true;
|
502 |
+
}
|
503 |
+
|
504 |
+
$this->log( "Failed to update wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_WARNING );
|
505 |
+
return true;
|
506 |
+
}
|
507 |
+
|
508 |
+
/**
|
509 |
+
* Update permalink_structure
|
510 |
+
* @return bool
|
511 |
+
*/
|
512 |
+
protected function step8() {
|
513 |
+
|
514 |
+
$this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
|
515 |
+
|
516 |
+
// Skip - Table does not exist
|
517 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
518 |
+
return true;
|
519 |
+
}
|
520 |
+
|
521 |
+
// Skip - Table is not selected or updated
|
522 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
523 |
+
$this->log( "Preparing Data Step8: Skipping" );
|
524 |
+
return true;
|
525 |
+
}
|
526 |
+
|
527 |
+
$result = $this->db->query(
|
528 |
+
$this->db->prepare(
|
529 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
|
530 |
+
)
|
531 |
+
);
|
532 |
+
|
533 |
+
// All good
|
534 |
+
if( $result ) {
|
535 |
+
$this->Log( "Preparing Data Step8: Finished Step 8 successfully" );
|
536 |
+
return true;
|
537 |
+
}
|
538 |
+
|
539 |
+
$this->log( "Failed to update permalink_structure in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
540 |
+
return true;
|
541 |
+
}
|
542 |
+
|
543 |
+
/**
|
544 |
+
* Update blog_public option to not allow staging site to be indexed by search engines
|
545 |
+
* @return bool
|
546 |
+
*/
|
547 |
+
protected function step9() {
|
548 |
+
|
549 |
+
$this->log( "Preparing Data Step9: Set staging site to noindex" );
|
550 |
+
|
551 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
552 |
+
return true;
|
553 |
+
}
|
554 |
+
|
555 |
+
// Skip - Table is not selected or updated
|
556 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
557 |
+
$this->log( "Preparing Data Step9: Skipping" );
|
558 |
+
return true;
|
559 |
+
}
|
560 |
+
|
561 |
+
$result = $this->db->query(
|
562 |
+
$this->db->prepare(
|
563 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
|
564 |
+
)
|
565 |
+
);
|
566 |
+
|
567 |
+
// All good
|
568 |
+
if( $result ) {
|
569 |
+
$this->Log( "Preparing Data Step9: Finished Step 9 successfully" );
|
570 |
+
return true;
|
571 |
+
}
|
572 |
+
|
573 |
+
$this->log( "Can not update staging site to noindex. Possible already done!", Logger::TYPE_WARNING );
|
574 |
+
return true;
|
575 |
+
}
|
576 |
+
|
577 |
+
/**
|
578 |
+
* Update WP_HOME in wp-config.php
|
579 |
+
* @return bool
|
580 |
+
*/
|
581 |
+
protected function step10() {
|
582 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
583 |
+
|
584 |
+
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
585 |
+
|
586 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
587 |
+
$this->log( "Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
588 |
+
return false;
|
589 |
+
}
|
590 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
591 |
|
592 |
+
// Get WP_HOME from wp-config.php
|
593 |
+
preg_match( "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
|
|
|
|
|
|
|
|
594 |
|
595 |
+
if( !empty( $matches[1] ) ) {
|
596 |
+
$matches[1];
|
597 |
|
598 |
+
$pattern = "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/";
|
|
|
|
|
|
|
599 |
|
600 |
+
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
601 |
+
$replace.= " // Changed by WP-Staging";
|
602 |
|
603 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
604 |
+
$this->log( "Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR );
|
605 |
+
return false;
|
606 |
+
}
|
607 |
+
} else {
|
608 |
+
$this->log( "Preparing Data Step10: WP_HOME not defined in wp-config.php. Skipping this step." );
|
609 |
+
}
|
610 |
|
611 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
612 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
613 |
+
return false;
|
614 |
+
}
|
615 |
+
$this->Log( "Preparing Data: Finished Step 11 successfully" );
|
616 |
+
return true;
|
617 |
+
}
|
618 |
+
|
619 |
+
/**
|
620 |
+
* Update WP_SITEURL in wp-config.php
|
621 |
+
* @return bool
|
622 |
+
*/
|
623 |
+
protected function step11() {
|
624 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
625 |
+
|
626 |
+
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
|
627 |
+
|
628 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
629 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
630 |
+
return false;
|
631 |
+
}
|
632 |
|
|
|
633 |
|
634 |
+
// Get WP_SITEURL from wp-config.php
|
635 |
+
preg_match( "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/", $content, $matches );
|
636 |
|
637 |
+
if( !empty( $matches[1] ) ) {
|
638 |
+
$matches[1];
|
639 |
+
|
640 |
+
$pattern = "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/";
|
641 |
+
|
642 |
+
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
643 |
+
$replace.= " // Changed by WP-Staging";
|
644 |
+
|
645 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
646 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL", Logger::TYPE_ERROR );
|
647 |
+
return false;
|
648 |
+
}
|
649 |
+
} else {
|
650 |
+
$this->log( "Preparing Data Step11: WP_SITEURL not defined in wp-config.php. Skipping this step." );
|
651 |
+
}
|
652 |
+
|
653 |
+
|
654 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
655 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
656 |
return false;
|
657 |
+
}
|
658 |
+
$this->Log( "Preparing Data: Finished Step 11 successfully" );
|
659 |
+
return true;
|
660 |
+
}
|
661 |
+
|
662 |
+
/**
|
663 |
+
* Update WP_ALLOW_MULTISITE constant in wp-config.php
|
664 |
+
* @return bool
|
665 |
+
*/
|
666 |
+
protected function step12() {
|
667 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
668 |
+
|
669 |
+
$this->log( "Preparing Data Step12: Updating WP_ALLOW_MULTISITE in wp-config.php to false" );
|
670 |
+
|
671 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
672 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
673 |
+
return false;
|
674 |
+
}
|
675 |
+
|
676 |
+
|
677 |
+
// Get WP_SITEURL from wp-config.php
|
678 |
+
preg_match( "/define\s*\(\s*'WP_ALLOW_MULTISITE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
679 |
|
680 |
+
if( !empty( $matches[1] ) ) {
|
681 |
+
$matches[1];
|
682 |
|
683 |
+
$pattern = "/define\s*\(\s*'WP_ALLOW_MULTISITE'\s*,\s*(.*)\s*\);/";
|
|
|
|
|
|
|
|
|
|
|
|
|
684 |
|
685 |
+
$replace = "define('WP_ALLOW_MULTISITE',false); // " . $matches[1];
|
686 |
+
$replace.= " // Changed by WP-Staging";
|
|
|
|
|
|
|
|
|
687 |
|
688 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
689 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE", Logger::TYPE_ERROR );
|
690 |
+
return false;
|
691 |
+
}
|
692 |
+
} else {
|
693 |
+
$this->log( "Preparing Data Step12: WP_ALLOW_MULTISITE not defined in wp-config.php. Skipping this step." );
|
694 |
+
}
|
695 |
|
|
|
|
|
|
|
|
|
696 |
|
697 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
698 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
699 |
+
return false;
|
700 |
+
}
|
701 |
+
$this->Log( "Preparing Data: Finished Step 12 successfully" );
|
702 |
+
return true;
|
703 |
+
}
|
704 |
+
|
705 |
+
/**
|
706 |
+
* Update MULTISITE constant in wp-config.php
|
707 |
+
* @return bool
|
708 |
+
*/
|
709 |
+
protected function step13() {
|
710 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
711 |
+
|
712 |
+
$this->log( "Preparing Data Step13: Updating MULTISITE in wp-config.php to false" );
|
713 |
+
|
714 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
715 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
716 |
+
return false;
|
717 |
+
}
|
718 |
|
|
|
|
|
719 |
|
720 |
+
// Get WP_SITEURL from wp-config.php
|
721 |
+
preg_match( "/define\s*\(\s*'MULTISITE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
722 |
|
723 |
+
if( !empty( $matches[1] ) ) {
|
724 |
+
$matches[1];
|
725 |
|
726 |
+
$pattern = "/define\s*\(\s*'MULTISITE'\s*,\s*(.*)\s*\);/";
|
|
|
727 |
|
728 |
+
$replace = "define('MULTISITE',false); // " . $matches[1];
|
729 |
+
$replace.= " // Changed by WP-Staging";
|
730 |
+
|
731 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
732 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE", Logger::TYPE_ERROR );
|
733 |
+
return false;
|
734 |
+
}
|
735 |
+
} else {
|
736 |
+
$this->log( "Preparing Data Step13: MULTISITE not defined in wp-config.php. Skipping this step." );
|
737 |
+
}
|
738 |
+
|
739 |
+
|
740 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
741 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
742 |
return false;
|
743 |
+
}
|
744 |
+
$this->Log( "Preparing Data: Finished Step 13 successfully" );
|
745 |
+
return true;
|
746 |
+
}
|
747 |
|
748 |
+
/**
|
749 |
+
* Get active_sitewide_plugins from wp_sitemeta and active_plugins from subsite
|
750 |
+
* Merge both arrays and copy them to the staging site into active_plugins
|
751 |
+
*/
|
752 |
+
protected function step14() {
|
753 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
754 |
|
755 |
+
$this->log( "Data Crunching Step 14: Updating active_plugins" );
|
|
|
|
|
|
|
|
|
|
|
756 |
|
757 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
758 |
+
$this->log( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
759 |
+
$this->returnException( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
760 |
+
return false;
|
761 |
+
}
|
762 |
|
763 |
+
// Skip - Table is not selected or updated
|
764 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
765 |
+
$this->log( "Preparing Data Step14: Skipping" );
|
766 |
+
return true;
|
767 |
+
}
|
768 |
|
769 |
+
// Get active_plugins value from sub site options table
|
770 |
+
$active_plugins = $this->db->get_var( "SELECT option_value FROM {$this->db->prefix}options WHERE option_name = 'active_plugins' " );
|
771 |
|
772 |
+
if( !$active_plugins ) {
|
773 |
+
$this->log( "Data Crunching Step 14: Option active_plugins are empty " );
|
774 |
+
$active_plugins = array();
|
775 |
+
}
|
776 |
+
// Get active_sitewide_plugins value from main multisite wp_sitemeta table
|
777 |
+
$active_sitewide_plugins = $this->db->get_var( "SELECT meta_value FROM {$this->db->base_prefix}sitemeta WHERE meta_key = 'active_sitewide_plugins' " );
|
778 |
|
779 |
+
if( !$active_sitewide_plugins ) {
|
780 |
+
$this->log( "Data Crunching Step 14: Options {$this->db->base_prefix}active_sitewide_plugins is empty " );
|
781 |
+
$active_sitewide_plugins = array();
|
782 |
+
}
|
783 |
|
784 |
+
$active_sitewide_plugins = unserialize( $active_sitewide_plugins );
|
785 |
+
$active_plugins = unserialize( $active_plugins );
|
786 |
|
787 |
+
$all_plugins = array_merge( $active_plugins, array_keys( $active_sitewide_plugins ) );
|
|
|
788 |
|
789 |
+
sort( $all_plugins );
|
790 |
+
|
791 |
+
|
792 |
+
// Update active_plugins
|
793 |
+
$update = $this->db->query(
|
794 |
+
"UPDATE {$this->prefix}options SET option_value = '" . serialize( $all_plugins ) . "' WHERE option_name = 'active_plugins'"
|
795 |
+
);
|
796 |
+
|
797 |
+
if( false === $update ) {
|
798 |
+
$this->log( "Data Crunching Step 14: Can not update option active_plugins in {$this->prefix}options", Logger::TYPE_WARNING );
|
799 |
return false;
|
800 |
+
}
|
801 |
+
|
802 |
+
$this->log( "Data Crunching Step 14: Successfull!" );
|
803 |
+
return true;
|
804 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
805 |
|
806 |
+
/**
|
807 |
+
* Update Table Prefix in wp_options
|
808 |
+
* @return bool
|
809 |
+
*/
|
810 |
+
protected function step15() {
|
811 |
+
$this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options." );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
812 |
|
813 |
+
// Skip - Table does not exist
|
814 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
815 |
+
return true;
|
816 |
+
}
|
817 |
+
|
818 |
+
// Skip - Table is not selected or updated
|
819 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
820 |
+
$this->log( "Preparing Data Step4: Skipping" );
|
821 |
+
return true;
|
822 |
+
}
|
823 |
+
|
824 |
+
|
825 |
+
$this->log( "Updating db option_names in {$this->prefix}options. " );
|
826 |
+
|
827 |
+
// Filter the rows below. Do not update them!
|
828 |
+
$filters = array(
|
829 |
+
'wp_mail_smtp',
|
830 |
+
'wp_mail_smtp_version',
|
831 |
+
'wp_mail_smtp_debug',
|
832 |
+
);
|
833 |
+
|
834 |
+
$filters = apply_filters( 'wpstg_data_excl_rows', $filters );
|
835 |
+
|
836 |
+
$where = "";
|
837 |
+
foreach ( $filters as $filter ) {
|
838 |
+
$where .= " AND option_name <> '" . $filter . "'";
|
839 |
+
}
|
840 |
+
|
841 |
+
$updateOptions = $this->db->query(
|
842 |
+
$this->db->prepare(
|
843 |
+
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
844 |
+
)
|
845 |
+
);
|
846 |
+
|
847 |
+
if( !$updateOptions ) {
|
848 |
+
$this->log( "Preparing Data Step15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_WARNING );
|
849 |
+
//$this->returnException( "Data Crunching Step 15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
850 |
+
return true;
|
851 |
+
}
|
852 |
+
|
853 |
+
|
854 |
+
return true;
|
855 |
+
}
|
856 |
+
|
857 |
+
/**
|
858 |
+
* Change upload_path in wp_options (if it is defined)
|
859 |
+
* @return bool
|
860 |
+
*/
|
861 |
+
protected function step16() {
|
862 |
+
$this->log( "Preparing Data Step16: Updating upload_path {$this->prefix}options." );
|
863 |
+
|
864 |
+
// Skip - Table does not exist
|
865 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
866 |
+
return true;
|
867 |
+
}
|
868 |
|
869 |
+
$newUploadPath = $this->getNewUploadPath();
|
870 |
|
871 |
+
if( false === $newUploadPath ) {
|
872 |
+
$this->log( "Preparing Data Step16: Skipping" );
|
873 |
+
return true;
|
874 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
875 |
|
876 |
+
// Skip - Table is not selected or updated
|
877 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
878 |
+
$this->log( "Preparing Data Step16: Skipping" );
|
879 |
+
return true;
|
880 |
+
}
|
881 |
|
882 |
+
$error = isset( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
|
|
|
|
|
|
|
|
|
|
|
|
|
883 |
|
884 |
+
$this->log( "Updating upload_path in {$this->prefix}options. {$error}" );
|
|
|
885 |
|
886 |
+
$updateOptions = $this->db->query(
|
887 |
+
$this->db->prepare(
|
888 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
|
889 |
+
)
|
890 |
+
);
|
891 |
+
|
892 |
+
if( !$updateOptions ) {
|
893 |
+
$this->log( "Preparing Data Step16: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
894 |
+
return true;
|
895 |
+
}
|
896 |
+
$this->Log( "Preparing Data: Finished Step 16 successfully" );
|
897 |
+
return true;
|
898 |
+
}
|
899 |
+
|
900 |
+
/**
|
901 |
+
* Update WP_CACHE in wp-config.php
|
902 |
+
* @return bool
|
903 |
+
*/
|
904 |
+
protected function step17() {
|
905 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
906 |
+
|
907 |
+
$this->log( "Preparing Data Step17: Set WP_CACHE in wp-config.php to false" );
|
908 |
+
|
909 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
910 |
+
$this->log( "Preparing Data Step17: Failed to update WP_CACHE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
911 |
return false;
|
912 |
+
}
|
913 |
+
|
914 |
+
|
915 |
+
// Get WP_CACHE from wp-config.php
|
916 |
+
preg_match( "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
917 |
+
|
918 |
+
if( !empty( $matches[1] ) ) {
|
919 |
+
$matches[1];
|
920 |
+
|
921 |
+
$pattern = "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/";
|
922 |
+
|
923 |
+
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
924 |
+
$replace.= " // Changed by WP-Staging";
|
925 |
+
|
926 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
927 |
+
$this->log( "Preparing Data: Failed to change WP_CACHE", Logger::TYPE_ERROR );
|
928 |
+
return false;
|
929 |
+
}
|
930 |
+
} else {
|
931 |
+
$this->log( "Preparing Data Step17: WP_CACHE not defined in wp-config.php. Skipping this step." );
|
932 |
+
}
|
933 |
+
|
934 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
935 |
+
$this->log( "Preparing Data Step17: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
|
936 |
+
return false;
|
937 |
+
}
|
938 |
+
$this->Log( "Preparing Data: Finished Step 17 successfully" );
|
939 |
+
return true;
|
940 |
+
}
|
941 |
+
|
942 |
+
/**
|
943 |
+
* Get Upload Path to staging site
|
944 |
+
* @return boolean|string
|
945 |
+
*/
|
946 |
+
protected function getNewUploadPath() {
|
947 |
+
$uploadPath = get_option( 'upload_path' );
|
948 |
+
|
949 |
+
if( !$uploadPath ) {
|
950 |
+
return false;
|
951 |
+
}
|
952 |
+
|
953 |
+
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
|
954 |
+
|
955 |
+
$newUploadPath = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR . $customSlug;
|
956 |
+
|
957 |
+
return $newUploadPath;
|
958 |
+
}
|
959 |
+
|
960 |
+
/**
|
961 |
+
* Return URL to staging site
|
962 |
+
* @return string
|
963 |
+
*/
|
964 |
+
protected function getStagingSiteUrl() {
|
965 |
+
|
966 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
967 |
+
return $this->options->cloneHostname;
|
968 |
+
}
|
969 |
+
|
970 |
+
if( $this->isSubDir() ) {
|
971 |
+
return trailingslashit( $this->multisiteHomeDomain ) . trailingslashit($this->getSubDir()) . $this->options->cloneDirectoryName;
|
972 |
+
}
|
973 |
+
|
974 |
+
return trailingslashit( $this->multisiteHomeDomain ) . $this->options->cloneDirectoryName;
|
975 |
+
}
|
976 |
+
|
977 |
+
/**
|
978 |
+
* Check if WP is installed in subdir
|
979 |
+
* @return boolean
|
980 |
+
*/
|
981 |
+
protected function isSubDir() {
|
982 |
+
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
983 |
+
// This is happening much more often than you would expect
|
984 |
+
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
985 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
986 |
+
|
987 |
+
if( $home !== $siteurl ) {
|
988 |
+
return true;
|
989 |
+
}
|
990 |
+
return false;
|
991 |
+
}
|
992 |
+
|
993 |
+
/**
|
994 |
+
* Get the install sub directory if WP is installed in sub directory
|
995 |
+
* @return string
|
996 |
+
*/
|
997 |
+
protected function getSubDir() {
|
998 |
+
$home = get_option( 'home' );
|
999 |
+
$siteurl = get_option( 'siteurl' );
|
1000 |
+
|
1001 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
1002 |
+
return '';
|
1003 |
+
}
|
1004 |
+
|
1005 |
+
$dir = str_replace( $home, '', $siteurl );
|
1006 |
+
return str_replace( '/', '', $dir );
|
1007 |
+
}
|
1008 |
|
1009 |
}
|
@@ -4,7 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
@@ -20,1063 +20,1116 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
20 |
*/
|
21 |
class DataExternal extends JobExecutable {
|
22 |
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
// Prefix is the same as the one of live site
|
157 |
// $wpdb = WPStaging::getInstance()->get( "wpdb" );
|
158 |
// if( $wpdb->prefix === $this->prefix ) {
|
159 |
// return true;
|
160 |
// }
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
213 |
$errors = error_get_last();
|
214 |
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
215 |
return true;
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
$this->
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
return true;
|
414 |
-
}
|
415 |
-
|
416 |
-
/**
|
417 |
-
* Reset index.php to original file
|
418 |
-
* This is needed if live site is located in subfolder
|
419 |
-
* Check first if main wordpress is used in subfolder and index.php in parent directory
|
420 |
-
* @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
|
421 |
-
* @return bool
|
422 |
-
*/
|
423 |
-
protected function step6() {
|
424 |
-
|
425 |
-
if( !$this->isSubDir() ) {
|
426 |
-
$this->debugLog( "Preparing Data Step6: WP installation is not in a subdirectory! All good, skipping this step" );
|
427 |
-
return true;
|
428 |
-
}
|
429 |
-
|
430 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/index.php";
|
431 |
-
|
432 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
433 |
-
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
|
434 |
-
return false;
|
435 |
-
}
|
436 |
-
|
437 |
-
|
438 |
-
if( !preg_match( "/(require(.*)wp-blog-header.php' \);)/", $content, $matches ) ) {
|
439 |
-
$this->log(
|
440 |
-
"Preparing Data Step6: Failed to reset index.php for sub directory; wp-blog-header.php is missing", Logger::TYPE_ERROR
|
441 |
-
);
|
442 |
-
return false;
|
443 |
-
}
|
444 |
-
$this->log( "Preparing Data: WP installation is in a subdirectory. Progressing..." );
|
445 |
-
|
446 |
-
$pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
|
447 |
-
|
448 |
-
$replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
|
449 |
-
$replace.= " // Changed by WP-Staging";
|
450 |
-
|
451 |
-
|
452 |
-
|
453 |
-
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
454 |
-
$this->log( "Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR );
|
455 |
-
return false;
|
456 |
-
}
|
457 |
-
|
458 |
-
if( false === @file_put_contents( $path, $content ) ) {
|
459 |
-
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
460 |
-
return false;
|
461 |
-
}
|
462 |
-
$this->Log( "Preparing Data: Finished Step 6 successfully" );
|
463 |
-
return true;
|
464 |
-
}
|
465 |
-
|
466 |
-
/**
|
467 |
-
* Update wpstg_rmpermalinks_executed
|
468 |
-
* @return bool
|
469 |
-
*/
|
470 |
-
protected function step7() {
|
471 |
-
|
472 |
-
$this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
|
473 |
-
|
474 |
-
// Skip - Table does not exist
|
475 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
476 |
-
return true;
|
477 |
-
}
|
478 |
-
|
479 |
-
// Skip - Table is not selected or updated
|
480 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
481 |
-
$this->log( "Preparing Data Step7: Skipping" );
|
482 |
-
return true;
|
483 |
-
}
|
484 |
-
|
485 |
-
$result = $this->db->query(
|
486 |
-
$this->db->prepare(
|
487 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'", ' '
|
488 |
-
)
|
489 |
-
);
|
490 |
-
|
491 |
-
// All good
|
492 |
-
if( $result ) {
|
493 |
-
$this->Log( "Preparing Data Step7: Finished Step 7 successfully" );
|
494 |
-
return true;
|
495 |
-
}
|
496 |
-
|
497 |
-
$this->log( "Failed to update wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_WARNING );
|
498 |
-
return true;
|
499 |
-
}
|
500 |
-
|
501 |
-
/**
|
502 |
-
* Update permalink_structure
|
503 |
-
* @return bool
|
504 |
-
*/
|
505 |
-
protected function step8() {
|
506 |
-
|
507 |
-
$this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
|
508 |
-
|
509 |
-
// Skip - Table does not exist
|
510 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
511 |
-
return true;
|
512 |
-
}
|
513 |
-
|
514 |
-
// Skip - Table is not selected or updated
|
515 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
516 |
-
$this->log( "Preparing Data Step8: Skipping" );
|
517 |
-
return true;
|
518 |
-
}
|
519 |
-
|
520 |
-
$result = $this->db->query(
|
521 |
-
$this->db->prepare(
|
522 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
|
523 |
-
)
|
524 |
-
);
|
525 |
-
|
526 |
-
// All good
|
527 |
-
if( $result ) {
|
528 |
-
$this->Log( "Preparing Data Step8: Finished Step 8 successfully" );
|
529 |
-
return true;
|
530 |
-
}
|
531 |
-
|
532 |
-
$this->log( "Failed to update permalink_structure in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
533 |
-
return true;
|
534 |
-
}
|
535 |
-
|
536 |
-
/**
|
537 |
-
* Update blog_public option to not allow staging site to be indexed by search engines
|
538 |
-
* @return bool
|
539 |
-
*/
|
540 |
-
protected function step9() {
|
541 |
-
|
542 |
-
$this->log( "Preparing Data Step9: Set staging site to noindex" );
|
543 |
-
|
544 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
545 |
-
return true;
|
546 |
-
}
|
547 |
-
|
548 |
-
// Skip - Table is not selected or updated
|
549 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
550 |
-
$this->log( "Preparing Data Step9: Skipping" );
|
551 |
-
return true;
|
552 |
-
}
|
553 |
-
|
554 |
-
$result = $this->db->query(
|
555 |
-
$this->db->prepare(
|
556 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
|
557 |
-
)
|
558 |
-
);
|
559 |
-
|
560 |
-
// All good
|
561 |
-
if( $result ) {
|
562 |
-
$this->Log( "Preparing Data Step9: Finished Step 9 successfully" );
|
563 |
-
return true;
|
564 |
-
}
|
565 |
-
|
566 |
-
$this->log( "Can not update staging site to noindex. Possible already done!", Logger::TYPE_WARNING );
|
567 |
-
return true;
|
568 |
-
}
|
569 |
-
|
570 |
-
/**
|
571 |
-
* Update WP_HOME in wp-config.php
|
572 |
-
* @return bool
|
573 |
-
*/
|
574 |
-
protected function step10() {
|
575 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
576 |
-
|
577 |
-
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
578 |
-
|
579 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
580 |
-
$this->log( "Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
581 |
-
return false;
|
582 |
-
}
|
583 |
-
|
584 |
-
|
585 |
-
// Get WP_HOME from wp-config.php
|
586 |
-
preg_match( "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
587 |
-
|
588 |
-
if( !empty( $matches[1] ) ) {
|
589 |
-
$matches[1];
|
590 |
-
|
591 |
-
$pattern = "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/";
|
592 |
-
|
593 |
-
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
594 |
-
$replace.= " // Changed by WP-Staging";
|
595 |
-
|
596 |
-
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
597 |
-
$this->log( "Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR );
|
598 |
return false;
|
599 |
-
|
600 |
-
} else {
|
601 |
-
$this->log( "Preparing Data Step10: WP_HOME not defined in wp-config.php. Skipping this step." );
|
602 |
-
}
|
603 |
|
604 |
-
|
605 |
-
|
606 |
-
return false;
|
607 |
-
}
|
608 |
-
$this->Log( "Preparing Data: Finished Step 10 successfully" );
|
609 |
-
return true;
|
610 |
-
}
|
611 |
|
612 |
-
|
613 |
-
|
614 |
-
* @return bool
|
615 |
-
*/
|
616 |
-
protected function step11() {
|
617 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
618 |
|
619 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
620 |
|
621 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
622 |
-
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
623 |
-
return false;
|
624 |
-
}
|
625 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
626 |
|
627 |
-
|
628 |
-
preg_match( "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/", $content, $matches );
|
629 |
|
630 |
-
|
631 |
-
|
632 |
|
633 |
-
$pattern = "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/";
|
634 |
|
635 |
-
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
636 |
-
$replace.= " // Changed by WP-Staging";
|
637 |
|
638 |
-
|
639 |
-
$this->log( "Preparing Data
|
640 |
return false;
|
641 |
-
|
642 |
-
} else {
|
643 |
-
$this->log( "Preparing Data Step11: WP_SITEURL not defined in wp-config.php. Skipping this step." );
|
644 |
-
}
|
645 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
646 |
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
return true;
|
653 |
-
}
|
654 |
|
655 |
-
|
656 |
-
* Update WP_ALLOW_MULTISITE constant in wp-config.php
|
657 |
-
* @return bool
|
658 |
-
*/
|
659 |
-
protected function step12() {
|
660 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
661 |
|
662 |
-
|
|
|
|
|
|
|
663 |
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
|
|
668 |
|
|
|
|
|
|
|
|
|
|
|
669 |
|
670 |
-
|
671 |
-
|
|
|
|
|
|
|
672 |
|
673 |
-
|
674 |
-
|
|
|
675 |
|
676 |
-
|
|
|
|
|
|
|
|
|
677 |
|
678 |
-
|
679 |
-
$replace.= " // Changed by WP-Staging";
|
680 |
|
681 |
-
|
682 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
683 |
return false;
|
684 |
-
|
685 |
-
} else {
|
686 |
-
$this->log( "Preparing Data Step12: WP_ALLOW_MULTISITE not defined in wp-config.php. Skipping this step." );
|
687 |
-
}
|
688 |
|
689 |
|
690 |
-
|
691 |
-
|
692 |
-
return false;
|
693 |
-
}
|
694 |
-
$this->Log( "Preparing Data: Finished Step 12 successfully" );
|
695 |
-
return true;
|
696 |
-
}
|
697 |
|
698 |
-
|
699 |
-
|
700 |
-
* @return bool
|
701 |
-
*/
|
702 |
-
protected function step13() {
|
703 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
704 |
|
705 |
-
|
706 |
|
707 |
-
|
708 |
-
|
709 |
-
return false;
|
710 |
-
}
|
711 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
712 |
|
713 |
-
|
714 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
715 |
|
716 |
-
if( !empty( $matches[1] ) ) {
|
717 |
-
$matches[1];
|
718 |
|
719 |
-
|
|
|
720 |
|
721 |
-
|
722 |
-
|
723 |
|
724 |
-
|
725 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
726 |
return false;
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
$this->log( "Data Crunching Step 14: Updating active_plugins" );
|
749 |
-
|
750 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
751 |
-
$this->log( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
752 |
-
$this->returnException( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
753 |
-
return false;
|
754 |
-
}
|
755 |
-
|
756 |
-
// Skip - Table is not selected or updated
|
757 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
758 |
-
$this->log( "Preparing Data Step14: Skipping" );
|
759 |
-
return true;
|
760 |
-
}
|
761 |
-
|
762 |
-
// Get active_plugins value from sub site options table
|
763 |
-
$active_plugins = $this->db->get_var( "SELECT option_value FROM {$this->productionDb->prefix}options WHERE option_name = 'active_plugins' " );
|
764 |
-
|
765 |
-
if( !$active_plugins ) {
|
766 |
-
$this->log( "Data Crunching Step 14: Option active_plugins are empty " );
|
767 |
-
$active_plugins = array();
|
768 |
-
}
|
769 |
-
// Get active_sitewide_plugins value from main multisite wp_sitemeta table
|
770 |
-
$active_sitewide_plugins = $this->db->get_var( "SELECT meta_value FROM {$this->productionDb->base_prefix}sitemeta WHERE meta_key = 'active_sitewide_plugins' " );
|
771 |
-
|
772 |
-
if( !$active_sitewide_plugins ) {
|
773 |
-
$this->log( "Data Crunching Step 14: Options {$this->liveDb->base_prefix}active_sitewide_plugins is empty " );
|
774 |
-
$active_sitewide_plugins = array();
|
775 |
-
}
|
776 |
-
|
777 |
-
$active_sitewide_plugins = unserialize( $active_sitewide_plugins );
|
778 |
-
$active_plugins = unserialize( $active_plugins );
|
779 |
-
|
780 |
-
$all_plugins = array_merge( $active_plugins, array_keys( $active_sitewide_plugins ) );
|
781 |
-
|
782 |
-
sort( $all_plugins );
|
783 |
-
|
784 |
-
|
785 |
-
// Update active_plugins
|
786 |
-
$update = $this->db->query(
|
787 |
-
"UPDATE {$this->prefix}options SET option_value = '" . serialize( $all_plugins ) . "' WHERE option_name = 'active_plugins'"
|
788 |
-
);
|
789 |
-
|
790 |
-
if( false === $update ) {
|
791 |
-
$this->log( "Data Crunching Step 14: Can not update option active_plugins in {$this->prefix}options", Logger::TYPE_WARNING );
|
792 |
-
return false;
|
793 |
-
}
|
794 |
-
|
795 |
-
$this->log( "Data Crunching Step 14: Successfull!" );
|
796 |
-
return true;
|
797 |
-
}
|
798 |
-
|
799 |
-
/**
|
800 |
-
* Update Table Prefix in wp_options
|
801 |
-
* @return bool
|
802 |
-
*/
|
803 |
-
protected function step15() {
|
804 |
-
$this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options." );
|
805 |
-
|
806 |
-
// Skip - Table does not exist
|
807 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
808 |
-
return true;
|
809 |
-
}
|
810 |
-
|
811 |
-
// Skip - Table is not selected or updated
|
812 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
813 |
-
$this->log( "Preparing Data Step4: Skipping" );
|
814 |
-
return true;
|
815 |
-
}
|
816 |
-
|
817 |
-
// Skip, prefixes are identical. No change needed
|
818 |
-
if( $this->db->prefix === $this->prefix ) {
|
819 |
-
$this->log( "Preparing Data Step4: Skipping" );
|
820 |
-
return true;
|
821 |
-
}
|
822 |
-
|
823 |
-
$this->log( "Updating db option_names in {$this->prefix}options. " );
|
824 |
-
|
825 |
-
// Filter the rows below. Do not update them!
|
826 |
-
$filters = array(
|
827 |
-
'wp_mail_smtp',
|
828 |
-
'wp_mail_smtp_version',
|
829 |
-
'wp_mail_smtp_debug',
|
830 |
-
);
|
831 |
-
|
832 |
-
$filters = apply_filters( 'wpstg_data_excl_rows', $filters );
|
833 |
-
|
834 |
-
$where = "";
|
835 |
-
foreach ( $filters as $filter ) {
|
836 |
-
$where .= " AND option_name <> '" . $filter . "'";
|
837 |
-
}
|
838 |
-
|
839 |
-
$updateOptions = $this->db->query(
|
840 |
-
$this->db->prepare(
|
841 |
-
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
842 |
-
)
|
843 |
-
);
|
844 |
-
|
845 |
-
if( !$updateOptions ) {
|
846 |
-
$this->log( "Preparing Data Step15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_ERROR );
|
847 |
-
$this->returnException( "Data Crunching Step 15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
848 |
-
return false;
|
849 |
-
}
|
850 |
-
|
851 |
-
return true;
|
852 |
-
}
|
853 |
-
|
854 |
-
/**
|
855 |
-
* Change upload_path in wp_options (if it is defined)
|
856 |
-
* @return bool
|
857 |
-
*/
|
858 |
-
protected function step16() {
|
859 |
-
$this->log( "Preparing Data Step16: Updating upload_path {$this->prefix}options." );
|
860 |
-
|
861 |
-
// Skip - Table does not exist
|
862 |
-
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
863 |
-
return true;
|
864 |
-
}
|
865 |
-
|
866 |
-
$newUploadPath = $this->getNewUploadPath();
|
867 |
-
|
868 |
-
if( false === $newUploadPath ) {
|
869 |
-
$this->log( "Preparing Data Step16: Skipping" );
|
870 |
-
return true;
|
871 |
-
}
|
872 |
-
|
873 |
-
// Skip - Table is not selected or updated
|
874 |
-
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
875 |
-
$this->log( "Preparing Data Step16: Skipping" );
|
876 |
-
return true;
|
877 |
-
}
|
878 |
-
|
879 |
-
$error = isset( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
|
880 |
-
|
881 |
-
$this->log( "Updating upload_path in {$this->prefix}options. {$error}" );
|
882 |
-
|
883 |
-
$updateOptions = $this->db->query(
|
884 |
-
$this->db->prepare(
|
885 |
-
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
|
886 |
-
)
|
887 |
-
);
|
888 |
-
|
889 |
-
if( !$updateOptions ) {
|
890 |
-
$this->log( "Preparing Data Step16: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
891 |
-
return true;
|
892 |
-
}
|
893 |
-
$this->Log( "Preparing Data: Finished Step 16 successfully" );
|
894 |
-
return true;
|
895 |
-
}
|
896 |
-
|
897 |
-
/**
|
898 |
-
* Update WP_CACHE in wp-config.php
|
899 |
-
* @return bool
|
900 |
-
*/
|
901 |
-
protected function step17() {
|
902 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
903 |
-
|
904 |
-
$this->log( "Preparing Data Step17: Set WP_CACHE in wp-config.php to false" );
|
905 |
-
|
906 |
-
if( false === ($content = file_get_contents( $path )) ) {
|
907 |
-
$this->log( "Preparing Data Step17: Failed to update WP_CACHE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
908 |
-
return false;
|
909 |
-
}
|
910 |
-
|
911 |
-
|
912 |
-
// Get WP_CACHE from wp-config.php
|
913 |
-
preg_match( "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
914 |
-
|
915 |
-
if( !empty( $matches[1] ) ) {
|
916 |
-
$matches[1];
|
917 |
-
|
918 |
-
$pattern = "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/";
|
919 |
-
|
920 |
-
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
921 |
-
$replace.= " // Changed by WP-Staging";
|
922 |
|
923 |
-
|
924 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
925 |
return false;
|
926 |
-
|
927 |
-
|
928 |
-
$this->log( "Preparing Data Step17: WP_CACHE not defined in wp-config.php. Skipping this step." );
|
929 |
-
}
|
930 |
|
931 |
-
|
932 |
-
|
933 |
-
return false;
|
934 |
-
}
|
935 |
-
$this->Log( "Preparing Data: Finished Step 17 successfully" );
|
936 |
-
return true;
|
937 |
-
}
|
938 |
|
939 |
-
|
940 |
-
|
941 |
-
* @return bool
|
942 |
-
*/
|
943 |
-
protected function step18() {
|
944 |
-
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
945 |
|
946 |
-
|
947 |
|
948 |
-
|
949 |
-
|
950 |
-
return false;
|
951 |
-
}
|
952 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
953 |
|
954 |
-
// Get DB_NAME from wp-config.php
|
955 |
-
preg_match( "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
956 |
|
957 |
-
|
958 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
959 |
|
960 |
-
$pattern = "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);/";
|
961 |
|
962 |
-
|
963 |
-
$replace.= " // Changed by WP-Staging";
|
964 |
|
965 |
-
|
966 |
-
$this->log(
|
|
|
967 |
return false;
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
|
972 |
-
|
973 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
974 |
|
975 |
-
|
976 |
-
$matches[1];
|
977 |
|
978 |
-
|
979 |
|
980 |
-
|
981 |
-
|
|
|
|
|
|
|
982 |
|
983 |
-
|
984 |
-
$this->log( "Preparing Data: Failed to
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
985 |
return false;
|
986 |
-
|
987 |
-
|
988 |
-
|
989 |
-
|
990 |
-
|
991 |
-
preg_match( "/define\s*\(\s*'DB_PASSWORD'\s*,\s*(.*)\s*\);/", $content, $matches );
|
992 |
|
993 |
-
|
994 |
-
|
995 |
|
996 |
-
|
997 |
|
998 |
-
|
999 |
-
|
1000 |
|
1001 |
-
|
1002 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1003 |
return false;
|
1004 |
-
|
1005 |
-
|
1006 |
-
|
1007 |
-
|
1008 |
-
|
1009 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1010 |
|
1011 |
-
|
1012 |
-
|
1013 |
|
1014 |
-
|
1015 |
|
1016 |
-
|
1017 |
-
|
1018 |
|
1019 |
-
|
1020 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1021 |
return false;
|
1022 |
-
|
1023 |
-
|
1024 |
-
|
1025 |
-
|
1026 |
-
|
1027 |
-
|
1028 |
-
|
1029 |
-
|
1030 |
-
|
1031 |
-
|
1032 |
-
|
1033 |
-
|
1034 |
-
|
1035 |
-
|
1036 |
-
|
1037 |
-
|
1038 |
-
|
1039 |
-
|
1040 |
-
|
1041 |
-
|
1042 |
-
|
1043 |
-
|
1044 |
-
|
1045 |
-
|
1046 |
-
|
1047 |
-
|
1048 |
-
|
1049 |
-
|
1050 |
-
|
1051 |
-
|
1052 |
-
|
1053 |
-
|
1054 |
-
|
1055 |
-
|
1056 |
-
|
1057 |
-
|
1058 |
-
|
1059 |
-
|
1060 |
-
|
1061 |
-
|
1062 |
-
|
1063 |
-
|
1064 |
-
|
1065 |
-
|
1066 |
-
|
1067 |
-
|
1068 |
-
|
1069 |
-
|
1070 |
-
|
1071 |
-
|
1072 |
-
|
1073 |
-
|
1074 |
-
|
1075 |
-
|
1076 |
-
|
1077 |
-
|
1078 |
-
|
1079 |
-
return false;
|
1080 |
-
}
|
1081 |
|
1082 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\Utils\Logger;
|
20 |
*/
|
21 |
class DataExternal extends JobExecutable {
|
22 |
|
23 |
+
/**
|
24 |
+
* @var \wpdb
|
25 |
+
*/
|
26 |
+
private $db;
|
27 |
+
|
28 |
+
/**
|
29 |
+
* @var string
|
30 |
+
*/
|
31 |
+
private $prefix;
|
32 |
+
|
33 |
+
/**
|
34 |
+
* Tables e.g wpstg3_options
|
35 |
+
* @var array
|
36 |
+
*/
|
37 |
+
private $tables;
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Initialize
|
41 |
+
*/
|
42 |
+
public function initialize() {
|
43 |
+
$this->db = $this->getStagingDB();
|
44 |
+
$this->productionDb = WPStaging::getInstance()->get( "wpdb" );
|
45 |
+
$this->prefix = $this->options->prefix;
|
46 |
+
$this->db->prefix = $this->options->databasePrefix;
|
47 |
+
|
48 |
+
$this->getTables();
|
49 |
+
|
50 |
+
// Fix current step
|
51 |
+
if( 0 == $this->options->currentStep ) {
|
52 |
+
$this->options->currentStep = 0;
|
53 |
+
}
|
54 |
+
}
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Get database object to interact with
|
58 |
+
*/
|
59 |
+
private function getStagingDB() {
|
60 |
+
return new \wpdb( $this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer );
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Get a list of tables to copy
|
65 |
+
*/
|
66 |
+
private function getTables() {
|
67 |
+
$strings = new Strings();
|
68 |
+
$this->tables = array();
|
69 |
+
foreach ( $this->options->tables as $table ) {
|
70 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->productionDb->prefix, null, $table );
|
71 |
+
}
|
72 |
+
// Add extra global tables from main multisite (wpstgx_users and wpstgx_usermeta)
|
73 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->productionDb->prefix, null, 'users' );
|
74 |
+
$this->tables[] = $this->options->prefix . $strings->str_replace_first( $this->productionDb->prefix, null, 'usermeta' );
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
79 |
+
* @return void
|
80 |
+
*/
|
81 |
+
protected function calculateTotalSteps() {
|
82 |
+
$this->options->totalSteps = 19;
|
83 |
+
}
|
84 |
+
|
85 |
+
/**
|
86 |
+
* Start Module
|
87 |
+
* @return object
|
88 |
+
*/
|
89 |
+
public function start() {
|
90 |
+
// Execute steps
|
91 |
+
$this->run();
|
92 |
+
|
93 |
+
// Save option, progress
|
94 |
+
$this->saveOptions();
|
95 |
+
|
96 |
+
return ( object ) $this->response;
|
97 |
+
}
|
98 |
+
|
99 |
+
/**
|
100 |
+
* Execute the Current Step
|
101 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
102 |
+
* @return bool
|
103 |
+
*/
|
104 |
+
protected function execute() {
|
105 |
+
// Fatal error. Let this happen never and break here immediately
|
106 |
+
if( $this->isRoot() ) {
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
|
110 |
+
// Over limits threshold
|
111 |
+
if( $this->isOverThreshold() ) {
|
112 |
+
// Prepare response and save current progress
|
113 |
+
$this->prepareResponse( false, false );
|
114 |
+
$this->saveOptions();
|
115 |
+
return false;
|
116 |
+
}
|
117 |
+
|
118 |
+
// No more steps, finished
|
119 |
+
if( $this->isFinished() ) {
|
120 |
+
$this->prepareResponse( true, false );
|
121 |
+
return false;
|
122 |
+
}
|
123 |
+
|
124 |
+
// Execute step
|
125 |
+
$stepMethodName = "step" . $this->options->currentStep;
|
126 |
+
if( !$this->{$stepMethodName}() ) {
|
127 |
+
$this->prepareResponse( false, false );
|
128 |
+
return false;
|
129 |
+
}
|
130 |
+
|
131 |
+
// Prepare Response
|
132 |
+
$this->prepareResponse();
|
133 |
+
|
134 |
+
// Not finished
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
|
138 |
+
/**
|
139 |
+
* Checks Whether There is Any Job to Execute or Not
|
140 |
+
* @return bool
|
141 |
+
*/
|
142 |
+
protected function isFinished() {
|
143 |
+
return (
|
144 |
+
$this->options->currentStep > $this->options->totalSteps ||
|
145 |
+
!method_exists( $this, "step" . $this->options->currentStep )
|
146 |
+
);
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Check if current operation is done on the root folder or on the live DB
|
151 |
+
* @return boolean
|
152 |
+
*/
|
153 |
+
protected function isRoot() {
|
154 |
+
|
155 |
+
// Prefix is the same as the one of live site
|
|
|
156 |
// $wpdb = WPStaging::getInstance()->get( "wpdb" );
|
157 |
// if( $wpdb->prefix === $this->prefix ) {
|
158 |
// return true;
|
159 |
// }
|
160 |
+
// CloneName is empty
|
161 |
+
$name = ( array ) $this->options->cloneDirectoryName;
|
162 |
+
if( empty( $name ) ) {
|
163 |
+
return true;
|
164 |
+
}
|
165 |
+
|
166 |
+
// Live domain === Staging domain
|
167 |
+
if( $this->multisiteHomeDomain . $this->options->cloneDirectoryName === $this->multisiteHomeDomain ) {
|
168 |
+
return true;
|
169 |
+
}
|
170 |
+
|
171 |
+
return false;
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Check if table exists
|
176 |
+
* @param string $table
|
177 |
+
* @return boolean
|
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;
|
185 |
+
}
|
186 |
+
|
187 |
+
/**
|
188 |
+
* Return absolute destination path
|
189 |
+
* @return string
|
190 |
+
*/
|
191 |
+
// private function getAbsDestination() {
|
192 |
+
// if( empty( $this->options->cloneDir ) ) {
|
193 |
+
// return \WPStaging\WPStaging::getWPpath();
|
194 |
+
// }
|
195 |
+
// return trailingslashit( $this->options->cloneDir );
|
196 |
+
// }
|
197 |
+
|
198 |
+
/**
|
199 |
+
* Copy wp-config.php if it is located outside of root one level up
|
200 |
+
* @todo Needs some more testing before it will be released
|
201 |
+
* @return boolean
|
202 |
+
*/
|
203 |
+
protected function step0() {
|
204 |
+
$this->log( "Preparing Data Step0: Check if wp-config.php is located in root path", Logger::TYPE_INFO );
|
205 |
+
|
206 |
+
$dir = trailingslashit( dirname( ABSPATH ) );
|
207 |
+
|
208 |
+
$source = $dir . 'wp-config.php';
|
209 |
+
|
210 |
+
$destination = $this->options->destinationDir . 'wp-config.php';
|
211 |
+
|
212 |
+
|
213 |
+
// Do not do anything
|
214 |
+
if( (!is_file( $source ) && !is_link( $source )) || is_file( $destination ) ) {
|
215 |
+
$this->log( "Preparing Data Step0: Skip it", Logger::TYPE_INFO );
|
216 |
+
return true;
|
217 |
+
}
|
218 |
+
|
219 |
+
// Copy target of a symbolic link
|
220 |
+
if( is_link( $source ) ) {
|
221 |
+
$this->log( "Preparing Data Step0: Symbolic link found...", Logger::TYPE_INFO );
|
222 |
+
if( !@copy( readlink( $source ), $destination ) ) {
|
223 |
+
$errors = error_get_last();
|
224 |
+
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
225 |
+
return true;
|
226 |
+
}
|
227 |
+
}
|
228 |
+
|
229 |
+
// Copy file wp-config.php
|
230 |
+
if( !@copy( $source, $destination ) ) {
|
231 |
$errors = error_get_last();
|
232 |
$this->log( "Preparing Data Step0: Failed to copy wp-config.php! Error: {$errors['message']} {$source} -> {$destination}", Logger::TYPE_ERROR );
|
233 |
return true;
|
234 |
+
}
|
235 |
+
$this->log( "Preparing Data Step0: Successfull", Logger::TYPE_INFO );
|
236 |
+
return true;
|
237 |
+
}
|
238 |
+
|
239 |
+
/**
|
240 |
+
* Replace "siteurl" and "home"
|
241 |
+
* @return bool
|
242 |
+
*/
|
243 |
+
protected function step1() {
|
244 |
+
$this->log( "Preparing Data Step1: Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
|
245 |
+
|
246 |
+
// Skip - Table does not exist
|
247 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
248 |
+
return true;
|
249 |
+
}
|
250 |
+
// Skip - Table is not selected or updated
|
251 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
252 |
+
$this->log( "Preparing Data Step1: Skipping" );
|
253 |
+
return true;
|
254 |
+
}
|
255 |
+
|
256 |
+
// Installed in sub-directory
|
257 |
+
// if( $this->isSubDir() ) {
|
258 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName );
|
259 |
+
// // Replace URLs
|
260 |
+
// $result = $this->db->query(
|
261 |
+
// $this->db->prepare(
|
262 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName
|
263 |
+
// )
|
264 |
+
// );
|
265 |
+
// } else
|
266 |
+
// {
|
267 |
+
// $this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . rtrim( $this->multisiteHomeDomain, "/" ) . '/' . $this->options->cloneDirectoryName );
|
268 |
+
// // Replace URLs
|
269 |
+
// $result = $this->db->query(
|
270 |
+
// $this->db->prepare(
|
271 |
+
// "UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->multisiteHomeDomain . '/' . $this->options->cloneDirectoryName
|
272 |
+
// )
|
273 |
+
// );
|
274 |
+
// }
|
275 |
+
|
276 |
+
$this->log( "Preparing Data Step1: Updating siteurl and homeurl to " . $this->getStagingSiteUrl() );
|
277 |
+
// Replace URLs
|
278 |
+
$result = $this->db->query(
|
279 |
+
$this->db->prepare(
|
280 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'siteurl' or option_name='home'", $this->getStagingSiteUrl()
|
281 |
+
)
|
282 |
+
);
|
283 |
+
|
284 |
+
|
285 |
+
|
286 |
+
// All good
|
287 |
+
if( $result ) {
|
288 |
+
return true;
|
289 |
+
}
|
290 |
+
|
291 |
+
$this->log( "Preparing Data Step1: Failed to update siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
292 |
+
return false;
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Update "wpstg_is_staging_site"
|
297 |
+
* @return bool
|
298 |
+
*/
|
299 |
+
protected function step2() {
|
300 |
+
|
301 |
+
$this->log( "Preparing Data Step2: Updating row wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}" );
|
302 |
+
|
303 |
+
// Skip - Table does not exist
|
304 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
305 |
+
return true;
|
306 |
+
}
|
307 |
+
// Skip - Table is not selected or updated
|
308 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
309 |
+
$this->log( "Preparing Data Step2: Skipping" );
|
310 |
+
return true;
|
311 |
+
}
|
312 |
+
|
313 |
+
$result = $this->db->query(
|
314 |
+
$this->db->prepare(
|
315 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_is_staging_site'", "true"
|
316 |
+
)
|
317 |
+
);
|
318 |
+
|
319 |
+
// No errors but no option name such as wpstg_is_staging_site
|
320 |
+
if( '' === $this->db->last_error && 0 == $result ) {
|
321 |
+
$result = $this->db->query(
|
322 |
+
$this->db->prepare(
|
323 |
+
"INSERT INTO {$this->prefix}options (option_name,option_value) VALUES ('wpstg_is_staging_site',%s)", "true"
|
324 |
+
)
|
325 |
+
);
|
326 |
+
}
|
327 |
+
|
328 |
+
// All good
|
329 |
+
if( $result ) {
|
330 |
+
return true;
|
331 |
+
}
|
332 |
+
|
333 |
+
$this->log( "Preparing Data Step2: Failed to update wpstg_is_staging_site in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
334 |
+
return false;
|
335 |
+
}
|
336 |
+
|
337 |
+
/**
|
338 |
+
* Update rewrite_rules
|
339 |
+
* @return bool
|
340 |
+
*/
|
341 |
+
protected function step3() {
|
342 |
+
|
343 |
+
$this->log( "Preparing Data Step3: Updating rewrite_rules in {$this->prefix}options {$this->db->last_error}" );
|
344 |
+
|
345 |
+
// Skip - Table does not exist
|
346 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
347 |
+
return true;
|
348 |
+
}
|
349 |
+
|
350 |
+
// Skip - Table is not selected or updated
|
351 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
352 |
+
$this->log( "Preparing Data Step3: Skipping" );
|
353 |
+
return true;
|
354 |
+
}
|
355 |
+
|
356 |
+
$result = $this->db->query(
|
357 |
+
$this->db->prepare(
|
358 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'rewrite_rules'", ' '
|
359 |
+
)
|
360 |
+
);
|
361 |
+
|
362 |
+
// All good
|
363 |
+
if( $result ) {
|
364 |
+
return true;
|
365 |
+
}
|
366 |
+
|
367 |
+
$this->log( "Preparing Data Step3: Failed to update rewrite_rules in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
368 |
+
return true;
|
369 |
+
}
|
370 |
+
|
371 |
+
/**
|
372 |
+
* Update Table Prefix in wp_usermeta
|
373 |
+
* @return bool
|
374 |
+
*/
|
375 |
+
protected function step4() {
|
376 |
+
$this->log( "Preparing Data Step4: Updating db prefix in {$this->prefix}usermeta. " );
|
377 |
+
|
378 |
+
// Skip - Table does not exist
|
379 |
+
if( false === $this->isTable( $this->prefix . 'usermeta' ) ) {
|
380 |
+
return true;
|
381 |
+
}
|
382 |
+
|
383 |
+
// Skip - Table is not selected or updated
|
384 |
+
if( !in_array( $this->prefix . 'usermeta', $this->tables ) ) {
|
385 |
+
$this->log( "Preparing Data Step4: Skipping" );
|
386 |
+
return true;
|
387 |
+
}
|
388 |
+
|
389 |
+
// Skip, prefixes are identical. No change needed
|
390 |
+
// if( $this->db->prefix === $this->prefix ) {
|
391 |
+
// $this->log( "Preparing Data Step4: Skipping" );
|
392 |
+
// return true;
|
393 |
+
// }
|
394 |
+
|
395 |
+
$update = $this->db->query(
|
396 |
+
$this->db->prepare(
|
397 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->productionDb->base_prefix, $this->prefix, $this->productionDb->base_prefix . "_%"
|
398 |
+
)
|
399 |
+
);
|
400 |
+
|
401 |
+
if( !$update ) {
|
402 |
+
$this->log( "Preparing Data Step4a: Skip updating {$this->prefix}usermeta meta_key database base_prefix; {$this->db->last_error}", Logger::TYPE_INFO );
|
403 |
+
//return true;
|
404 |
+
}
|
405 |
+
|
406 |
+
$update = $this->db->query(
|
407 |
+
$this->db->prepare(
|
408 |
+
"UPDATE {$this->prefix}usermeta SET meta_key = replace(meta_key, %s, %s) WHERE meta_key LIKE %s", $this->db->prefix, $this->prefix, $this->db->prefix . "_%"
|
409 |
+
)
|
410 |
+
);
|
411 |
+
|
412 |
+
if( !$update ) {
|
413 |
+
$this->log( "Preparing Data Step4: Skip updating {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}", Logger::TYPE_INFO );
|
414 |
+
//$this->returnException( "Data Crunching Step 4: Failed to update {$this->prefix}usermeta meta_key database table prefixes; {$this->db->last_error}" );
|
415 |
+
return true;
|
416 |
+
}
|
417 |
+
return true;
|
418 |
+
}
|
419 |
+
|
420 |
+
/**
|
421 |
+
* Update $table_prefix in wp-config.php
|
422 |
+
* @return bool
|
423 |
+
*/
|
424 |
+
protected function step5() {
|
425 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
426 |
+
|
427 |
+
$this->log( "Preparing Data Step5: Updating table_prefix in {$path} to " . $this->prefix );
|
428 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
429 |
+
$this->log( "Preparing Data Step5: Failed to update table_prefix in {$path}. Can't read contents", Logger::TYPE_ERROR );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
430 |
return false;
|
431 |
+
}
|
|
|
|
|
|
|
432 |
|
433 |
+
// Replace table prefix
|
434 |
+
$content = str_replace( '$table_prefix', '$table_prefix = \'' . $this->prefix . '\';//', $content );
|
|
|
|
|
|
|
|
|
|
|
435 |
|
436 |
+
// Replace URLs
|
437 |
+
$content = str_replace( $this->multisiteHomeDomain, $this->getStagingSiteUrl(), $content );
|
|
|
|
|
|
|
|
|
438 |
|
439 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
440 |
+
$this->log( "Preparing Data Step5: Failed to update $table_prefix in {$path} to " . $this->prefix . ". Can't save contents", Logger::TYPE_ERROR );
|
441 |
+
return false;
|
442 |
+
}
|
443 |
+
|
444 |
+
return true;
|
445 |
+
}
|
446 |
+
|
447 |
+
/**
|
448 |
+
* Reset index.php to original file
|
449 |
+
* This is needed if live site is located in subfolder
|
450 |
+
* Check first if main wordpress is used in subfolder and index.php in parent directory
|
451 |
+
* @see: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
|
452 |
+
* @return bool
|
453 |
+
*/
|
454 |
+
protected function step6() {
|
455 |
+
|
456 |
+
if( !$this->isSubDir() ) {
|
457 |
+
$this->debugLog( "Preparing Data Step6: WP installation is not in a subdirectory! All good, skipping this step" );
|
458 |
+
return true;
|
459 |
+
}
|
460 |
+
|
461 |
+
$path = $this->options->destinationDir . "index.php";
|
462 |
+
|
463 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
464 |
+
$this->log( "Preparing Data Step6: Failed to reset {$path} for sub directory; can't read contents", Logger::TYPE_ERROR );
|
465 |
+
return false;
|
466 |
+
}
|
467 |
|
|
|
|
|
|
|
|
|
468 |
|
469 |
+
if( !preg_match( "/(require(.*)wp-blog-header.php' \);)/", $content, $matches ) ) {
|
470 |
+
$this->log(
|
471 |
+
"Preparing Data Step6: Failed to reset index.php for sub directory; wp-blog-header.php is missing", Logger::TYPE_ERROR
|
472 |
+
);
|
473 |
+
return false;
|
474 |
+
}
|
475 |
+
$this->log( "Preparing Data: WP installation is in a subdirectory. Progressing..." );
|
476 |
|
477 |
+
$pattern = "/require(.*) dirname(.*) __FILE__ (.*) \. '(.*)wp-blog-header.php'(.*);/";
|
|
|
478 |
|
479 |
+
$replace = "require( dirname( __FILE__ ) . '/wp-blog-header.php' ); // " . $matches[0];
|
480 |
+
$replace.= " // Changed by WP-Staging";
|
481 |
|
|
|
482 |
|
|
|
|
|
483 |
|
484 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
485 |
+
$this->log( "Preparing Data: Failed to reset index.php for sub directory; replacement failed", Logger::TYPE_ERROR );
|
486 |
return false;
|
487 |
+
}
|
|
|
|
|
|
|
488 |
|
489 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
490 |
+
$this->log( "Preparing Data: Failed to reset index.php for sub directory; can't save contents", Logger::TYPE_ERROR );
|
491 |
+
return false;
|
492 |
+
}
|
493 |
+
$this->Log( "Preparing Data: Finished Step 6 successfully" );
|
494 |
+
return true;
|
495 |
+
}
|
496 |
|
497 |
+
/**
|
498 |
+
* Update wpstg_rmpermalinks_executed
|
499 |
+
* @return bool
|
500 |
+
*/
|
501 |
+
protected function step7() {
|
|
|
|
|
502 |
|
503 |
+
$this->log( "Preparing Data Step7: Updating wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}" );
|
|
|
|
|
|
|
|
|
|
|
504 |
|
505 |
+
// Skip - Table does not exist
|
506 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
507 |
+
return true;
|
508 |
+
}
|
509 |
|
510 |
+
// Skip - Table is not selected or updated
|
511 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
512 |
+
$this->log( "Preparing Data Step7: Skipping" );
|
513 |
+
return true;
|
514 |
+
}
|
515 |
|
516 |
+
$result = $this->db->query(
|
517 |
+
$this->db->prepare(
|
518 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'wpstg_rmpermalinks_executed'", ' '
|
519 |
+
)
|
520 |
+
);
|
521 |
|
522 |
+
// All good
|
523 |
+
if( $result ) {
|
524 |
+
$this->Log( "Preparing Data Step7: Finished Step 7 successfully" );
|
525 |
+
return true;
|
526 |
+
}
|
527 |
|
528 |
+
$this->log( "Failed to update wpstg_rmpermalinks_executed in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_WARNING );
|
529 |
+
return true;
|
530 |
+
}
|
531 |
|
532 |
+
/**
|
533 |
+
* Update permalink_structure
|
534 |
+
* @return bool
|
535 |
+
*/
|
536 |
+
protected function step8() {
|
537 |
|
538 |
+
$this->log( "Preparing Data Step8: Updating permalink_structure in {$this->prefix}options {$this->db->last_error}" );
|
|
|
539 |
|
540 |
+
// Skip - Table does not exist
|
541 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
542 |
+
return true;
|
543 |
+
}
|
544 |
+
|
545 |
+
// Skip - Table is not selected or updated
|
546 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
547 |
+
$this->log( "Preparing Data Step8: Skipping" );
|
548 |
+
return true;
|
549 |
+
}
|
550 |
+
|
551 |
+
$result = $this->db->query(
|
552 |
+
$this->db->prepare(
|
553 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'permalink_structure'", ' '
|
554 |
+
)
|
555 |
+
);
|
556 |
+
|
557 |
+
// All good
|
558 |
+
if( $result ) {
|
559 |
+
$this->Log( "Preparing Data Step8: Finished Step 8 successfully" );
|
560 |
+
return true;
|
561 |
+
}
|
562 |
+
|
563 |
+
$this->log( "Failed to update permalink_structure in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
|
564 |
+
return true;
|
565 |
+
}
|
566 |
+
|
567 |
+
/**
|
568 |
+
* Update blog_public option to not allow staging site to be indexed by search engines
|
569 |
+
* @return bool
|
570 |
+
*/
|
571 |
+
protected function step9() {
|
572 |
+
|
573 |
+
$this->log( "Preparing Data Step9: Set staging site to noindex" );
|
574 |
+
|
575 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
576 |
+
return true;
|
577 |
+
}
|
578 |
+
|
579 |
+
// Skip - Table is not selected or updated
|
580 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
581 |
+
$this->log( "Preparing Data Step9: Skipping" );
|
582 |
+
return true;
|
583 |
+
}
|
584 |
+
|
585 |
+
$result = $this->db->query(
|
586 |
+
$this->db->prepare(
|
587 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'blog_public'", '0'
|
588 |
+
)
|
589 |
+
);
|
590 |
+
|
591 |
+
// All good
|
592 |
+
if( $result ) {
|
593 |
+
$this->Log( "Preparing Data Step9: Finished Step 9 successfully" );
|
594 |
+
return true;
|
595 |
+
}
|
596 |
+
|
597 |
+
$this->log( "Can not update staging site to noindex. Possible already done!", Logger::TYPE_WARNING );
|
598 |
+
return true;
|
599 |
+
}
|
600 |
+
|
601 |
+
/**
|
602 |
+
* Update WP_HOME in wp-config.php
|
603 |
+
* @return bool
|
604 |
+
*/
|
605 |
+
protected function step10() {
|
606 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
607 |
+
|
608 |
+
$this->log( "Preparing Data Step10: Updating WP_HOME in wp-config.php to " . $this->getStagingSiteUrl() );
|
609 |
+
|
610 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
611 |
+
$this->log( "Preparing Data Step10: Failed to update WP_HOME in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
612 |
return false;
|
613 |
+
}
|
|
|
|
|
|
|
614 |
|
615 |
|
616 |
+
// Get WP_HOME from wp-config.php
|
617 |
+
preg_match( "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
|
|
|
|
|
|
|
|
|
|
618 |
|
619 |
+
if( !empty( $matches[1] ) ) {
|
620 |
+
$matches[1];
|
|
|
|
|
|
|
|
|
621 |
|
622 |
+
$pattern = "/define\s*\(\s*'WP_HOME'\s*,\s*(.*)\s*\);/";
|
623 |
|
624 |
+
$replace = "define('WP_HOME','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
625 |
+
$replace.= " // Changed by WP-Staging";
|
|
|
|
|
626 |
|
627 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
628 |
+
$this->log( "Preparing Data: Failed to update WP_HOME", Logger::TYPE_ERROR );
|
629 |
+
return false;
|
630 |
+
}
|
631 |
+
} else {
|
632 |
+
$this->log( "Preparing Data Step10: WP_HOME not defined in wp-config.php. Skipping this step." );
|
633 |
+
}
|
634 |
|
635 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
636 |
+
$this->log( "Preparing Data Step10: Failed to update WP_HOME. Can't save contents", Logger::TYPE_ERROR );
|
637 |
+
return false;
|
638 |
+
}
|
639 |
+
$this->Log( "Preparing Data: Finished Step 10 successfully" );
|
640 |
+
return true;
|
641 |
+
}
|
642 |
+
|
643 |
+
/**
|
644 |
+
* Update WP_SITEURL in wp-config.php
|
645 |
+
* @return bool
|
646 |
+
*/
|
647 |
+
protected function step11() {
|
648 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
649 |
+
|
650 |
+
$this->log( "Preparing Data Step11: Updating WP_SITEURL in wp-config.php to " . $this->getStagingSiteUrl() );
|
651 |
+
|
652 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
653 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
654 |
+
return false;
|
655 |
+
}
|
656 |
|
|
|
|
|
657 |
|
658 |
+
// Get WP_SITEURL from wp-config.php
|
659 |
+
preg_match( "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/", $content, $matches );
|
660 |
|
661 |
+
if( !empty( $matches[1] ) ) {
|
662 |
+
$matches[1];
|
663 |
|
664 |
+
$pattern = "/define\s*\(\s*'WP_SITEURL'\s*,\s*(.*)\s*\);/";
|
665 |
+
|
666 |
+
$replace = "define('WP_SITEURL','" . $this->getStagingSiteUrl() . "'); // " . $matches[1];
|
667 |
+
$replace.= " // Changed by WP-Staging";
|
668 |
+
|
669 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
670 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL", Logger::TYPE_ERROR );
|
671 |
+
return false;
|
672 |
+
}
|
673 |
+
} else {
|
674 |
+
$this->log( "Preparing Data Step11: WP_SITEURL not defined in wp-config.php. Skipping this step." );
|
675 |
+
}
|
676 |
+
|
677 |
+
|
678 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
679 |
+
$this->log( "Preparing Data Step11: Failed to update WP_SITEURL. Can't save contents", Logger::TYPE_ERROR );
|
680 |
+
return false;
|
681 |
+
}
|
682 |
+
$this->Log( "Preparing Data: Finished Step 11 successfully" );
|
683 |
+
return true;
|
684 |
+
}
|
685 |
+
|
686 |
+
/**
|
687 |
+
* Update WP_ALLOW_MULTISITE constant in wp-config.php
|
688 |
+
* @return bool
|
689 |
+
*/
|
690 |
+
protected function step12() {
|
691 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
692 |
+
|
693 |
+
$this->log( "Preparing Data Step12: Updating WP_ALLOW_MULTISITE in wp-config.php to false" );
|
694 |
+
|
695 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
696 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
697 |
return false;
|
698 |
+
}
|
699 |
+
|
700 |
+
|
701 |
+
// Get WP_SITEURL from wp-config.php
|
702 |
+
preg_match( "/define\s*\(\s*'WP_ALLOW_MULTISITE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
703 |
+
|
704 |
+
if( !empty( $matches[1] ) ) {
|
705 |
+
$matches[1];
|
706 |
+
|
707 |
+
$pattern = "/define\s*\(\s*'WP_ALLOW_MULTISITE'\s*,\s*(.*)\s*\);/";
|
708 |
+
|
709 |
+
$replace = "define('WP_ALLOW_MULTISITE',false); // " . $matches[1];
|
710 |
+
$replace.= " // Changed by WP-Staging";
|
711 |
+
|
712 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
713 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE", Logger::TYPE_ERROR );
|
714 |
+
return false;
|
715 |
+
}
|
716 |
+
} else {
|
717 |
+
$this->log( "Preparing Data Step12: WP_ALLOW_MULTISITE not defined in wp-config.php. Skipping this step." );
|
718 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
719 |
|
720 |
+
|
721 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
722 |
+
$this->log( "Preparing Data Step12: Failed to update WP_ALLOW_MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
723 |
+
return false;
|
724 |
+
}
|
725 |
+
$this->Log( "Preparing Data: Finished Step 12 successfully" );
|
726 |
+
return true;
|
727 |
+
}
|
728 |
+
|
729 |
+
/**
|
730 |
+
* Update MULTISITE constant in wp-config.php
|
731 |
+
* @return bool
|
732 |
+
*/
|
733 |
+
protected function step13() {
|
734 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
735 |
+
|
736 |
+
$this->log( "Preparing Data Step13: Updating MULTISITE in wp-config.php to false" );
|
737 |
+
|
738 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
739 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
740 |
return false;
|
741 |
+
}
|
742 |
+
|
|
|
|
|
743 |
|
744 |
+
// Get WP_SITEURL from wp-config.php
|
745 |
+
preg_match( "/define\s*\(\s*'MULTISITE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
|
|
|
|
|
|
|
|
|
|
746 |
|
747 |
+
if( !empty( $matches[1] ) ) {
|
748 |
+
$matches[1];
|
|
|
|
|
|
|
|
|
749 |
|
750 |
+
$pattern = "/define\s*\(\s*'MULTISITE'\s*,\s*(.*)\s*\);/";
|
751 |
|
752 |
+
$replace = "define('MULTISITE',false); // " . $matches[1];
|
753 |
+
$replace.= " // Changed by WP-Staging";
|
|
|
|
|
754 |
|
755 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
756 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE", Logger::TYPE_ERROR );
|
757 |
+
return false;
|
758 |
+
}
|
759 |
+
} else {
|
760 |
+
$this->log( "Preparing Data Step13: MULTISITE not defined in wp-config.php. Skipping this step." );
|
761 |
+
}
|
762 |
|
|
|
|
|
763 |
|
764 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
765 |
+
$this->log( "Preparing Data Step13: Failed to update MULTISITE. Can't save contents", Logger::TYPE_ERROR );
|
766 |
+
return false;
|
767 |
+
}
|
768 |
+
$this->Log( "Preparing Data: Finished Step 13 successfully" );
|
769 |
+
return true;
|
770 |
+
}
|
771 |
+
|
772 |
+
/**
|
773 |
+
* Get active_sitewide_plugins from wp_sitemeta and active_plugins from subsite
|
774 |
+
* Merge both arrays and copy them to the staging site into active_plugins
|
775 |
+
*/
|
776 |
+
protected function step14() {
|
777 |
|
|
|
778 |
|
779 |
+
$this->log( "Data Crunching Step 14: Updating active_plugins" );
|
|
|
780 |
|
781 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
782 |
+
$this->log( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
783 |
+
$this->returnException( 'Data Crunching Step 14: Fatal Error ' . $this->prefix . 'options does not exist' );
|
784 |
return false;
|
785 |
+
}
|
786 |
+
|
787 |
+
// Skip - Table is not selected or updated
|
788 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
789 |
+
$this->log( "Preparing Data Step14: Skipping" );
|
790 |
+
return true;
|
791 |
+
}
|
792 |
+
|
793 |
+
// Get active_plugins value from sub site options table
|
794 |
+
$active_plugins = $this->productionDb->get_var( "SELECT option_value FROM {$this->productionDb->prefix}options WHERE option_name = 'active_plugins' " );
|
795 |
+
|
796 |
+
if( !$active_plugins ) {
|
797 |
+
$this->log( "Data Crunching Step 14: Option active_plugins are empty " );
|
798 |
+
$active_plugins = array();
|
799 |
+
}
|
800 |
+
// Get active_sitewide_plugins value from main multisite wp_sitemeta table
|
801 |
+
$active_sitewide_plugins = $this->productionDb->get_var( "SELECT meta_value FROM {$this->productionDb->base_prefix}sitemeta WHERE meta_key = 'active_sitewide_plugins' " );
|
802 |
+
|
803 |
+
if( !$active_sitewide_plugins ) {
|
804 |
+
$this->log( "Data Crunching Step 14: Options {$this->productionDb->base_prefix}active_sitewide_plugins is empty " );
|
805 |
+
$active_sitewide_plugins = array();
|
806 |
+
}
|
807 |
+
|
808 |
+
$active_sitewide_plugins = unserialize( $active_sitewide_plugins );
|
809 |
+
$active_plugins = unserialize( $active_plugins );
|
810 |
+
|
811 |
+
$all_plugins = array_merge( $active_plugins, array_keys( $active_sitewide_plugins ) );
|
812 |
+
|
813 |
+
sort( $all_plugins );
|
814 |
+
|
815 |
+
|
816 |
+
// Update active_plugins
|
817 |
+
$update = $this->db->query(
|
818 |
+
"UPDATE {$this->prefix}options SET option_value = '" . serialize( $all_plugins ) . "' WHERE option_name = 'active_plugins'"
|
819 |
+
);
|
820 |
+
|
821 |
+
if( false === $update ) {
|
822 |
+
$this->log( "Data Crunching Step 14: Can not update option active_plugins in {$this->prefix}options", Logger::TYPE_WARNING );
|
823 |
+
return false;
|
824 |
+
}
|
825 |
+
|
826 |
+
$this->log( "Data Crunching Step 14: Successfull!" );
|
827 |
+
return true;
|
828 |
+
}
|
829 |
+
|
830 |
+
/**
|
831 |
+
* Update Table Prefix in wp_options
|
832 |
+
* @return bool
|
833 |
+
*/
|
834 |
+
protected function step15() {
|
835 |
+
$this->log( "Preparing Data Step15: Updating db prefix in {$this->prefix}options." );
|
836 |
+
|
837 |
+
// Skip - Table does not exist
|
838 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
839 |
+
return true;
|
840 |
+
}
|
841 |
+
|
842 |
+
// Skip - Table is not selected or updated
|
843 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
844 |
+
$this->log( "Preparing Data Step4: Skipping" );
|
845 |
+
return true;
|
846 |
+
}
|
847 |
+
|
848 |
+
// Skip, prefixes are identical. No change needed
|
849 |
+
// if( $this->productionDb->prefix === $this->prefix ) {
|
850 |
+
// $this->log( "Preparing Data Step4: Skipping" );
|
851 |
+
// return true;
|
852 |
+
// }
|
853 |
+
|
854 |
+
$this->log( "Updating db option_names in {$this->prefix}options. " );
|
855 |
+
|
856 |
+
// Filter the rows below. Do not update them!
|
857 |
+
$filters = array(
|
858 |
+
'wp_mail_smtp',
|
859 |
+
'wp_mail_smtp_version',
|
860 |
+
'wp_mail_smtp_debug',
|
861 |
+
);
|
862 |
+
|
863 |
+
$filters = apply_filters( 'wpstg_data_excl_rows', $filters );
|
864 |
+
|
865 |
+
$where = "";
|
866 |
+
foreach ( $filters as $filter ) {
|
867 |
+
$where .= " AND option_name <> '" . $filter . "'";
|
868 |
+
}
|
869 |
+
|
870 |
+
$updateOptions = $this->db->query(
|
871 |
+
$this->db->prepare(
|
872 |
+
"UPDATE IGNORE {$this->prefix}options SET option_name= replace(option_name, %s, %s) WHERE option_name LIKE %s" . $where, $this->productionDb->prefix, $this->prefix, $this->productionDb->prefix . "_%"
|
873 |
+
)
|
874 |
+
);
|
875 |
+
|
876 |
+
if( !$updateOptions ) {
|
877 |
+
$this->log( "Preparing Data Step15: Skip updating db option_names in {$this->prefix}options. Error: {$this->db->last_error}", Logger::TYPE_WARNING );
|
878 |
+
//$this->returnException( "Data Crunching Step 15: Failed to update db option_names in {$this->prefix}options. Error: {$this->db->last_error}" );
|
879 |
+
return true;
|
880 |
+
}
|
881 |
+
|
882 |
+
|
883 |
+
return true;
|
884 |
+
}
|
885 |
+
|
886 |
+
/**
|
887 |
+
* Change upload_path in wp_options (if it is defined)
|
888 |
+
* @return bool
|
889 |
+
*/
|
890 |
+
protected function step16() {
|
891 |
+
$this->log( "Preparing Data Step16: Updating upload_path {$this->prefix}options." );
|
892 |
+
|
893 |
+
// Skip - Table does not exist
|
894 |
+
if( false === $this->isTable( $this->prefix . 'options' ) ) {
|
895 |
+
return true;
|
896 |
+
}
|
897 |
+
|
898 |
+
$newUploadPath = $this->getNewUploadPath();
|
899 |
+
|
900 |
+
if( false === $newUploadPath ) {
|
901 |
+
$this->log( "Preparing Data Step16: Skipping" );
|
902 |
+
return true;
|
903 |
+
}
|
904 |
+
|
905 |
+
// Skip - Table is not selected or updated
|
906 |
+
if( !in_array( $this->prefix . 'options', $this->tables ) ) {
|
907 |
+
$this->log( "Preparing Data Step16: Skipping" );
|
908 |
+
return true;
|
909 |
+
}
|
910 |
|
911 |
+
$error = isset( $this->db->last_error ) ? 'Last error: ' . $this->db->last_error : '';
|
|
|
912 |
|
913 |
+
$this->log( "Updating upload_path in {$this->prefix}options. {$error}" );
|
914 |
|
915 |
+
$updateOptions = $this->db->query(
|
916 |
+
$this->db->prepare(
|
917 |
+
"UPDATE {$this->prefix}options SET option_value = %s WHERE option_name = 'upload_path'", $newUploadPath
|
918 |
+
)
|
919 |
+
);
|
920 |
|
921 |
+
if( !$updateOptions ) {
|
922 |
+
$this->log( "Preparing Data Step16: Failed to update upload_path in {$this->prefix}options. {$error}", Logger::TYPE_ERROR );
|
923 |
+
return true;
|
924 |
+
}
|
925 |
+
$this->Log( "Preparing Data: Finished Step 16 successfully" );
|
926 |
+
return true;
|
927 |
+
}
|
928 |
+
|
929 |
+
/**
|
930 |
+
* Update WP_CACHE in wp-config.php
|
931 |
+
* @return bool
|
932 |
+
*/
|
933 |
+
protected function step17() {
|
934 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
935 |
+
|
936 |
+
$this->log( "Preparing Data Step17: Set WP_CACHE in wp-config.php to false" );
|
937 |
+
|
938 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
939 |
+
$this->log( "Preparing Data Step17: Failed to update WP_CACHE in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
940 |
return false;
|
941 |
+
}
|
942 |
+
|
943 |
+
|
944 |
+
// Get WP_CACHE from wp-config.php
|
945 |
+
preg_match( "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/", $content, $matches );
|
|
|
946 |
|
947 |
+
if( !empty( $matches[1] ) ) {
|
948 |
+
$matches[1];
|
949 |
|
950 |
+
$pattern = "/define\s*\(\s*'WP_CACHE'\s*,\s*(.*)\s*\);/";
|
951 |
|
952 |
+
$replace = "define('WP_CACHE',false); // " . $matches[1];
|
953 |
+
$replace.= " // Changed by WP-Staging";
|
954 |
|
955 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
956 |
+
$this->log( "Preparing Data: Failed to change WP_CACHE", Logger::TYPE_ERROR );
|
957 |
+
return false;
|
958 |
+
}
|
959 |
+
} else {
|
960 |
+
$this->log( "Preparing Data Step17: WP_CACHE not defined in wp-config.php. Skipping this step." );
|
961 |
+
}
|
962 |
+
|
963 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
964 |
+
$this->log( "Preparing Data Step17: Failed to update WP_CACHE. Can't save contents", Logger::TYPE_ERROR );
|
965 |
+
return false;
|
966 |
+
}
|
967 |
+
$this->Log( "Preparing Data: Finished Step 17 successfully" );
|
968 |
+
return true;
|
969 |
+
}
|
970 |
+
|
971 |
+
/**
|
972 |
+
* Update database credentials in wp-config.php
|
973 |
+
* @return bool
|
974 |
+
*/
|
975 |
+
protected function step18() {
|
976 |
+
$path = $this->options->destinationDir . "wp-config.php";
|
977 |
+
|
978 |
+
$this->log( "Preparing Data Step18: Change database credentials in wp-config.php" );
|
979 |
+
|
980 |
+
if( false === ($content = file_get_contents( $path )) ) {
|
981 |
+
$this->log( "Preparing Data Step18: Failed to update database credentials in wp-config.php. Can't read wp-config.php", Logger::TYPE_ERROR );
|
982 |
return false;
|
983 |
+
}
|
984 |
+
|
985 |
+
|
986 |
+
// Get DB_NAME from wp-config.php
|
987 |
+
preg_match( "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);/", $content, $matches );
|
988 |
+
|
989 |
+
if( !empty( $matches[1] ) ) {
|
990 |
+
$matches[1];
|
991 |
+
|
992 |
+
$pattern = "/define\s*\(\s*'DB_NAME'\s*,\s*(.*)\s*\);/";
|
993 |
+
|
994 |
+
$replace = "define('DB_NAME','{$this->options->databaseDatabase}'); // " . $matches[1];
|
995 |
+
$replace.= " // Changed by WP-Staging";
|
996 |
+
|
997 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
998 |
+
$this->log( "Preparing Data: Failed to change DB_NAME", Logger::TYPE_ERROR );
|
999 |
+
return false;
|
1000 |
+
}
|
1001 |
+
} else {
|
1002 |
+
$this->log( "Preparing Data Step18: DB_NAME not defined in wp-config.php. Skipping this step." );
|
1003 |
+
}
|
1004 |
+
// Get DB_USER from wp-config.php
|
1005 |
+
preg_match( "/define\s*\(\s*'DB_USER'\s*,\s*(.*)\s*\);/", $content, $matches );
|
1006 |
|
1007 |
+
if( !empty( $matches[1] ) ) {
|
1008 |
+
$matches[1];
|
1009 |
|
1010 |
+
$pattern = "/define\s*\(\s*'DB_USER'\s*,\s*(.*)\s*\);/";
|
1011 |
|
1012 |
+
$replace = "define('DB_USER','{$this->options->databaseUser}'); // " . $matches[1];
|
1013 |
+
$replace.= " // Changed by WP-Staging";
|
1014 |
|
1015 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
1016 |
+
$this->log( "Preparing Data: Failed to change DB_USER", Logger::TYPE_ERROR );
|
1017 |
+
return false;
|
1018 |
+
}
|
1019 |
+
} else {
|
1020 |
+
$this->log( "Preparing Data Step18: DB_USER not defined in wp-config.php. Skipping this step." );
|
1021 |
+
}
|
1022 |
+
// Get DB_PASSWORD from wp-config.php
|
1023 |
+
preg_match( "/define\s*\(\s*'DB_PASSWORD'\s*,\s*(.*)\s*\);/", $content, $matches );
|
1024 |
+
|
1025 |
+
if( !empty( $matches[1] ) ) {
|
1026 |
+
$matches[1];
|
1027 |
+
|
1028 |
+
$pattern = "/define\s*\(\s*'DB_PASSWORD'\s*,\s*(.*)\s*\);/";
|
1029 |
+
|
1030 |
+
$replace = "define('DB_PASSWORD','{$this->options->databasePassword}'); // " . $matches[1];
|
1031 |
+
$replace.= " // Changed by WP-Staging";
|
1032 |
+
|
1033 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
1034 |
+
$this->log( "Preparing Data: Failed to change DB_PASSWORD", Logger::TYPE_ERROR );
|
1035 |
+
return false;
|
1036 |
+
}
|
1037 |
+
} else {
|
1038 |
+
$this->log( "Preparing Data Step18: DB_PASSWORD not defined in wp-config.php. Skipping this step." );
|
1039 |
+
}
|
1040 |
+
// Get DB_HOST from wp-config.php
|
1041 |
+
preg_match( "/define\s*\(\s*'DB_HOST'\s*,\s*(.*)\s*\);/", $content, $matches );
|
1042 |
+
|
1043 |
+
if( !empty( $matches[1] ) ) {
|
1044 |
+
$matches[1];
|
1045 |
+
|
1046 |
+
$pattern = "/define\s*\(\s*'DB_HOST'\s*,\s*(.*)\s*\);/";
|
1047 |
+
|
1048 |
+
$replace = "define('DB_HOST','{$this->options->databaseServer}'); // " . $matches[1];
|
1049 |
+
$replace.= " // Changed by WP-Staging";
|
1050 |
+
|
1051 |
+
if( null === ($content = preg_replace( array($pattern), $replace, $content )) ) {
|
1052 |
+
$this->log( "Preparing Data: Failed to change DB_HOST", Logger::TYPE_ERROR );
|
1053 |
+
return false;
|
1054 |
+
}
|
1055 |
+
} else {
|
1056 |
+
$this->log( "Preparing Data Step18: DB_HOST not defined in wp-config.php. Skipping this step." );
|
1057 |
+
}
|
1058 |
+
|
1059 |
+
|
1060 |
+
if( false === @file_put_contents( $path, $content ) ) {
|
1061 |
+
$this->log( "Preparing Data Step18: Failed to update database credentials in wp-config.php. Can't save contents", Logger::TYPE_ERROR );
|
1062 |
+
return false;
|
1063 |
+
}
|
1064 |
+
$this->Log( "Preparing Data: Finished Step 18 successfully" );
|
1065 |
+
return true;
|
1066 |
+
}
|
1067 |
+
|
1068 |
+
/**
|
1069 |
+
* Get upload path
|
1070 |
+
* @return boolean|string
|
1071 |
+
*/
|
1072 |
+
protected function getNewUploadPath() {
|
1073 |
+
$uploadPath = get_option( 'upload_path' );
|
1074 |
+
|
1075 |
+
if( !$uploadPath ) {
|
1076 |
return false;
|
1077 |
+
}
|
1078 |
+
|
1079 |
+
$customSlug = str_replace( \WPStaging\WPStaging::getWPpath(), '', $uploadPath );
|
1080 |
+
|
1081 |
+
$newUploadPath = \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR . $customSlug;
|
1082 |
+
|
1083 |
+
return $newUploadPath;
|
1084 |
+
}
|
1085 |
+
|
1086 |
+
/**
|
1087 |
+
* Return URL to staging site
|
1088 |
+
* @return string
|
1089 |
+
*/
|
1090 |
+
protected function getStagingSiteUrl() {
|
1091 |
+
|
1092 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
1093 |
+
return $this->options->cloneHostname;
|
1094 |
+
}
|
1095 |
+
|
1096 |
+
if( $this->isSubDir() ) {
|
1097 |
+
return trailingslashit( $this->multisiteHomeDomain) . trailingslashit( $this->getSubDir() ) . $this->options->cloneDirectoryName;
|
1098 |
+
}
|
1099 |
+
|
1100 |
+
return trailingslashit( $this->multisiteHomeDomain) . $this->options->cloneDirectoryName;
|
1101 |
+
}
|
1102 |
+
|
1103 |
+
/**
|
1104 |
+
* Check if WP is installed in subdir
|
1105 |
+
* @return boolean
|
1106 |
+
*/
|
1107 |
+
protected function isSubDir() {
|
1108 |
+
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
1109 |
+
// This is happening much more often than you would expect
|
1110 |
+
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
1111 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
1112 |
+
|
1113 |
+
if( $home !== $siteurl ) {
|
1114 |
+
return true;
|
1115 |
+
}
|
1116 |
+
return false;
|
1117 |
+
}
|
1118 |
+
|
1119 |
+
/**
|
1120 |
+
* Get the install sub directory if WP is installed in sub directory
|
1121 |
+
* @return string
|
1122 |
+
*/
|
1123 |
+
protected function getSubDir() {
|
1124 |
+
$home = get_option( 'home' );
|
1125 |
+
$siteurl = get_option( 'siteurl' );
|
1126 |
+
|
1127 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
1128 |
+
return '';
|
1129 |
+
}
|
1130 |
+
|
1131 |
+
$dir = str_replace( $home, '', $siteurl );
|
1132 |
+
return str_replace( '/', '', $dir );
|
1133 |
+
}
|
|
|
|
|
1134 |
|
1135 |
}
|
@@ -31,22 +31,35 @@ class Database extends JobExecutable {
|
|
31 |
* Initialize
|
32 |
*/
|
33 |
public function initialize() {
|
34 |
-
// Add 2 to total table count because we need to copy two more tables from the main multisite installation wp_users and wp_usermeta
|
35 |
-
$this->total = count( $this->options->tables ) + 2;
|
36 |
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
|
|
|
|
|
|
37 |
$this->isFatalError();
|
|
|
|
|
|
|
|
|
|
|
38 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
39 |
}
|
40 |
-
|
41 |
-
|
42 |
/**
|
43 |
* Return fatal error and stops here if subfolder already exists
|
44 |
* and mainJob is not updating the clone
|
45 |
* @return boolean
|
46 |
*/
|
47 |
-
private function isFatalError(){
|
48 |
-
$path = trailingslashit(get_home_path()) . $this->options->cloneDirectoryName;
|
49 |
-
if
|
50 |
$this->returnException( " Can not continue! Change the name of the clone or delete existing folder. Then try again. Folder already exists: " . $path );
|
51 |
}
|
52 |
return false;
|
@@ -57,7 +70,7 @@ class Database extends JobExecutable {
|
|
57 |
* @return void
|
58 |
*/
|
59 |
protected function calculateTotalSteps() {
|
60 |
-
$this->options->totalSteps = $this->total === 0 ? 1 : $this->total;
|
61 |
}
|
62 |
|
63 |
/**
|
@@ -66,8 +79,8 @@ class Database extends JobExecutable {
|
|
66 |
* @return bool
|
67 |
*/
|
68 |
protected function execute() {
|
69 |
-
|
70 |
-
|
71 |
// Over limits threshold
|
72 |
if( $this->isOverThreshold() ) {
|
73 |
// Prepare response and save current progress
|
@@ -77,15 +90,13 @@ class Database extends JobExecutable {
|
|
77 |
}
|
78 |
|
79 |
// No more steps, finished
|
80 |
-
//if( $this->options->currentStep > $this->total || !isset( $this->options->tables[$this->options->currentStep] ) ) {
|
81 |
if( $this->options->currentStep > $this->total ) {
|
82 |
$this->prepareResponse( true, false );
|
83 |
return false;
|
84 |
}
|
85 |
|
86 |
// Copy table
|
87 |
-
|
88 |
-
if( isset($this->options->tables[$this->options->currentStep]) && !$this->copyTable( $this->options->tables[$this->options->currentStep] ) ) {
|
89 |
// Prepare Response
|
90 |
$this->prepareResponse( false, false );
|
91 |
|
@@ -93,10 +104,12 @@ class Database extends JobExecutable {
|
|
93 |
return true;
|
94 |
}
|
95 |
|
96 |
-
$this->
|
97 |
-
|
98 |
-
|
99 |
-
|
|
|
|
|
100 |
// Prepare Response
|
101 |
$this->prepareResponse();
|
102 |
|
@@ -128,6 +141,15 @@ class Database extends JobExecutable {
|
|
128 |
$tableName = is_object( $tableName ) ? $tableName->name : $tableName;
|
129 |
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->prefix, null, $tableName );
|
130 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
131 |
// Drop table if necessary
|
132 |
$this->dropTable( $newTableName );
|
133 |
|
@@ -150,54 +172,65 @@ class Database extends JobExecutable {
|
|
150 |
* Copy multisite global user table wp_users to wpstgX_users
|
151 |
* @return bool
|
152 |
*/
|
153 |
-
private function copyWpUsers() {
|
154 |
-
$strings = new Strings();
|
155 |
-
$tableName = $this->db->base_prefix . 'users';
|
156 |
-
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
157 |
-
|
158 |
-
|
159 |
-
$this->
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
//
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
175 |
|
176 |
/**
|
177 |
* Copy multisite global user table wp_usermeta to wpstgX_users
|
178 |
* @return bool
|
179 |
*/
|
180 |
-
private function copyWpUsermeta() {
|
181 |
-
$strings = new Strings();
|
182 |
-
$tableName = $this->db->base_prefix . 'usermeta';
|
183 |
-
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
|
|
|
|
|
|
|
|
|
|
201 |
|
202 |
/**
|
203 |
* Copy data from old table to new table
|
@@ -244,10 +277,19 @@ class Database extends JobExecutable {
|
|
244 |
* @return bool
|
245 |
*/
|
246 |
private function startJob( $new, $old ) {
|
|
|
|
|
|
|
247 |
if( 0 != $this->options->job->start ) {
|
248 |
return true;
|
249 |
}
|
250 |
|
|
|
|
|
|
|
|
|
|
|
|
|
251 |
$this->log( "DB Copy: Creating table {$new}" );
|
252 |
|
253 |
$this->db->query( "CREATE TABLE {$new} LIKE {$old}" );
|
@@ -272,7 +314,7 @@ class Database extends JobExecutable {
|
|
272 |
}
|
273 |
|
274 |
// Add it to cloned tables listing
|
275 |
-
$this->options->clonedTables[] = isset($this->options->tables[$this->options->currentStep]) ? $this->options->tables[$this->options->currentStep] : false;
|
276 |
|
277 |
// Reset job
|
278 |
$this->options->job = new \stdClass();
|
@@ -285,6 +327,7 @@ class Database extends JobExecutable {
|
|
285 |
* @param string $new
|
286 |
*/
|
287 |
private function dropTable( $new ) {
|
|
|
288 |
$old = $this->db->get_var( $this->db->prepare( "SHOW TABLES LIKE %s", $new ) );
|
289 |
|
290 |
if( !$this->shouldDropTable( $new, $old ) ) {
|
@@ -302,14 +345,18 @@ class Database extends JobExecutable {
|
|
302 |
* @return bool
|
303 |
*/
|
304 |
private function shouldDropTable( $new, $old ) {
|
305 |
-
|
306 |
-
|
|
|
|
|
307 |
(
|
308 |
!isset( $this->options->job->current ) ||
|
309 |
!isset( $this->options->job->start ) ||
|
310 |
0 == $this->options->job->start
|
311 |
-
)
|
312 |
-
|
|
|
|
|
313 |
}
|
314 |
|
315 |
}
|
31 |
* Initialize
|
32 |
*/
|
33 |
public function initialize() {
|
|
|
|
|
34 |
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
35 |
+
$this->getTables();
|
36 |
+
// Add wp_users and wp_usermeta to the tables object because they are not available in MU installation but we need them on the staging site
|
37 |
+
$this->total = count( $this->options->tables );
|
38 |
$this->isFatalError();
|
39 |
+
}
|
40 |
+
|
41 |
+
private function getTables() {
|
42 |
+
// Add wp_users and wp_usermeta to the tables if they do not exist
|
43 |
+
// because they are not available in MU installation but we need them on the staging site
|
44 |
|
45 |
+
if( !in_array( $this->db->prefix . 'users', $this->options->tables ) ) {
|
46 |
+
array_push( $this->options->tables, $this->db->prefix . 'users' );
|
47 |
+
$this->saveOptions();
|
48 |
+
}
|
49 |
+
if( !in_array( $this->db->prefix . 'usermeta', $this->options->tables ) ) {
|
50 |
+
array_push( $this->options->tables, $this->db->prefix . 'usermeta' );
|
51 |
+
$this->saveOptions();
|
52 |
+
}
|
53 |
}
|
54 |
+
|
|
|
55 |
/**
|
56 |
* Return fatal error and stops here if subfolder already exists
|
57 |
* and mainJob is not updating the clone
|
58 |
* @return boolean
|
59 |
*/
|
60 |
+
private function isFatalError() {
|
61 |
+
$path = trailingslashit( get_home_path() ) . $this->options->cloneDirectoryName;
|
62 |
+
if( isset( $this->options->mainJob ) && $this->options->mainJob !== 'updating' && is_dir( $path ) ) {
|
63 |
$this->returnException( " Can not continue! Change the name of the clone or delete existing folder. Then try again. Folder already exists: " . $path );
|
64 |
}
|
65 |
return false;
|
70 |
* @return void
|
71 |
*/
|
72 |
protected function calculateTotalSteps() {
|
73 |
+
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
74 |
}
|
75 |
|
76 |
/**
|
79 |
* @return bool
|
80 |
*/
|
81 |
protected function execute() {
|
82 |
+
|
83 |
+
|
84 |
// Over limits threshold
|
85 |
if( $this->isOverThreshold() ) {
|
86 |
// Prepare response and save current progress
|
90 |
}
|
91 |
|
92 |
// No more steps, finished
|
|
|
93 |
if( $this->options->currentStep > $this->total ) {
|
94 |
$this->prepareResponse( true, false );
|
95 |
return false;
|
96 |
}
|
97 |
|
98 |
// Copy table
|
99 |
+
if( isset( $this->options->tables[$this->options->currentStep] ) && !$this->copyTable( $this->options->tables[$this->options->currentStep] ) ) {
|
|
|
100 |
// Prepare Response
|
101 |
$this->prepareResponse( false, false );
|
102 |
|
104 |
return true;
|
105 |
}
|
106 |
|
107 |
+
// if( isset( $this->options->tables[$this->options->currentStep] ) && $this->db->prefix . 'users' === $this->options->tables[$this->options->currentStep] ) {
|
108 |
+
// $this->copyWpUsers();
|
109 |
+
// }
|
110 |
+
// if( isset( $this->options->tables[$this->options->currentStep] ) && $this->db->prefix . 'usermeta' === $this->options->tables[$this->options->currentStep] ) {
|
111 |
+
// $this->copyWpUsermeta();
|
112 |
+
// }
|
113 |
// Prepare Response
|
114 |
$this->prepareResponse();
|
115 |
|
141 |
$tableName = is_object( $tableName ) ? $tableName->name : $tableName;
|
142 |
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->prefix, null, $tableName );
|
143 |
|
144 |
+
// Get wp_users from main site
|
145 |
+
if( 'users' === $strings->str_replace_first( $this->db->prefix, null, $tableName ) ) {
|
146 |
+
$tableName = $this->db->base_prefix . 'users';
|
147 |
+
}
|
148 |
+
// Get wp_usermeta from main site
|
149 |
+
if( 'usermeta' === $strings->str_replace_first( $this->db->prefix, null, $tableName ) ) {
|
150 |
+
$tableName = $this->db->base_prefix . 'usermeta';
|
151 |
+
}
|
152 |
+
|
153 |
// Drop table if necessary
|
154 |
$this->dropTable( $newTableName );
|
155 |
|
172 |
* Copy multisite global user table wp_users to wpstgX_users
|
173 |
* @return bool
|
174 |
*/
|
175 |
+
// private function copyWpUsers() {
|
176 |
+
//// $strings = new Strings();
|
177 |
+
//// $tableName = $this->db->base_prefix . 'users';
|
178 |
+
//// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
179 |
+
//
|
180 |
+
// $tableName = $this->db->base_prefix . 'users';
|
181 |
+
// $newTableName = $this->getStagingPrefix() . 'users';
|
182 |
+
//
|
183 |
+
// $this->log( "DB Copy: Try to create table {$newTableName}" );
|
184 |
+
//
|
185 |
+
//
|
186 |
+
// // Drop table if necessary
|
187 |
+
// $this->dropTable( $newTableName );
|
188 |
+
//
|
189 |
+
// // Save current job
|
190 |
+
// $this->setJob( $newTableName );
|
191 |
+
//
|
192 |
+
// // Beginning of the job
|
193 |
+
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
194 |
+
// return true;
|
195 |
+
// }
|
196 |
+
//
|
197 |
+
// // Copy data
|
198 |
+
// $this->copyData( $newTableName, $tableName );
|
199 |
+
//
|
200 |
+
// // Finish the step
|
201 |
+
// return $this->finishStep();
|
202 |
+
// }
|
203 |
|
204 |
/**
|
205 |
* Copy multisite global user table wp_usermeta to wpstgX_users
|
206 |
* @return bool
|
207 |
*/
|
208 |
+
// private function copyWpUsermeta() {
|
209 |
+
//// $strings = new Strings();
|
210 |
+
//// $tableName = $this->db->base_prefix . 'usermeta';
|
211 |
+
//// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
212 |
+
// $tableName = $this->db->base_prefix . 'usermeta';
|
213 |
+
// $newTableName = $this->getStagingPrefix() . 'usermeta';
|
214 |
+
//
|
215 |
+
// $this->log( "DB Copy: Try to create table {$newTableName}" );
|
216 |
+
//
|
217 |
+
//
|
218 |
+
// // Drop table if necessary
|
219 |
+
// $this->dropTable( $newTableName );
|
220 |
+
//
|
221 |
+
// // Save current job
|
222 |
+
// $this->setJob( $newTableName );
|
223 |
+
//
|
224 |
+
// // Beginning of the job
|
225 |
+
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
226 |
+
// return true;
|
227 |
+
// }
|
228 |
+
// // Copy data
|
229 |
+
// $this->copyData( $newTableName, $tableName );
|
230 |
+
//
|
231 |
+
// // Finish the step
|
232 |
+
// return $this->finishStep();
|
233 |
+
// }
|
234 |
|
235 |
/**
|
236 |
* Copy data from old table to new table
|
277 |
* @return bool
|
278 |
*/
|
279 |
private function startJob( $new, $old ) {
|
280 |
+
|
281 |
+
$this->options->job->total = 0;
|
282 |
+
|
283 |
if( 0 != $this->options->job->start ) {
|
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;
|
291 |
+
}
|
292 |
+
|
293 |
$this->log( "DB Copy: Creating table {$new}" );
|
294 |
|
295 |
$this->db->query( "CREATE TABLE {$new} LIKE {$old}" );
|
314 |
}
|
315 |
|
316 |
// Add it to cloned tables listing
|
317 |
+
$this->options->clonedTables[] = isset( $this->options->tables[$this->options->currentStep] ) ? $this->options->tables[$this->options->currentStep] : false;
|
318 |
|
319 |
// Reset job
|
320 |
$this->options->job = new \stdClass();
|
327 |
* @param string $new
|
328 |
*/
|
329 |
private function dropTable( $new ) {
|
330 |
+
|
331 |
$old = $this->db->get_var( $this->db->prepare( "SHOW TABLES LIKE %s", $new ) );
|
332 |
|
333 |
if( !$this->shouldDropTable( $new, $old ) ) {
|
345 |
* @return bool
|
346 |
*/
|
347 |
private function shouldDropTable( $new, $old ) {
|
348 |
+
|
349 |
+
|
350 |
+
|
351 |
+
if( $old === $new &&
|
352 |
(
|
353 |
!isset( $this->options->job->current ) ||
|
354 |
!isset( $this->options->job->start ) ||
|
355 |
0 == $this->options->job->start
|
356 |
+
) ) {
|
357 |
+
return true;
|
358 |
+
}
|
359 |
+
return false;
|
360 |
}
|
361 |
|
362 |
}
|
@@ -37,10 +37,11 @@ class DatabaseExternal extends JobExecutable {
|
|
37 |
* Initialize
|
38 |
*/
|
39 |
public function initialize() {
|
40 |
-
// Add 2 to total table count because we need to copy two more tables from the main multisite installation wp_users and wp_usermeta
|
41 |
-
$this->total = count( $this->options->tables ) + 2;
|
42 |
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
43 |
$this->stagingDb = $this->getExternalDBConnection();
|
|
|
|
|
|
|
44 |
$this->isFatalError();
|
45 |
}
|
46 |
|
@@ -68,6 +69,19 @@ class DatabaseExternal extends JobExecutable {
|
|
68 |
return $db;
|
69 |
}
|
70 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
71 |
|
72 |
/**
|
73 |
* Return fatal error and stops here if subfolder already exists
|
@@ -87,7 +101,7 @@ class DatabaseExternal extends JobExecutable {
|
|
87 |
* @return void
|
88 |
*/
|
89 |
protected function calculateTotalSteps() {
|
90 |
-
$this->options->totalSteps = $this->total === 0 ? 1 : $this->total;
|
91 |
}
|
92 |
|
93 |
/**
|
@@ -107,7 +121,6 @@ class DatabaseExternal extends JobExecutable {
|
|
107 |
}
|
108 |
|
109 |
// No more steps, finished
|
110 |
-
//if( $this->options->currentStep > $this->total || !isset( $this->options->tables[$this->options->currentStep] ) ) {
|
111 |
if( $this->options->currentStep > $this->total ) {
|
112 |
$this->prepareResponse( true, false );
|
113 |
return false;
|
@@ -122,10 +135,9 @@ class DatabaseExternal extends JobExecutable {
|
|
122 |
return true;
|
123 |
}
|
124 |
|
125 |
-
$this->copyWpUsers();
|
126 |
-
|
127 |
-
$this->copyWpUsermeta();
|
128 |
-
|
129 |
// Prepare Response
|
130 |
$this->prepareResponse();
|
131 |
|
@@ -139,7 +151,7 @@ class DatabaseExternal extends JobExecutable {
|
|
139 |
*/
|
140 |
private function getStagingPrefix() {
|
141 |
|
142 |
-
$this->options->prefix = $this->options->databasePrefix;
|
143 |
|
144 |
return $this->options->prefix;
|
145 |
}
|
@@ -155,6 +167,15 @@ class DatabaseExternal extends JobExecutable {
|
|
155 |
$tableName = is_object( $tableName ) ? $tableName->name : $tableName;
|
156 |
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->prefix, null, $tableName );
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
// Drop table if necessary
|
159 |
$this->dropTable( $newTableName );
|
160 |
|
@@ -177,54 +198,54 @@ class DatabaseExternal extends JobExecutable {
|
|
177 |
* Copy multisite global user table wp_users to wpstgX_users
|
178 |
* @return bool
|
179 |
*/
|
180 |
-
private function copyWpUsers() {
|
181 |
-
$strings = new Strings();
|
182 |
-
$tableName = $this->db->base_prefix . 'users';
|
183 |
-
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
184 |
-
|
185 |
-
// Drop table if necessary
|
186 |
-
$this->dropTable( $newTableName );
|
187 |
-
|
188 |
-
// Save current job
|
189 |
-
$this->setJob( $newTableName );
|
190 |
-
|
191 |
-
// Beginning of the job
|
192 |
-
if( !$this->startJob( $newTableName, $tableName ) ) {
|
193 |
-
return true;
|
194 |
-
}
|
195 |
-
|
196 |
-
// Copy data
|
197 |
-
$this->copyData( $newTableName, $tableName );
|
198 |
-
|
199 |
-
// Finish the step
|
200 |
-
return $this->finishStep();
|
201 |
-
}
|
202 |
|
203 |
/**
|
204 |
* Copy multisite global user table wp_usermeta to wpstgX_users
|
205 |
* @return bool
|
206 |
*/
|
207 |
-
private function copyWpUsermeta() {
|
208 |
-
$strings = new Strings();
|
209 |
-
$tableName = $this->db->base_prefix . 'usermeta';
|
210 |
-
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
211 |
-
|
212 |
-
// Drop table if necessary
|
213 |
-
$this->dropTable( $newTableName );
|
214 |
-
|
215 |
-
// Save current job
|
216 |
-
$this->setJob( $newTableName );
|
217 |
-
|
218 |
-
// Beginning of the job
|
219 |
-
if( !$this->startJob( $newTableName, $tableName ) ) {
|
220 |
-
return true;
|
221 |
-
}
|
222 |
-
// Copy data
|
223 |
-
$this->copyData( $newTableName, $tableName );
|
224 |
-
|
225 |
-
// Finish the step
|
226 |
-
return $this->finishStep();
|
227 |
-
}
|
228 |
|
229 |
/**
|
230 |
* Copy data from old table to new table
|
@@ -232,7 +253,7 @@ class DatabaseExternal extends JobExecutable {
|
|
232 |
* @param string $old
|
233 |
*/
|
234 |
private function copyData( $new, $old ) {
|
235 |
-
$old = $this->db->dbname . '.' . $
|
236 |
$new = $this->options->databaseDatabase . '.' . $new;
|
237 |
|
238 |
|
@@ -276,6 +297,12 @@ class DatabaseExternal extends JobExecutable {
|
|
276 |
*/
|
277 |
private function startJob( $new, $old ) {
|
278 |
|
|
|
|
|
|
|
|
|
|
|
|
|
279 |
$new = $this->options->databaseDatabase . '.' . $new;
|
280 |
$old = $this->db->dbname . '.' . $old;
|
281 |
|
@@ -283,6 +310,13 @@ class DatabaseExternal extends JobExecutable {
|
|
283 |
return true;
|
284 |
}
|
285 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
286 |
$this->log( "DB Copy: Creating table {$new}" );
|
287 |
|
288 |
$this->stagingDb->query( "CREATE TABLE {$new} LIKE {$old}" );
|
@@ -297,6 +331,29 @@ class DatabaseExternal extends JobExecutable {
|
|
297 |
return true;
|
298 |
}
|
299 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
300 |
/**
|
301 |
* Finish the step
|
302 |
*/
|
@@ -337,14 +394,18 @@ class DatabaseExternal extends JobExecutable {
|
|
337 |
* @return bool
|
338 |
*/
|
339 |
private function shouldDropTable( $new, $old ) {
|
340 |
-
|
341 |
-
|
|
|
|
|
342 |
(
|
343 |
!isset( $this->options->job->current ) ||
|
344 |
!isset( $this->options->job->start ) ||
|
345 |
0 == $this->options->job->start
|
346 |
-
)
|
347 |
-
|
|
|
|
|
348 |
}
|
349 |
|
350 |
}
|
37 |
* Initialize
|
38 |
*/
|
39 |
public function initialize() {
|
|
|
|
|
40 |
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
41 |
$this->stagingDb = $this->getExternalDBConnection();
|
42 |
+
$this->getTables();
|
43 |
+
// Add 2 to total table count because we need to copy two more tables from the main multisite installation wp_users and wp_usermeta
|
44 |
+
$this->total = count( $this->options->tables ) + 2;
|
45 |
$this->isFatalError();
|
46 |
}
|
47 |
|
69 |
return $db;
|
70 |
}
|
71 |
|
72 |
+
private function getTables() {
|
73 |
+
// Add wp_users and wp_usermeta to the tables if they do not exist
|
74 |
+
// because they are not available in MU installation but we need them on the staging site
|
75 |
+
|
76 |
+
if( !in_array( $this->db->prefix . 'users', $this->options->tables ) ) {
|
77 |
+
array_push( $this->options->tables, $this->db->prefix . 'users' );
|
78 |
+
$this->saveOptions();
|
79 |
+
}
|
80 |
+
if( !in_array( $this->db->prefix . 'usermeta', $this->options->tables ) ) {
|
81 |
+
array_push( $this->options->tables, $this->db->prefix . 'usermeta' );
|
82 |
+
$this->saveOptions();
|
83 |
+
}
|
84 |
+
}
|
85 |
|
86 |
/**
|
87 |
* Return fatal error and stops here if subfolder already exists
|
101 |
* @return void
|
102 |
*/
|
103 |
protected function calculateTotalSteps() {
|
104 |
+
$this->options->totalSteps = ($this->total === 0) ? 1 : $this->total;
|
105 |
}
|
106 |
|
107 |
/**
|
121 |
}
|
122 |
|
123 |
// No more steps, finished
|
|
|
124 |
if( $this->options->currentStep > $this->total ) {
|
125 |
$this->prepareResponse( true, false );
|
126 |
return false;
|
135 |
return true;
|
136 |
}
|
137 |
|
138 |
+
// $this->copyWpUsers();
|
139 |
+
//
|
140 |
+
// $this->copyWpUsermeta();
|
|
|
141 |
// Prepare Response
|
142 |
$this->prepareResponse();
|
143 |
|
151 |
*/
|
152 |
private function getStagingPrefix() {
|
153 |
|
154 |
+
$this->options->prefix = !empty( $this->options->databasePrefix ) ? $this->options->databasePrefix : $this->db->prefix;
|
155 |
|
156 |
return $this->options->prefix;
|
157 |
}
|
167 |
$tableName = is_object( $tableName ) ? $tableName->name : $tableName;
|
168 |
$newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->prefix, null, $tableName );
|
169 |
|
170 |
+
// Get wp_users from main site
|
171 |
+
if( 'users' === $strings->str_replace_first( $this->db->prefix, null, $tableName ) ) {
|
172 |
+
$tableName = $this->db->base_prefix . 'users';
|
173 |
+
}
|
174 |
+
// Get wp_usermeta from main site
|
175 |
+
if( 'usermeta' === $strings->str_replace_first( $this->db->prefix, null, $tableName ) ) {
|
176 |
+
$tableName = $this->db->base_prefix . 'usermeta';
|
177 |
+
}
|
178 |
+
|
179 |
// Drop table if necessary
|
180 |
$this->dropTable( $newTableName );
|
181 |
|
198 |
* Copy multisite global user table wp_users to wpstgX_users
|
199 |
* @return bool
|
200 |
*/
|
201 |
+
// private function copyWpUsers() {
|
202 |
+
// $strings = new Strings();
|
203 |
+
// $tableName = $this->db->base_prefix . 'users';
|
204 |
+
// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
205 |
+
//
|
206 |
+
// // Drop table if necessary
|
207 |
+
// $this->dropTable( $newTableName );
|
208 |
+
//
|
209 |
+
// // Save current job
|
210 |
+
// $this->setJob( $newTableName );
|
211 |
+
//
|
212 |
+
// // Beginning of the job
|
213 |
+
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
214 |
+
// return true;
|
215 |
+
// }
|
216 |
+
//
|
217 |
+
// // Copy data
|
218 |
+
// $this->copyData( $newTableName, $tableName );
|
219 |
+
//
|
220 |
+
// // Finish the step
|
221 |
+
// return $this->finishStep();
|
222 |
+
// }
|
223 |
|
224 |
/**
|
225 |
* Copy multisite global user table wp_usermeta to wpstgX_users
|
226 |
* @return bool
|
227 |
*/
|
228 |
+
// private function copyWpUsermeta() {
|
229 |
+
// $strings = new Strings();
|
230 |
+
// $tableName = $this->db->base_prefix . 'usermeta';
|
231 |
+
// $newTableName = $this->getStagingPrefix() . $strings->str_replace_first( $this->db->base_prefix, null, $tableName );
|
232 |
+
//
|
233 |
+
// // Drop table if necessary
|
234 |
+
// $this->dropTable( $newTableName );
|
235 |
+
//
|
236 |
+
// // Save current job
|
237 |
+
// $this->setJob( $newTableName );
|
238 |
+
//
|
239 |
+
// // Beginning of the job
|
240 |
+
// if( !$this->startJob( $newTableName, $tableName ) ) {
|
241 |
+
// return true;
|
242 |
+
// }
|
243 |
+
// // Copy data
|
244 |
+
// $this->copyData( $newTableName, $tableName );
|
245 |
+
//
|
246 |
+
// // Finish the step
|
247 |
+
// return $this->finishStep();
|
248 |
+
// }
|
249 |
|
250 |
/**
|
251 |
* Copy data from old table to new table
|
253 |
* @param string $old
|
254 |
*/
|
255 |
private function copyData( $new, $old ) {
|
256 |
+
$old = $this->db->dbname . '.' . $old;
|
257 |
$new = $this->options->databaseDatabase . '.' . $new;
|
258 |
|
259 |
|
297 |
*/
|
298 |
private function startJob( $new, $old ) {
|
299 |
|
300 |
+
if( $this->isExcludedTable( $new ) ) {
|
301 |
+
return false;
|
302 |
+
}
|
303 |
+
|
304 |
+
$this->options->job->total = 0;
|
305 |
+
|
306 |
$new = $this->options->databaseDatabase . '.' . $new;
|
307 |
$old = $this->db->dbname . '.' . $old;
|
308 |
|
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 ) {
|
317 |
+
return true;
|
318 |
+
}
|
319 |
+
|
320 |
$this->log( "DB Copy: Creating table {$new}" );
|
321 |
|
322 |
$this->stagingDb->query( "CREATE TABLE {$new} LIKE {$old}" );
|
331 |
return true;
|
332 |
}
|
333 |
|
334 |
+
/**
|
335 |
+
* Is table excluded from search replace processing?
|
336 |
+
* @param string $table
|
337 |
+
* @return boolean
|
338 |
+
*/
|
339 |
+
private function isExcludedTable( $table ) {
|
340 |
+
|
341 |
+
$customTables = apply_filters( 'wpstg_clone_database_tables_exclude', array() );
|
342 |
+
$defaultTables = array('blogs', 'blog_versions');
|
343 |
+
|
344 |
+
$tables = array_merge( $customTables, $defaultTables );
|
345 |
+
|
346 |
+
$excludedTables = array();
|
347 |
+
foreach ( $tables as $key => $value ) {
|
348 |
+
$excludedTables[] = $this->options->prefix . $value;
|
349 |
+
}
|
350 |
+
|
351 |
+
if( in_array( $table, $excludedTables ) ) {
|
352 |
+
return true;
|
353 |
+
}
|
354 |
+
return false;
|
355 |
+
}
|
356 |
+
|
357 |
/**
|
358 |
* Finish the step
|
359 |
*/
|
394 |
* @return bool
|
395 |
*/
|
396 |
private function shouldDropTable( $new, $old ) {
|
397 |
+
|
398 |
+
|
399 |
+
|
400 |
+
if( $old === $new &&
|
401 |
(
|
402 |
!isset( $this->options->job->current ) ||
|
403 |
!isset( $this->options->job->start ) ||
|
404 |
0 == $this->options->job->start
|
405 |
+
) ) {
|
406 |
+
return true;
|
407 |
+
}
|
408 |
+
return false;
|
409 |
}
|
410 |
|
411 |
}
|
@@ -392,8 +392,8 @@ class Directories extends JobExecutable {
|
|
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
|
@@ -403,6 +403,7 @@ class Directories extends JobExecutable {
|
|
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
|
@@ -410,8 +411,8 @@ class Directories extends JobExecutable {
|
|
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 |
/**
|
@@ -421,6 +422,9 @@ class Directories extends JobExecutable {
|
|
421 |
*/
|
422 |
private function getExtraFiles( $folder ) {
|
423 |
|
|
|
|
|
|
|
424 |
|
425 |
// open file handle and attach data to end of file
|
426 |
$files = $this->open( $this->filename, 'a' );
|
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
|
403 |
// return 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
|
404 |
// }
|
405 |
}
|
406 |
+
|
407 |
/**
|
408 |
* Get relative path to the upload folder like wp-content/uploads or wp-content/blogs.dir/2/files
|
409 |
* @return string
|
411 |
private function getRelUploadPath() {
|
412 |
$uploads = wp_upload_dir();
|
413 |
$basedir = $uploads['basedir'];
|
414 |
+
|
415 |
+
return trailingslashit( str_replace( \WPStaging\WPStaging::getWPpath(), '', $basedir ) );
|
416 |
}
|
417 |
|
418 |
/**
|
422 |
*/
|
423 |
private function getExtraFiles( $folder ) {
|
424 |
|
425 |
+
if( !is_dir( $folder ) ) {
|
426 |
+
return true;
|
427 |
+
}
|
428 |
|
429 |
// open file handle and attach data to end of file
|
430 |
$files = $this->open( $this->filename, 'a' );
|
@@ -7,7 +7,7 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
if( !defined( "WPINC" ) ) {
|
10 |
-
|
11 |
}
|
12 |
|
13 |
/**
|
@@ -16,368 +16,416 @@ if( !defined( "WPINC" ) ) {
|
|
16 |
*/
|
17 |
class Files extends JobExecutable {
|
18 |
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
}
|
135 |
-
|
136 |
-
return true;
|
137 |
-
}
|
138 |
-
|
139 |
-
/**
|
140 |
-
* Checks Whether There is Any Job to Execute or Not
|
141 |
-
* @return bool
|
142 |
-
*/
|
143 |
-
private function isFinished() {
|
144 |
-
return (
|
145 |
-
$this->options->currentStep > $this->options->totalSteps ||
|
146 |
-
$this->options->copiedFiles >= $this->options->totalFiles
|
147 |
-
);
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* @param string $file
|
152 |
-
* @return bool
|
153 |
-
*/
|
154 |
-
private function copyFile( $file ) {
|
155 |
-
$file = trim( \WPStaging\WPStaging::getWPpath() . $file );
|
156 |
-
|
157 |
-
$directory = dirname( $file );
|
158 |
-
|
159 |
-
// Get file size
|
160 |
-
$fileSize = filesize( $file );
|
161 |
-
|
162 |
-
// Directory is excluded
|
163 |
-
if( $this->isDirectoryExcluded( $directory ) ) {
|
164 |
-
$this->debugLog( "Skipping directory by rule: {$file}", Logger::TYPE_INFO );
|
165 |
-
return false;
|
166 |
-
}
|
167 |
-
|
168 |
-
// File is excluded
|
169 |
-
if( $this->isFileExcluded( $file ) ) {
|
170 |
-
$this->log( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
171 |
-
return false;
|
172 |
-
}
|
173 |
-
// Path + File is excluded
|
174 |
-
if( $this->isFileExcludedFullPath( $file ) ) {
|
175 |
-
$this->log( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
176 |
-
return false;
|
177 |
-
}
|
178 |
-
|
179 |
-
// File is over maximum allowed file size (8MB)
|
180 |
-
if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
|
181 |
-
$this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
|
182 |
-
return false;
|
183 |
-
}
|
184 |
-
|
185 |
-
// Invalid file, skipping it as if succeeded
|
186 |
-
if( !is_file( $file ) || !is_readable( $file ) ) {
|
187 |
-
$this->log( "Can't read file or file doesn't exist {$file}" );
|
188 |
-
return true;
|
189 |
-
}
|
190 |
-
|
191 |
-
// Failed to get destination
|
192 |
-
if( false === ($destination = $this->getDestination( $file )) ) {
|
193 |
-
$this->log( "Can't get the destination of {$file}" );
|
194 |
-
return false;
|
195 |
-
}
|
196 |
-
|
197 |
-
// File is over batch size
|
198 |
-
if( $fileSize >= $this->settings->batchSize ) {
|
199 |
-
$this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
|
200 |
-
return $this->copyBig( $file, $destination, $this->settings->batchSize );
|
201 |
-
}
|
202 |
-
|
203 |
-
// Attempt to copy
|
204 |
-
if( !@copy( $file, $destination ) ) {
|
205 |
-
$errors = error_get_last();
|
206 |
-
$this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
|
207 |
-
return false;
|
208 |
-
}
|
209 |
-
|
210 |
-
return true;
|
211 |
-
|
212 |
-
// Good old PHP
|
213 |
-
//return $this->copy($file, $destination);
|
214 |
-
}
|
215 |
-
|
216 |
-
/**
|
217 |
-
* Gets destination file and checks if the directory exists, if it does not attempts to create it.
|
218 |
-
* If creating destination directory fails, it returns false, gives destination full path otherwise
|
219 |
-
* @param string $file
|
220 |
-
* @return bool|string
|
221 |
-
*/
|
222 |
-
private function getDestination( $file ) {
|
223 |
-
$file = $this->getMultisiteUploadFolder( $file );
|
224 |
-
$relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
|
225 |
-
$destinationPath = $this->destination . $relativePath;
|
226 |
-
$destinationDirectory = dirname( $destinationPath );
|
227 |
-
|
228 |
-
if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, 0775, true ) ) {
|
229 |
-
$this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
|
230 |
-
return false;
|
231 |
-
}
|
232 |
-
|
233 |
-
return $destinationPath;
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Replace relative path of file if its located in multisite upload folder
|
238 |
-
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
239 |
-
* @return boolean
|
240 |
-
*/
|
241 |
-
private function getMultisiteUploadFolder( $file ) {
|
242 |
-
// Check first which method is used
|
243 |
-
$uploads = wp_upload_dir();
|
244 |
-
$basedir = $uploads['basedir'];
|
245 |
-
|
246 |
-
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
247 |
-
// Since WP 3.5
|
248 |
-
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
|
249 |
-
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
250 |
-
$uploadsFolder = str_replace( $search, $replace, $file );
|
251 |
-
} else {
|
252 |
-
// old blog structure
|
253 |
-
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
|
254 |
-
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
255 |
-
$uploadsFolder = str_replace( $search, $replace, $file );
|
256 |
-
}
|
257 |
-
|
258 |
-
return $uploadsFolder;
|
259 |
-
}
|
260 |
-
|
261 |
-
/**
|
262 |
-
* Copy bigger files than $this->settings->batchSize
|
263 |
-
* @param string $src
|
264 |
-
* @param string $dst
|
265 |
-
* @param int $buffersize
|
266 |
-
* @return boolean
|
267 |
-
*/
|
268 |
-
private function copyBig( $src, $dst, $buffersize ) {
|
269 |
-
$src = fopen( $src, 'r' );
|
270 |
-
$dest = fopen( $dst, 'w' );
|
271 |
-
|
272 |
-
// Try first method:
|
273 |
-
while ( !feof( $src ) ) {
|
274 |
-
if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
|
275 |
-
$error = true;
|
276 |
-
}
|
277 |
-
}
|
278 |
-
// Try second method if first one failed
|
279 |
-
if( isset( $error ) && ($error === true) ) {
|
280 |
-
while ( !feof( $src ) ) {
|
281 |
-
if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
|
282 |
-
$this->log( "Can not copy big file; {$src} -> {$dest}" );
|
283 |
-
fclose( $src );
|
284 |
-
fclose( $dest );
|
285 |
-
return false;
|
286 |
}
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
326 |
return true;
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
361 |
return true;
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
/**
|
369 |
-
* Check if directory is an extra directory and should be copied
|
370 |
-
* @param string $directory
|
371 |
-
* @return boolean
|
372 |
-
*/
|
373 |
-
private function isExtraDirectory( $directory ) {
|
374 |
-
foreach ( $this->options->extraDirectories as $extraDirectory ) {
|
375 |
-
if( strpos( $directory, $extraDirectory ) === 0 ) {
|
376 |
return true;
|
377 |
-
|
378 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
379 |
|
380 |
-
|
381 |
-
|
382 |
|
383 |
}
|
7 |
use WPStaging\Utils\Logger;
|
8 |
|
9 |
if( !defined( "WPINC" ) ) {
|
10 |
+
die;
|
11 |
}
|
12 |
|
13 |
/**
|
16 |
*/
|
17 |
class Files extends JobExecutable {
|
18 |
|
19 |
+
/**
|
20 |
+
* @var \SplFileObject
|
21 |
+
*/
|
22 |
+
private $file;
|
23 |
+
|
24 |
+
/**
|
25 |
+
* @var int
|
26 |
+
*/
|
27 |
+
private $maxFilesPerRun;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* @var string
|
31 |
+
*/
|
32 |
+
private $destination;
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Initialization
|
36 |
+
*/
|
37 |
+
public function initialize() {
|
38 |
+
|
39 |
+
$this->destination = $this->options->destinationDir;
|
40 |
+
|
41 |
+
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
42 |
+
|
43 |
+
if( is_file( $filePath ) ) {
|
44 |
+
$this->file = new \SplFileObject( $filePath, 'r' );
|
45 |
+
}
|
46 |
+
|
47 |
+
// Informational logs
|
48 |
+
if( 0 == $this->options->currentStep ) {
|
49 |
+
$this->log( "Copying files..." );
|
50 |
+
}
|
51 |
+
|
52 |
+
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
53 |
+
$this->maxFilesPerRun = $this->settings->fileLimit;
|
54 |
+
//$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
|
55 |
+
}
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
59 |
+
* @return void
|
60 |
+
*/
|
61 |
+
protected function calculateTotalSteps() {
|
62 |
+
$this->options->totalSteps = ceil( $this->options->totalFiles / $this->maxFilesPerRun );
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Execute the Current Step
|
67 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
68 |
+
* @return bool
|
69 |
+
*/
|
70 |
+
protected function execute() {
|
71 |
+
// Finished
|
72 |
+
if( $this->isFinished() ) {
|
73 |
+
$this->log( "Copying files finished" );
|
74 |
+
$this->prepareResponse( true, false );
|
75 |
+
return false;
|
76 |
+
}
|
77 |
+
|
78 |
+
// Get files and copy'em
|
79 |
+
if( !$this->getFilesAndCopy() ) {
|
80 |
+
$this->prepareResponse( false, false );
|
81 |
+
return false;
|
82 |
+
}
|
83 |
+
|
84 |
+
// Prepare and return response
|
85 |
+
$this->prepareResponse();
|
86 |
+
|
87 |
+
// Not finished
|
88 |
+
return true;
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get files and copy
|
93 |
+
* @return bool
|
94 |
+
*/
|
95 |
+
private function getFilesAndCopy() {
|
96 |
+
// Over limits threshold
|
97 |
+
if( $this->isOverThreshold() ) {
|
98 |
+
// Prepare response and save current progress
|
99 |
+
$this->prepareResponse( false, false );
|
100 |
+
$this->saveOptions();
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
// Go to last copied line and than to next one
|
105 |
+
//if ($this->options->copiedFiles != 0) {
|
106 |
+
if( isset( $this->options->copiedFiles ) && $this->options->copiedFiles != 0 ) {
|
107 |
+
$this->file->seek( $this->options->copiedFiles - 1 );
|
108 |
+
}
|
109 |
+
|
110 |
+
$this->file->setFlags( \SplFileObject::SKIP_EMPTY | \SplFileObject::READ_AHEAD );
|
111 |
+
|
112 |
+
// Start time
|
113 |
+
//$start = microtime( true );
|
114 |
+
// Loop x files at a time
|
115 |
+
//$this->maxFilesPerRun = 300;
|
116 |
+
for ( $i = 0; $i < $this->maxFilesPerRun; $i++ ) {
|
117 |
+
|
118 |
+
// Reached timeout
|
119 |
+
// if( ( $timeout = apply_filters( 'wpstg_job_timeout', 10 ) ) ) {
|
120 |
+
// if( ( \microtime( true ) - $start ) > $timeout ) {
|
121 |
+
// // Prepare response and save current progress
|
122 |
+
// $this->prepareResponse( false, true );
|
123 |
+
// $this->saveOptions();
|
124 |
+
// return false;
|
125 |
+
// }
|
126 |
+
// }
|
127 |
+
// Increment copied files
|
128 |
+
// Do this anytime to make sure to not stuck in the same step / files
|
129 |
+
$this->options->copiedFiles++;
|
130 |
+
|
131 |
+
// End of file
|
132 |
+
if( $this->file->eof() ) {
|
133 |
+
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
134 |
}
|
135 |
+
|
136 |
+
$file = $this->file->fgets();
|
137 |
+
|
138 |
+
// if( false !== strpos( $file, 'index.php' ) ) {
|
139 |
+
// $test = $file;
|
140 |
+
// }
|
141 |
+
$this->copyFile( $file );
|
142 |
+
}
|
143 |
+
|
144 |
+
|
145 |
+
|
146 |
+
$totalFiles = $this->options->copiedFiles;
|
147 |
+
// Log this only every 50 entries to keep the log small and to not block the rendering browser
|
148 |
+
if( $this->options->copiedFiles % 50 == 0 ) {
|
149 |
+
$this->log( "Total {$totalFiles} files processed" );
|
150 |
+
}
|
151 |
+
|
152 |
+
return true;
|
153 |
+
}
|
154 |
+
|
155 |
+
/**
|
156 |
+
* Checks Whether There is Any Job to Execute or Not
|
157 |
+
* @return bool
|
158 |
+
*/
|
159 |
+
private function isFinished() {
|
160 |
+
return (
|
161 |
+
$this->options->currentStep > $this->options->totalSteps ||
|
162 |
+
$this->options->copiedFiles >= $this->options->totalFiles
|
163 |
+
);
|
164 |
+
}
|
165 |
+
|
166 |
+
/**
|
167 |
+
* @param string $file
|
168 |
+
* @return bool
|
169 |
+
*/
|
170 |
+
private function copyFile( $file ) {
|
171 |
+
|
172 |
+
$file = trim( \WPStaging\WPStaging::getWPpath() . $file );
|
173 |
+
|
174 |
+
$directory = dirname( $file );
|
175 |
+
|
176 |
+
// Directory is excluded
|
177 |
+
if( $this->isDirectoryExcluded( $directory ) ) {
|
178 |
+
$this->debugLog( "Skipping directory by rule: {$file}", Logger::TYPE_INFO );
|
179 |
+
return false;
|
180 |
+
}
|
181 |
+
|
182 |
+
// File is excluded
|
183 |
+
if( $this->isFileExcluded( $file ) ) {
|
184 |
+
$this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
185 |
+
return false;
|
186 |
+
}
|
187 |
+
// Path + File is excluded
|
188 |
+
if( $this->isFileExcludedFullPath( $file ) ) {
|
189 |
+
$this->debugLog( "Skipping file by rule: {$file}", Logger::TYPE_INFO );
|
190 |
+
return false;
|
191 |
+
}
|
192 |
+
|
193 |
+
// Invalid file, skipping it as if succeeded
|
194 |
+
if( !is_file( $file ) ) {
|
195 |
+
$this->log( "File doesn't exist {$file}", Logger::TYPE_WARNING );
|
196 |
+
return true;
|
197 |
+
}
|
198 |
+
// Invalid file, skipping it as if succeeded
|
199 |
+
if( !is_readable( $file ) ) {
|
200 |
+
$this->log( "Can't read file {$file}", Logger::TYPE_WARNING );
|
201 |
return true;
|
202 |
+
}
|
203 |
+
|
204 |
+
|
205 |
+
// Get file size
|
206 |
+
$fileSize = filesize( $file );
|
207 |
+
|
208 |
+
// File is over maximum allowed file size (8MB)
|
209 |
+
if( $fileSize >= $this->settings->maxFileSize * 1000000 ) {
|
210 |
+
$this->log( "Skipping big file: {$file}", Logger::TYPE_INFO );
|
211 |
+
return false;
|
212 |
+
}
|
213 |
+
|
214 |
+
// Failed to get destination
|
215 |
+
if( false === ($destination = $this->getDestination( $file )) ) {
|
216 |
+
$this->log( "Can't get the destination of {$file}", Logger::TYPE_WARNING );
|
217 |
+
return false;
|
218 |
+
}
|
219 |
+
|
220 |
+
// File is over batch size
|
221 |
+
if( $fileSize >= $this->settings->batchSize ) {
|
222 |
+
$this->log( "Trying to copy big file: {$file} -> {$destination}", Logger::TYPE_INFO );
|
223 |
+
return $this->copyBig( $file, $destination, $this->settings->batchSize );
|
224 |
+
}
|
225 |
+
|
226 |
+
// Attempt to copy
|
227 |
+
if( !@copy( $file, $destination ) ) {
|
228 |
+
$errors = error_get_last();
|
229 |
+
$this->log( "Files: Failed to copy file to destination. Error: {$errors['message']} {$file} -> {$destination}", Logger::TYPE_ERROR );
|
230 |
+
return false;
|
231 |
+
}
|
232 |
+
|
233 |
+
// Set file permissions
|
234 |
+
@chmod( $file, wpstg_get_permissions_for_file() );
|
235 |
+
|
236 |
+
$this->setDirPermissions( $file );
|
237 |
+
|
238 |
+
return true;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Set directory permissions
|
243 |
+
* @param type $file
|
244 |
+
* @return boolean
|
245 |
+
*/
|
246 |
+
private function setDirPermissions( $file ) {
|
247 |
+
$dir = dirname( $file );
|
248 |
+
if( is_dir( $dir ) ) {
|
249 |
+
@chmod( $dir, wpstg_get_permissions_for_directory() );
|
250 |
+
}
|
251 |
+
return false;
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Gets destination file and checks if the directory exists, if it does not attempts to create it.
|
256 |
+
* If creating destination directory fails, it returns false, gives destination full path otherwise
|
257 |
+
* @param string $file
|
258 |
+
* @return bool|string
|
259 |
+
*/
|
260 |
+
private function getDestination( $file ) {
|
261 |
+
$file = $this->getMultisiteUploadFolder( $file );
|
262 |
+
$relativePath = str_replace( \WPStaging\WPStaging::getWPpath(), null, $file );
|
263 |
+
$destinationPath = $this->destination . $relativePath;
|
264 |
+
$destinationDirectory = dirname( $destinationPath );
|
265 |
+
|
266 |
+
if( !is_dir( $destinationDirectory ) && !@mkdir( $destinationDirectory, wpstg_get_permissions_for_directory(), true ) ) {
|
267 |
+
$this->log( "Files: Can not create directory {$destinationDirectory}", Logger::TYPE_ERROR );
|
268 |
+
return false;
|
269 |
+
}
|
270 |
+
|
271 |
+
return $this->sanitizeDirectorySeparator( $destinationPath );
|
272 |
+
}
|
273 |
+
|
274 |
+
/**
|
275 |
+
* Replace relative path of file if its located in multisite upload folder
|
276 |
+
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
277 |
+
* @return boolean
|
278 |
+
*/
|
279 |
+
private function getMultisiteUploadFolder( $file ) {
|
280 |
+
// Check first which method is used
|
281 |
+
$uploads = wp_upload_dir();
|
282 |
+
$basedir = $uploads['basedir'];
|
283 |
+
|
284 |
+
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
285 |
+
// Since WP 3.5
|
286 |
+
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
|
287 |
+
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
288 |
+
$uploadsFolder = str_replace( $search, $replace, $file );
|
289 |
+
} else {
|
290 |
+
// old blog structure
|
291 |
+
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
|
292 |
+
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
293 |
+
$uploadsFolder = str_replace( $search, $replace, $file );
|
294 |
+
}
|
295 |
+
|
296 |
+
return $uploadsFolder;
|
297 |
+
}
|
298 |
+
|
299 |
+
/**
|
300 |
+
* Copy bigger files than $this->settings->batchSize
|
301 |
+
* @param string $src
|
302 |
+
* @param string $dst
|
303 |
+
* @param int $buffersize
|
304 |
+
* @return boolean
|
305 |
+
*/
|
306 |
+
private function copyBig( $src, $dst, $buffersize ) {
|
307 |
+
$src = fopen( $src, 'r' );
|
308 |
+
$dest = fopen( $dst, 'w' );
|
309 |
+
|
310 |
+
// Try first method:
|
311 |
+
while ( !feof( $src ) ) {
|
312 |
+
if( false === fwrite( $dest, fread( $src, $buffersize ) ) ) {
|
313 |
+
$error = true;
|
314 |
+
}
|
315 |
+
}
|
316 |
+
// Try second method if first one failed
|
317 |
+
if( isset( $error ) && ($error === true) ) {
|
318 |
+
while ( !feof( $src ) ) {
|
319 |
+
if( false === stream_copy_to_stream( $src, $dest, 1024 ) ) {
|
320 |
+
$this->log( "Can not copy file; {$src} -> {$dest}" );
|
321 |
+
fclose( $src );
|
322 |
+
fclose( $dest );
|
323 |
+
return false;
|
324 |
+
}
|
325 |
+
}
|
326 |
+
}
|
327 |
+
// Close any open handler
|
328 |
+
fclose( $src );
|
329 |
+
fclose( $dest );
|
330 |
+
return true;
|
331 |
+
}
|
332 |
+
|
333 |
+
/**
|
334 |
+
* Check if certain file is excluded from copying process
|
335 |
+
*
|
336 |
+
* @param string $file filename including ending without full path
|
337 |
+
* @return boolean
|
338 |
+
*/
|
339 |
+
private function isFileExcluded( $file ) {
|
340 |
+
// If file name exists
|
341 |
+
if( in_array( basename( $file ), $this->options->excludedFiles ) ) {
|
342 |
return true;
|
343 |
+
}
|
344 |
+
|
345 |
+
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
346 |
+
// because if the updating process fails, the staging site would not be accessable any longer
|
347 |
+
if( isset( $this->options->mainJob ) && $this->options->mainJob == "updating" && stripos( strrev( $file ), strrev( "wp-config.php" ) ) === 0 ) {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
348 |
return true;
|
349 |
+
}
|
350 |
+
|
351 |
+
|
352 |
+
return false;
|
353 |
+
}
|
354 |
+
|
355 |
+
/**
|
356 |
+
* Check if certain file is excluded from copying process
|
357 |
+
*
|
358 |
+
* @param string $file filename including ending + (part) path e.g wp-content/db.php
|
359 |
+
* @return boolean
|
360 |
+
*/
|
361 |
+
private function isFileExcludedFullPath( $file ) {
|
362 |
+
// If path + file exists
|
363 |
+
foreach ( $this->options->excludedFilesFullPath as $excludedFile ) {
|
364 |
+
if( false !== strpos( $file, $excludedFile ) ) {
|
365 |
+
return true;
|
366 |
+
}
|
367 |
+
}
|
368 |
+
|
369 |
+
return false;
|
370 |
+
}
|
371 |
+
|
372 |
+
/**
|
373 |
+
* Replace backward slash with forward slash directory separator
|
374 |
+
* Escape Windows Backward Slash - Compatibility Fix
|
375 |
+
|
376 |
+
* @param string $path Path
|
377 |
+
*
|
378 |
+
* @return string
|
379 |
+
*/
|
380 |
+
private function sanitizeDirectorySeparator( $path ) {
|
381 |
+
//$string = str_replace( '\\', '/', $path );
|
382 |
+
//$string = str_replace( "/", "\\", $path );
|
383 |
+
//return str_replace( '\\\\', '\\', $string );
|
384 |
+
//return preg_replace( '/[\\\\]+/', '\\\\\\\\', $string );
|
385 |
+
return preg_replace( '/[\\\\]+/', '/', $path );
|
386 |
+
}
|
387 |
+
|
388 |
+
/**
|
389 |
+
* Check if directory is excluded from copying
|
390 |
+
* @param string $directory
|
391 |
+
* @return bool
|
392 |
+
*/
|
393 |
+
private function isDirectoryExcluded( $directory ) {
|
394 |
+
// Make sure that wp-staging-pro directory / plugin is never excluded
|
395 |
+
if( false !== strpos( $directory, 'wp-staging' ) || false !== strpos( $directory, 'wp-staging-pro' ) ) {
|
396 |
+
return false;
|
397 |
+
}
|
398 |
+
// $directory = wpstg_replace_windows_directory_separator( $directory );
|
399 |
+
// $directory = trailingslashit( $directory );
|
400 |
+
$directory = trailingslashit( $this->sanitizeDirectorySeparator( $directory ) );
|
401 |
+
|
402 |
+
foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
|
403 |
+
// $excludedDirectory = wpstg_replace_windows_directory_separator( $excludedDirectory );
|
404 |
+
// $excludedDirectory = trailingslashit( $excludedDirectory );
|
405 |
+
$excludedDirectory = trailingslashit( $this->sanitizeDirectorySeparator( $excludedDirectory ) );
|
406 |
+
if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
|
407 |
+
return true;
|
408 |
+
}
|
409 |
+
}
|
410 |
+
|
411 |
+
return false;
|
412 |
+
}
|
413 |
+
|
414 |
+
/**
|
415 |
+
* Check if directory is an extra directory and should be copied
|
416 |
+
* @param string $directory
|
417 |
+
* @return boolean
|
418 |
+
*/
|
419 |
+
private function isExtraDirectory( $directory ) {
|
420 |
+
$directory = $this->sanitizeDirectorySeparator( $directory );
|
421 |
+
|
422 |
+
foreach ( $this->options->extraDirectories as $extraDirectory ) {
|
423 |
+
if( strpos( $directory, $this->sanitizeDirectorySeparator( $extraDirectory ) ) === 0 ) {
|
424 |
+
return true;
|
425 |
+
}
|
426 |
+
}
|
427 |
|
428 |
+
return false;
|
429 |
+
}
|
430 |
|
431 |
}
|
@@ -1,34 +1,31 @@
|
|
1 |
<?php
|
|
|
2 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
3 |
|
4 |
use WPStaging\WPStaging;
|
5 |
use WPStaging\Backend\Modules\Jobs\Job;
|
6 |
use WPStaging\Utils\Multisite;
|
7 |
|
8 |
-
|
9 |
/**
|
10 |
* Class Finish
|
11 |
* @package WPStaging\Backend\Modules\Jobs
|
12 |
*/
|
13 |
-
class Finish extends Job
|
14 |
-
|
15 |
/**
|
16 |
* Clone Key
|
17 |
* @var string
|
18 |
*/
|
19 |
private $clone = '';
|
20 |
-
|
21 |
-
|
22 |
|
23 |
/**
|
24 |
* Start Module
|
25 |
* @return object
|
26 |
*/
|
27 |
-
public function start()
|
28 |
-
{
|
29 |
// sanitize the clone name before saving
|
30 |
-
$this->clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
31 |
-
|
32 |
// Delete Cache Files
|
33 |
$this->deleteCacheFiles();
|
34 |
|
@@ -36,86 +33,131 @@ class Finish extends Job
|
|
36 |
$this->prepareCloneDataRecords();
|
37 |
|
38 |
$multisite = new Multisite;
|
39 |
-
|
|
|
|
|
40 |
$return = array(
|
41 |
-
"directoryName"
|
42 |
-
"path"
|
43 |
-
"url"
|
44 |
-
"number"
|
45 |
-
"version"
|
46 |
-
"status"
|
47 |
-
"prefix"
|
48 |
-
"last_msg"
|
49 |
-
"job"
|
50 |
-
"percentage"
|
51 |
-
|
52 |
);
|
53 |
-
|
54 |
//$this->flush();
|
55 |
-
|
56 |
-
return (object) $return;
|
57 |
}
|
58 |
|
59 |
/**
|
60 |
* Delete Cache Files
|
61 |
*/
|
62 |
-
protected function deleteCacheFiles()
|
63 |
-
|
64 |
-
$this->log("Finish: Deleting clone job's cache files...");
|
65 |
|
66 |
// Clean cache files
|
67 |
-
$this->cache->delete("clone_options");
|
68 |
-
$this->cache->delete("files_to_copy");
|
69 |
|
70 |
-
$this->log("Finish: Clone job's cache files have been deleted!");
|
71 |
}
|
72 |
-
|
73 |
/**
|
74 |
* Prepare clone records
|
75 |
* @return bool
|
76 |
*/
|
77 |
-
protected function prepareCloneDataRecords()
|
78 |
-
{
|
79 |
// Check if clones still exist
|
80 |
-
$this->log("Finish: Verifying existing clones...");
|
81 |
|
82 |
// Clone data already exists
|
83 |
-
if
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
return true;
|
89 |
}
|
90 |
|
91 |
// Save new clone data
|
92 |
-
$this->log("Finish: {$this->options->clone}'s clone job's data is not in database, generating data");
|
93 |
-
|
94 |
// sanitize the clone name before saving
|
95 |
//$clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
96 |
-
|
97 |
$this->options->existingClones[$this->clone] = array(
|
98 |
-
"directoryName"
|
99 |
-
"path"
|
100 |
-
"url"
|
101 |
-
"number"
|
102 |
-
"version"
|
103 |
-
"status"
|
104 |
-
"prefix"
|
105 |
-
"datetime"
|
106 |
-
"databaseUser"
|
107 |
-
"databasePassword"
|
108 |
-
"databaseDatabase"
|
109 |
-
"databaseServer"
|
110 |
-
"databasePrefix"
|
111 |
);
|
112 |
|
113 |
-
if
|
114 |
-
|
115 |
-
$this->log("Finish: Failed to save {$this->options->clone}'s clone job data to database'");
|
116 |
return false;
|
117 |
}
|
118 |
|
119 |
return true;
|
120 |
}
|
121 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<?php
|
2 |
+
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
use WPStaging\WPStaging;
|
6 |
use WPStaging\Backend\Modules\Jobs\Job;
|
7 |
use WPStaging\Utils\Multisite;
|
8 |
|
|
|
9 |
/**
|
10 |
* Class Finish
|
11 |
* @package WPStaging\Backend\Modules\Jobs
|
12 |
*/
|
13 |
+
class Finish extends Job {
|
14 |
+
|
15 |
/**
|
16 |
* Clone Key
|
17 |
* @var string
|
18 |
*/
|
19 |
private $clone = '';
|
|
|
|
|
20 |
|
21 |
/**
|
22 |
* Start Module
|
23 |
* @return object
|
24 |
*/
|
25 |
+
public function start() {
|
|
|
26 |
// sanitize the clone name before saving
|
27 |
+
$this->clone = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
|
28 |
+
|
29 |
// Delete Cache Files
|
30 |
$this->deleteCacheFiles();
|
31 |
|
33 |
$this->prepareCloneDataRecords();
|
34 |
|
35 |
$multisite = new Multisite;
|
36 |
+
|
37 |
+
|
38 |
+
|
39 |
$return = array(
|
40 |
+
"directoryName" => $this->options->cloneDirectoryName,
|
41 |
+
"path" => $this->options->destinationDir,
|
42 |
+
"url" => $this->getDestinationUrl(),
|
43 |
+
"number" => $this->options->cloneNumber,
|
44 |
+
"version" => \WPStaging\WPStaging::VERSION,
|
45 |
+
"status" => 'finished',
|
46 |
+
"prefix" => $this->options->prefix,
|
47 |
+
"last_msg" => $this->logger->getLastLogMsg(),
|
48 |
+
"job" => $this->options->currentJob,
|
49 |
+
"percentage" => 100
|
|
|
50 |
);
|
51 |
+
|
52 |
//$this->flush();
|
53 |
+
|
54 |
+
return ( object ) $return;
|
55 |
}
|
56 |
|
57 |
/**
|
58 |
* Delete Cache Files
|
59 |
*/
|
60 |
+
protected function deleteCacheFiles() {
|
61 |
+
$this->log( "Finish: Deleting clone job's cache files..." );
|
|
|
62 |
|
63 |
// Clean cache files
|
64 |
+
$this->cache->delete( "clone_options" );
|
65 |
+
$this->cache->delete( "files_to_copy" );
|
66 |
|
67 |
+
$this->log( "Finish: Clone job's cache files have been deleted!" );
|
68 |
}
|
69 |
+
|
70 |
/**
|
71 |
* Prepare clone records
|
72 |
* @return bool
|
73 |
*/
|
74 |
+
protected function prepareCloneDataRecords() {
|
|
|
75 |
// Check if clones still exist
|
76 |
+
$this->log( "Finish: Verifying existing clones..." );
|
77 |
|
78 |
// Clone data already exists
|
79 |
+
if( isset( $this->options->existingClones[$this->options->clone] ) ) {
|
80 |
+
$this->options->existingClones[$this->options->clone]['datetime'] = time();
|
81 |
+
$this->options->existingClones[$this->options->clone]['url'] = $this->getDestinationUrl();
|
82 |
+
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
83 |
+
$this->log( "Finish: The job finished!" );
|
84 |
return true;
|
85 |
}
|
86 |
|
87 |
// Save new clone data
|
88 |
+
$this->log( "Finish: {$this->options->clone}'s clone job's data is not in database, generating data" );
|
89 |
+
|
90 |
// sanitize the clone name before saving
|
91 |
//$clone = preg_replace("#\W+#", '-', strtolower($this->options->clone));
|
92 |
+
|
93 |
$this->options->existingClones[$this->clone] = array(
|
94 |
+
"directoryName" => $this->options->cloneDirectoryName,
|
95 |
+
"path" => $this->options->destinationDir,
|
96 |
+
"url" => $this->getDestinationUrl(),
|
97 |
+
"number" => $this->options->cloneNumber,
|
98 |
+
"version" => \WPStaging\WPStaging::VERSION,
|
99 |
+
"status" => false,
|
100 |
+
"prefix" => $this->options->prefix,
|
101 |
+
"datetime" => time(),
|
102 |
+
"databaseUser" => $this->options->databaseUser,
|
103 |
+
"databasePassword" => $this->options->databasePassword,
|
104 |
+
"databaseDatabase" => $this->options->databaseDatabase,
|
105 |
+
"databaseServer" => $this->options->databaseServer,
|
106 |
+
"databasePrefix" => $this->options->databasePrefix,
|
107 |
);
|
108 |
|
109 |
+
if( false === update_option( "wpstg_existing_clones_beta", $this->options->existingClones ) ) {
|
110 |
+
$this->log( "Finish: Failed to save {$this->options->clone}'s clone job data to database'" );
|
|
|
111 |
return false;
|
112 |
}
|
113 |
|
114 |
return true;
|
115 |
}
|
116 |
+
|
117 |
+
|
118 |
+
/**
|
119 |
+
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
120 |
+
* @return type
|
121 |
+
*/
|
122 |
+
private function getDestinationUrl() {
|
123 |
+
|
124 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
125 |
+
return $this->options->cloneHostname;
|
126 |
+
}
|
127 |
+
|
128 |
+
return trailingslashit( $this->multisiteHomeDomain ) . $this->options->cloneDirectoryName;
|
129 |
+
}
|
130 |
+
|
131 |
+
/**
|
132 |
+
* Check if WP is installed in subdir
|
133 |
+
* @return boolean
|
134 |
+
*/
|
135 |
+
// private function isSubDir() {
|
136 |
+
// // Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
137 |
+
// // This is happening much more often than you would expect
|
138 |
+
// $siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
139 |
+
// $home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
140 |
+
//
|
141 |
+
// if( $home !== $siteurl ) {
|
142 |
+
// return true;
|
143 |
+
// }
|
144 |
+
// return false;
|
145 |
+
// }
|
146 |
+
|
147 |
+
/**
|
148 |
+
* Get the install sub directory if WP is installed in sub directory
|
149 |
+
* @return string
|
150 |
+
*/
|
151 |
+
// private function getSubDir() {
|
152 |
+
// $home = get_option( 'home' );
|
153 |
+
// $siteurl = get_option( 'siteurl' );
|
154 |
+
//
|
155 |
+
// if( empty( $home ) || empty( $siteurl ) ) {
|
156 |
+
// return '';
|
157 |
+
// }
|
158 |
+
//
|
159 |
+
// $dir = str_replace( $home, '', $siteurl );
|
160 |
+
// return str_replace( '/', '', $dir );
|
161 |
+
// }
|
162 |
+
|
163 |
+
}
|
@@ -4,7 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
@@ -19,552 +19,603 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
19 |
*/
|
20 |
class SearchReplace extends JobExecutable {
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
);
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
// Bail out early if there isn't a primary key.
|
272 |
-
// We commented this to search & replace through tables which have no primary keys like wp_revslider_slides
|
273 |
-
// @todo test this carefully. If it causes (performance) issues we need to activate it again!
|
274 |
-
// @since 2.4.4
|
275 |
-
// if( null === $primary_key ) {
|
276 |
-
// return false;
|
277 |
-
// }
|
278 |
-
|
279 |
-
$current_row = 0;
|
280 |
-
$start = $this->options->job->start;
|
281 |
-
$end = $this->settings->querySRLimit;
|
282 |
-
|
283 |
-
// Grab the content of the table.
|
284 |
-
$data = $this->db->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
285 |
-
|
286 |
-
// Filter certain rows option_name in wpstg_options
|
287 |
-
$filter = array(
|
288 |
-
'Admin_custome_login_Slidshow',
|
289 |
-
'Admin_custome_login_Social',
|
290 |
-
'Admin_custome_login_logo',
|
291 |
-
'Admin_custome_login_text',
|
292 |
-
'Admin_custome_login_login',
|
293 |
-
'Admin_custome_login_top',
|
294 |
-
'Admin_custome_login_dashboard',
|
295 |
-
'Admin_custome_login_Version',
|
296 |
-
'upload_path',
|
297 |
-
);
|
298 |
-
|
299 |
-
apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
|
300 |
-
|
301 |
-
// Loop through the data.
|
302 |
-
foreach ( $data as $row ) {
|
303 |
-
$current_row++;
|
304 |
-
$update_sql = array();
|
305 |
-
$where_sql = array();
|
306 |
-
$upd = false;
|
307 |
-
|
308 |
-
// Skip rows below
|
309 |
-
if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
|
310 |
-
continue;
|
311 |
-
}
|
312 |
-
|
313 |
-
// Skip rows with transients (They can store huge data and we need to save memory)
|
314 |
-
if( isset( $row['option_name'] ) && strpos( $row['option_name'], '_transient' ) === 0 ) {
|
315 |
-
continue;
|
316 |
-
}
|
317 |
-
|
318 |
-
|
319 |
-
foreach ( $columns as $column ) {
|
320 |
-
|
321 |
-
$dataRow = $row[$column];
|
322 |
-
|
323 |
-
if( $column == $primary_key ) {
|
324 |
-
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
325 |
-
continue;
|
326 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
327 |
|
328 |
-
// Skip GUIDs by default.
|
329 |
-
if( 'on' !== $args['replace_guids'] && 'guid' == $column ) {
|
330 |
-
continue;
|
331 |
-
}
|
332 |
|
333 |
|
334 |
-
// Skip mail addresses
|
335 |
-
if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' . $this->multisiteDomainWithoutScheme ) ) {
|
336 |
-
continue;
|
337 |
-
}
|
338 |
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
$should_skip = false;
|
345 |
-
continue;
|
346 |
-
}
|
347 |
-
|
348 |
-
// Skip this row
|
349 |
-
if( 'wpstg_existing_clones_beta' === $dataRow ||
|
350 |
-
'wpstg_existing_clones' === $dataRow ||
|
351 |
-
'wpstg_settings' === $dataRow ||
|
352 |
-
'wpstg_license_status' === $dataRow ||
|
353 |
-
'siteurl' === $dataRow ||
|
354 |
-
'home' === $dataRow
|
355 |
-
) {
|
356 |
-
$should_skip = true;
|
357 |
-
}
|
358 |
-
}
|
359 |
|
360 |
-
// Check the path delimiter for / or \/ and remove one of those which prevents from resulting in wrong syntax like domain.com/staging\/.
|
361 |
-
// 1. local.wordpress.test -> local.wordpress.test/staging
|
362 |
-
// 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
|
363 |
-
$tmp = $args;
|
364 |
-
if( false === strpos( $dataRow, $tmp['search_for'][0] ) ) {
|
365 |
-
array_shift( $tmp['search_for'] ); // rtrim( $this->homeUrl, '/' ),
|
366 |
-
array_shift( $tmp['replace_with'] ); // rtrim( $this->homeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
|
367 |
-
} else {
|
368 |
-
unset( $tmp['search_for'][1] );
|
369 |
-
unset( $tmp['replace_with'][1] );
|
370 |
-
// recount array
|
371 |
-
$tmp['search_for'] = array_values( $tmp['search_for'] );
|
372 |
-
$tmp['replace_with'] = array_values( $tmp['replace_with'] );
|
373 |
-
}
|
374 |
|
375 |
-
|
376 |
-
|
377 |
-
foreach ( $tmp['search_for'] as $replace ) {
|
378 |
-
//$this->log( "Search for: {$tmp['search_for'][$i]} Replace with {$tmp['replace_with'][$i]}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
379 |
-
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
380 |
-
$i++;
|
381 |
-
}
|
382 |
-
unset( $replace );
|
383 |
-
unset( $i );
|
384 |
-
unset( $tmp );
|
385 |
-
|
386 |
-
// Something was changed
|
387 |
-
if( $row[$column] != $dataRow ) {
|
388 |
-
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
389 |
-
$upd = true;
|
390 |
-
}
|
391 |
-
}
|
392 |
-
|
393 |
-
// Determine what to do with updates.
|
394 |
-
if( $args['dry_run'] === 'on' ) {
|
395 |
-
// Don't do anything if a dry run
|
396 |
-
} elseif( $upd && !empty( $where_sql ) ) {
|
397 |
-
// If there are changes to make, run the query.
|
398 |
-
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
399 |
-
$result = $this->db->query( $sql );
|
400 |
-
|
401 |
-
if( !$result ) {
|
402 |
-
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
403 |
-
}
|
404 |
-
}
|
405 |
-
} // end row loop
|
406 |
-
unset( $row );
|
407 |
-
unset( $update_sql );
|
408 |
-
unset( $where_sql );
|
409 |
-
unset( $sql );
|
410 |
-
|
411 |
-
|
412 |
-
// DB Flush
|
413 |
-
$this->db->flush();
|
414 |
-
return true;
|
415 |
-
}
|
416 |
-
|
417 |
-
/**
|
418 |
-
* Get path to multisite image folder e.g. wp-content/blogs.dir/ID/files or wp-content/uploads/sites/ID
|
419 |
-
* @return string
|
420 |
-
*/
|
421 |
-
private function getImagePathLive() {
|
422 |
-
// Check first which structure is used
|
423 |
-
$uploads = wp_upload_dir();
|
424 |
-
$basedir = $uploads['basedir'];
|
425 |
-
$blogId = get_current_blog_id();
|
426 |
-
|
427 |
-
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
428 |
-
// Since WP 3.5
|
429 |
-
$path = $blogId > 1 ?
|
430 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR :
|
431 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
432 |
-
} else {
|
433 |
-
// old blog structure
|
434 |
-
$path = $blogId > 1 ?
|
435 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR :
|
436 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
437 |
-
}
|
438 |
-
return $path;
|
439 |
-
}
|
440 |
-
|
441 |
-
/**
|
442 |
-
* Get path to staging site image path wp-content/uploads
|
443 |
-
* @return string
|
444 |
-
*/
|
445 |
-
private function getImagePathStaging() {
|
446 |
-
return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
447 |
-
}
|
448 |
-
|
449 |
-
/**
|
450 |
-
* Adapted from interconnect/it's search/replace script.
|
451 |
-
*
|
452 |
-
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
453 |
-
*
|
454 |
-
* Take a serialised array and unserialise it replacing elements as needed and
|
455 |
-
* unserialising any subordinate arrays and performing the replace on those too.
|
456 |
-
*
|
457 |
-
* @access private
|
458 |
-
* @param string $from String we're looking to replace.
|
459 |
-
* @param string $to What we want it to be replaced with
|
460 |
-
* @param array $data Used to pass any subordinate arrays back to in.
|
461 |
-
* @param boolean $serialized Does the array passed via $data need serialising.
|
462 |
-
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
463 |
-
*
|
464 |
-
* @return string|array The original array with all elements replaced as needed.
|
465 |
-
*/
|
466 |
-
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
467 |
-
try {
|
468 |
-
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
469 |
-
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
470 |
-
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
471 |
-
} elseif( is_array( $data ) ) {
|
472 |
-
$tmp = array();
|
473 |
-
foreach ( $data as $key => $value ) {
|
474 |
-
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
475 |
-
}
|
476 |
|
477 |
-
|
478 |
-
|
479 |
-
} elseif( is_object( $data ) ) {
|
480 |
-
$tmp = $data;
|
481 |
-
$props = get_object_vars( $data );
|
482 |
-
foreach ( $props as $key => $value ) {
|
483 |
-
if( $key === '' || ord( $key[0] ) === 0 ) {
|
484 |
-
continue;
|
485 |
-
}
|
486 |
-
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
487 |
-
}
|
488 |
|
489 |
-
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
-
|
494 |
-
|
495 |
-
|
496 |
-
}
|
497 |
-
}
|
498 |
|
499 |
-
|
500 |
-
|
501 |
-
|
502 |
-
} catch ( Exception $error ) {
|
503 |
-
|
504 |
-
}
|
505 |
|
506 |
-
|
507 |
-
|
508 |
|
509 |
-
//
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
// $data = $_tmp;
|
524 |
-
// unset( $_tmp );
|
525 |
-
// }
|
526 |
-
//
|
527 |
-
// // Submitted by Tina Matter
|
528 |
-
// elseif( $this->isValidObject( $data ) ) {
|
529 |
-
// $_tmp = $data; // new $data_class( );
|
530 |
-
// $props = get_object_vars( $data );
|
531 |
-
// foreach ( $props as $key => $value ) {
|
532 |
-
// if( $key === '' || ord( $key[0] ) === 0 ) {
|
533 |
-
// continue;
|
534 |
-
// }
|
535 |
-
// $_tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
536 |
-
// }
|
537 |
-
//
|
538 |
-
// $data = $_tmp;
|
539 |
-
// unset( $_tmp );
|
540 |
-
// } elseif( is_serialized_string( $data ) ) {
|
541 |
-
// if( false !== ($data = $this->unserialize( $data )) ) {
|
542 |
-
// $data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
543 |
-
// $data = serialize( $data );
|
544 |
-
// }
|
545 |
-
// } else {
|
546 |
-
// if( is_string( $data ) ) {
|
547 |
-
// $data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
548 |
-
// }
|
549 |
-
// }
|
550 |
-
//
|
551 |
-
// if( $serialised ) {
|
552 |
-
// return serialize( $data );
|
553 |
-
// }
|
554 |
-
// } catch ( Exception $error ) {
|
555 |
-
//
|
556 |
-
// }
|
557 |
-
//
|
558 |
-
// return $data;
|
559 |
-
// }
|
560 |
|
|
|
|
|
|
|
|
|
|
|
|
|
561 |
|
|
|
|
|
|
|
|
|
562 |
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
568 |
// private function isValidObject( $data ) {
|
569 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
570 |
// return false;
|
@@ -572,7 +623,7 @@ class SearchReplace extends JobExecutable {
|
|
572 |
//
|
573 |
// $invalid_class_props = get_object_vars( $data );
|
574 |
//
|
575 |
-
// if(
|
576 |
// // Assume it must be an valid object
|
577 |
// return true;
|
578 |
// }
|
@@ -587,189 +638,182 @@ class SearchReplace extends JobExecutable {
|
|
587 |
// return true;
|
588 |
// }
|
589 |
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
726 |
-
|
727 |
-
|
728 |
-
|
729 |
-
|
730 |
-
|
731 |
-
|
732 |
-
|
733 |
-
|
734 |
-
|
735 |
-
|
736 |
-
|
737 |
-
|
738 |
-
|
739 |
-
|
740 |
-
|
741 |
-
|
742 |
-
|
743 |
-
|
744 |
-
|
745 |
-
|
746 |
-
|
747 |
-
|
748 |
-
|
749 |
-
|
750 |
-
|
751 |
-
|
752 |
-
|
753 |
-
|
754 |
-
|
755 |
-
|
756 |
-
|
757 |
-
|
758 |
-
|
759 |
-
|
760 |
-
|
761 |
-
|
762 |
-
|
763 |
-
|
764 |
-
|
765 |
-
|
766 |
-
|
767 |
-
if( empty( $home ) || empty( $siteurl ) ) {
|
768 |
-
return '/';
|
769 |
-
}
|
770 |
-
|
771 |
-
$dir = str_replace( $home, '', $siteurl );
|
772 |
-
return '/' . str_replace( '/', '', $dir );
|
773 |
-
}
|
774 |
|
775 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
19 |
*/
|
20 |
class SearchReplace extends JobExecutable {
|
21 |
|
22 |
+
/**
|
23 |
+
* @var int
|
24 |
+
*/
|
25 |
+
private $total = 0;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @var \WPDB
|
29 |
+
*/
|
30 |
+
public $db;
|
31 |
+
|
32 |
+
/**
|
33 |
+
*
|
34 |
+
* @var Obj
|
35 |
+
*/
|
36 |
+
private $strings;
|
37 |
+
|
38 |
+
/**
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
private $destinationHostname;
|
43 |
+
|
44 |
+
/**
|
45 |
+
*
|
46 |
+
* @var string
|
47 |
+
*/
|
48 |
+
private $sourceHostname;
|
49 |
+
|
50 |
+
/**
|
51 |
+
*
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
//private $targetDir;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* The prefix of the new database tables which are used for the live site after updating tables
|
58 |
+
* @var string
|
59 |
+
*/
|
60 |
+
public $tmpPrefix;
|
61 |
+
|
62 |
+
/**
|
63 |
+
* Initialize
|
64 |
+
*/
|
65 |
+
public function initialize() {
|
66 |
+
$this->total = count( $this->options->tables );
|
67 |
+
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
68 |
+
$this->tmpPrefix = $this->options->prefix;
|
69 |
+
$this->strings = new Strings();
|
70 |
+
$this->sourceHostname = $this->getSourceHostname();
|
71 |
+
$this->destinationHostname = $this->getDestinationHostname();
|
72 |
+
}
|
73 |
+
|
74 |
+
public function start() {
|
75 |
+
// Skip job. Nothing to do
|
76 |
+
if( $this->options->totalSteps === 0 ) {
|
77 |
+
$this->prepareResponse( true, false );
|
78 |
+
}
|
79 |
+
|
80 |
+
$this->run();
|
81 |
+
|
82 |
+
// Save option, progress
|
83 |
+
$this->saveOptions();
|
84 |
+
|
85 |
+
return ( object ) $this->response;
|
86 |
+
}
|
87 |
+
|
88 |
+
/**
|
89 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
90 |
+
* @return void
|
91 |
+
*/
|
92 |
+
protected function calculateTotalSteps() {
|
93 |
+
$this->options->totalSteps = $this->total;
|
94 |
+
}
|
95 |
+
|
96 |
+
/**
|
97 |
+
* Execute the Current Step
|
98 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
99 |
+
* @return bool
|
100 |
+
*/
|
101 |
+
protected function execute() {
|
102 |
+
// Over limits threshold
|
103 |
+
if( $this->isOverThreshold() ) {
|
104 |
+
// Prepare response and save current progress
|
105 |
+
$this->prepareResponse( false, false );
|
106 |
+
$this->saveOptions();
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
|
110 |
+
// No more steps, finished
|
111 |
+
if( $this->options->currentStep > $this->total || !isset( $this->options->tables[$this->options->currentStep] ) ) {
|
112 |
+
$this->prepareResponse( true, false );
|
113 |
+
return false;
|
114 |
+
}
|
115 |
+
|
116 |
+
// Table is excluded
|
117 |
+
if( in_array( $this->options->tables[$this->options->currentStep], $this->options->excludedTables ) ) {
|
118 |
+
$this->prepareResponse();
|
119 |
+
return true;
|
120 |
+
}
|
121 |
+
|
122 |
+
// Search & Replace
|
123 |
+
if( !$this->stopExecution() && !$this->updateTable( $this->options->tables[$this->options->currentStep] ) ) {
|
124 |
+
// Prepare Response
|
125 |
+
$this->prepareResponse( false, false );
|
126 |
+
|
127 |
+
// Not finished
|
128 |
+
return true;
|
129 |
+
}
|
130 |
+
|
131 |
+
|
132 |
+
// Prepare Response
|
133 |
+
$this->prepareResponse();
|
134 |
+
|
135 |
+
// Not finished
|
136 |
+
return true;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* Stop Execution immediately
|
141 |
+
* return mixed bool | json
|
142 |
+
*/
|
143 |
+
private function stopExecution() {
|
144 |
+
if( $this->db->prefix == $this->tmpPrefix ) {
|
145 |
+
$this->returnException( 'Fatal Error 9: Prefix ' . $this->db->prefix . ' is used for the live site hence it can not be used for the staging site as well. Please ask support@wp-staging.com how to resolve this.' );
|
146 |
+
}
|
147 |
+
return false;
|
148 |
+
}
|
149 |
+
|
150 |
+
/**
|
151 |
+
* Copy Tables
|
152 |
+
* @param string $tableName
|
153 |
+
* @return bool
|
154 |
+
*/
|
155 |
+
private function updateTable( $tableName ) {
|
156 |
+
$strings = new Strings();
|
157 |
+
$table = $strings->str_replace_first( $this->db->prefix, '', $tableName );
|
158 |
+
$newTableName = $this->tmpPrefix . $table;
|
159 |
+
|
160 |
+
// Save current job
|
161 |
+
$this->setJob( $newTableName );
|
162 |
+
|
163 |
+
// Beginning of the job
|
164 |
+
if( !$this->startJob( $newTableName, $tableName ) ) {
|
165 |
+
return true;
|
166 |
+
}
|
167 |
+
// Copy data
|
168 |
+
$this->startReplace( $newTableName );
|
169 |
+
|
170 |
+
// Finish the step
|
171 |
+
return $this->finishStep();
|
172 |
+
}
|
173 |
+
|
174 |
+
/**
|
175 |
+
* Get source Hostname depending on wheather WP has been installed in sub dir or not
|
176 |
+
* @return type
|
177 |
+
*/
|
178 |
+
public function getSourceHostname() {
|
179 |
+
|
180 |
+
if( $this->isSubDir() ) {
|
181 |
+
return trailingslashit( $this->multisiteHomeUrlWithoutScheme ) . '/' . $this->getSubDir();
|
182 |
+
}
|
183 |
+
return $this->multisiteHomeUrlWithoutScheme;
|
184 |
+
}
|
185 |
+
|
186 |
+
/**
|
187 |
+
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
188 |
+
* @return type
|
189 |
+
*/
|
190 |
+
public function getDestinationHostname() {
|
191 |
+
|
192 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
193 |
+
return $this->strings->getUrlWithoutScheme($this->options->cloneHostname);
|
194 |
+
}
|
195 |
+
|
196 |
+
if( $this->isSubDir() ) {
|
197 |
+
return trailingslashit( $this->strings->getUrlWithoutScheme($this->multisiteDomainWithoutScheme) ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
198 |
+
}
|
199 |
+
return trailingslashit( $this->strings->getUrlWithoutScheme($this->multisiteDomainWithoutScheme) ) . $this->options->cloneDirectoryName;
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Get the install sub directory if WP is installed in sub directory
|
204 |
+
* @return string
|
205 |
+
*/
|
206 |
+
private function getSubDir() {
|
207 |
+
$home = get_option( 'home' );
|
208 |
+
$siteurl = get_option( 'siteurl' );
|
209 |
+
|
210 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
211 |
+
return '';
|
212 |
+
}
|
213 |
+
|
214 |
+
$dir = str_replace( $home, '', $siteurl );
|
215 |
+
return str_replace( '/', '', $dir );
|
216 |
+
}
|
217 |
+
|
218 |
+
/**
|
219 |
+
* Start search replace job
|
220 |
+
* @param string $new
|
221 |
+
* @param string $old
|
222 |
+
*/
|
223 |
+
private function startReplace( $table ) {
|
224 |
+
$rows = $this->options->job->start + $this->settings->querySRLimit;
|
225 |
+
$this->log(
|
226 |
+
"DB Processing: Table {$table} {$this->options->job->start} to {$rows} records"
|
227 |
+
);
|
228 |
+
|
229 |
+
// Search & Replace
|
230 |
+
$this->searchReplace( $table, $rows, array() );
|
231 |
+
|
232 |
+
// Set new offset
|
233 |
+
$this->options->job->start += $this->settings->querySRLimit;
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Returns the number of pages in a table.
|
238 |
+
* @access public
|
239 |
+
* @return int
|
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;
|
247 |
+
}
|
248 |
+
|
249 |
+
$table = esc_sql( $table );
|
250 |
+
$rows = $this->db->get_var( "SELECT COUNT(*) FROM $table" );
|
251 |
+
$pages = ceil( $rows / $this->settings->querySRLimit );
|
252 |
+
return absint( $pages );
|
253 |
+
}
|
254 |
+
|
255 |
+
/**
|
256 |
+
* Gets the columns in a table.
|
257 |
+
* @access public
|
258 |
+
* @param string $table The table to check.
|
259 |
+
* @return array
|
260 |
+
*/
|
261 |
+
private function get_columns( $table ) {
|
262 |
+
$primary_key = null;
|
263 |
+
$columns = array();
|
264 |
+
$fields = $this->db->get_results( 'DESCRIBE ' . $table );
|
265 |
+
if( is_array( $fields ) ) {
|
266 |
+
foreach ( $fields as $column ) {
|
267 |
+
$columns[] = $column->Field;
|
268 |
+
if( $column->Key == 'PRI' ) {
|
269 |
+
$primary_key = $column->Field;
|
270 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
271 |
}
|
272 |
+
}
|
273 |
+
return array($primary_key, $columns);
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Return absolute destination path
|
278 |
+
* @return string
|
279 |
+
*/
|
280 |
+
private function getAbsDestination() {
|
281 |
+
if( empty( $this->options->cloneDir ) ) {
|
282 |
+
return \WPStaging\WPStaging::getWPpath();
|
283 |
+
}
|
284 |
+
return trailingslashit( $this->options->cloneDir );
|
285 |
+
}
|
286 |
+
|
287 |
+
/**
|
288 |
+
* Adapated from interconnect/it's search/replace script, adapted from Better Search Replace
|
289 |
+
*
|
290 |
+
* Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions,
|
291 |
+
* and to be compatible with batch processing.
|
292 |
+
*
|
293 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
294 |
+
*
|
295 |
+
* @access public
|
296 |
+
* @param string $table The table to run the replacement on.
|
297 |
+
* @param int $page The page/block to begin the query on.
|
298 |
+
* @param array $args An associative array containing arguments for this run.
|
299 |
+
* @return array
|
300 |
+
*/
|
301 |
+
private function searchReplace( $table, $page, $args ) {
|
302 |
+
|
303 |
+
if( $this->thirdParty->isSearchReplaceExcluded( $table ) ) {
|
304 |
+
$this->log( "DB Processing: Skip {$table}", \WPStaging\Utils\Logger::TYPE_INFO );
|
305 |
+
return true;
|
306 |
+
}
|
307 |
+
|
308 |
+
// Load up the default settings for this chunk.
|
309 |
+
$table = esc_sql( $table );
|
310 |
+
$current_page = $this->options->job->start + $this->settings->querySRLimit;
|
311 |
+
$pages = $this->get_pages_in_table( $table );
|
312 |
+
|
313 |
+
|
314 |
+
// Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
|
315 |
+
$args['search_for'] = array(
|
316 |
+
'//' . $this->getSourceHostname(),
|
317 |
+
ABSPATH,
|
318 |
+
str_replace( '/', '\/', $this->getSourceHostname() ), // // Used by revslider and several visual editors
|
319 |
+
$this->getImagePathLive()
|
320 |
+
);
|
321 |
+
|
322 |
+
|
323 |
+
$args['replace_with'] = array(
|
324 |
+
'//' . $this->getDestinationHostname(),
|
325 |
+
$this->options->destinationDir,
|
326 |
+
str_replace( '/', '\/', $this->getDestinationHostname() ), // Used by revslider and several visual editors
|
327 |
+
$this->getImagePathStaging()
|
328 |
+
);
|
329 |
+
|
330 |
+
|
331 |
+
##########################
|
332 |
+
// if( $this->isSubDir() ) {
|
333 |
+
// // Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
|
334 |
+
// $args['search_for'] = array(
|
335 |
+
// rtrim( $this->multisiteHomeUrlWithoutScheme, "/" ) . $this->getSubDir(),
|
336 |
+
// ABSPATH,
|
337 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ) . str_replace( '/', '\/', $this->getSubDir() ), // // Used by revslider and several visual editors
|
338 |
+
// $this->getImagePathLive()
|
339 |
+
// );
|
340 |
+
//
|
341 |
+
//
|
342 |
+
// $args['replace_with'] = array(
|
343 |
+
// rtrim( $this->multisiteDomainWithoutScheme, "/" ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName,
|
344 |
+
// rtrim( $this->getAbsDestination(), '/' ) . '/' . $this->options->cloneDirectoryName,
|
345 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, "/" ) ) . str_replace( '/', '\/', $this->getSubDir() ) . '\/' . $this->options->cloneDirectoryName, // Used by revslider and several visual editors
|
346 |
+
// $this->getImagePathStaging()
|
347 |
+
// );
|
348 |
+
// } else {
|
349 |
+
// $args['search_for'] = array(
|
350 |
+
// rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ),
|
351 |
+
// ABSPATH,
|
352 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ),
|
353 |
+
// $this->getImagePathLive()
|
354 |
+
// );
|
355 |
+
// $args['replace_with'] = array(
|
356 |
+
// rtrim( $this->multisiteDomainWithoutScheme, '/' ) . '/' . $this->options->cloneDirectoryName,
|
357 |
+
// rtrim( $this->getAbsDestination(), '/' ) . '/' . $this->options->cloneDirectoryName,
|
358 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, '/' ) ) . '\/' . $this->options->cloneDirectoryName,
|
359 |
+
// $this->getImagePathStaging()
|
360 |
+
// );
|
361 |
+
// }
|
362 |
|
|
|
|
|
|
|
|
|
363 |
|
364 |
|
|
|
|
|
|
|
|
|
365 |
|
366 |
+
$args['replace_guids'] = 'off';
|
367 |
+
$args['dry_run'] = 'off';
|
368 |
+
$args['case_insensitive'] = false;
|
369 |
+
$args['replace_mails'] = 'off';
|
370 |
+
$args['skip_transients'] = 'on';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
372 |
|
373 |
+
// Allow filtering of search & replace parameters
|
374 |
+
$args = apply_filters( 'wpstg_clone_searchreplace_params', $args );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
375 |
|
376 |
+
// Get a list of columns in this table.
|
377 |
+
list( $primary_key, $columns ) = $this->get_columns( $table );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
378 |
|
379 |
+
// Bail out early if there isn't a primary key.
|
380 |
+
// We commented this to search & replace through tables which have no primary keys like wp_revslider_slides
|
381 |
+
// @todo test this carefully. If it causes (performance) issues we need to activate it again!
|
382 |
+
// @since 2.4.4
|
383 |
+
// if( null === $primary_key ) {
|
384 |
+
// return false;
|
385 |
+
// }
|
|
|
|
|
386 |
|
387 |
+
$current_row = 0;
|
388 |
+
$start = $this->options->job->start;
|
389 |
+
$end = $this->settings->querySRLimit;
|
|
|
|
|
|
|
390 |
|
391 |
+
// Grab the content of the table.
|
392 |
+
$data = $this->db->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
393 |
|
394 |
+
// Filter certain rows option_name in wpstg_options
|
395 |
+
$filter = array(
|
396 |
+
'Admin_custome_login_Slidshow',
|
397 |
+
'Admin_custome_login_Social',
|
398 |
+
'Admin_custome_login_logo',
|
399 |
+
'Admin_custome_login_text',
|
400 |
+
'Admin_custome_login_login',
|
401 |
+
'Admin_custome_login_top',
|
402 |
+
'Admin_custome_login_dashboard',
|
403 |
+
'Admin_custome_login_Version',
|
404 |
+
'upload_path',
|
405 |
+
);
|
406 |
+
|
407 |
+
$filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
408 |
|
409 |
+
// Loop through the data.
|
410 |
+
foreach ( $data as $row ) {
|
411 |
+
$current_row++;
|
412 |
+
$update_sql = array();
|
413 |
+
$where_sql = array();
|
414 |
+
$upd = false;
|
415 |
|
416 |
+
// Skip rows below
|
417 |
+
if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
|
418 |
+
continue;
|
419 |
+
}
|
420 |
|
421 |
+
// Skip rows with transients (They can store huge data and we need to save memory)
|
422 |
+
if( isset( $row['option_name'] ) && 'on' === $args['skip_transients'] && false !== strpos( $row['option_name'], '_transient' ) ) {
|
423 |
+
continue;
|
424 |
+
}
|
425 |
+
|
426 |
+
foreach ( $columns as $column ) {
|
427 |
+
|
428 |
+
$dataRow = $row[$column];
|
429 |
+
|
430 |
+
if( $column == $primary_key ) {
|
431 |
+
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
432 |
+
continue;
|
433 |
+
}
|
434 |
+
|
435 |
+
// Skip GUIDs by default.
|
436 |
+
if( 'on' !== $args['replace_guids'] && 'guid' == $column ) {
|
437 |
+
continue;
|
438 |
+
}
|
439 |
+
|
440 |
+
// Skip mail addresses
|
441 |
+
if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' . $this->multisiteDomainWithoutScheme ) ) {
|
442 |
+
continue;
|
443 |
+
}
|
444 |
+
|
445 |
+
// Check options table
|
446 |
+
if( $this->options->prefix . 'options' === $table ) {
|
447 |
+
|
448 |
+
// Skip certain options
|
449 |
+
if( isset( $should_skip ) && true === $should_skip ) {
|
450 |
+
$should_skip = false;
|
451 |
+
continue;
|
452 |
+
}
|
453 |
+
|
454 |
+
// Skip this row
|
455 |
+
if( 'wpstg_existing_clones_beta' === $dataRow ||
|
456 |
+
'wpstg_existing_clones' === $dataRow ||
|
457 |
+
'wpstg_settings' === $dataRow ||
|
458 |
+
'wpstg_license_status' === $dataRow ||
|
459 |
+
'siteurl' === $dataRow ||
|
460 |
+
'home' === $dataRow
|
461 |
+
) {
|
462 |
+
$should_skip = true;
|
463 |
+
}
|
464 |
+
}
|
465 |
+
|
466 |
+
// Check the path delimiter for / or \/ and remove one of those which prevents from resulting in wrong syntax like domain.com/staging\/.
|
467 |
+
// 1. local.wordpress.test -> local.wordpress.test/staging
|
468 |
+
// 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
|
469 |
+
$tmp = $args;
|
470 |
+
if( false === strpos( $dataRow, $tmp['search_for'][0] ) ) {
|
471 |
+
array_shift( $tmp['search_for'] ); // rtrim( $this->homeUrl, '/' ),
|
472 |
+
array_shift( $tmp['replace_with'] ); // rtrim( $this->homeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
|
473 |
+
} else {
|
474 |
+
unset( $tmp['search_for'][1] );
|
475 |
+
unset( $tmp['replace_with'][1] );
|
476 |
+
// recount array
|
477 |
+
$tmp['search_for'] = array_values( $tmp['search_for'] );
|
478 |
+
$tmp['replace_with'] = array_values( $tmp['replace_with'] );
|
479 |
+
}
|
480 |
+
|
481 |
+
// Run a search replace on the data row and respect the serialisation.
|
482 |
+
$i = 0;
|
483 |
+
foreach ( $tmp['search_for'] as $replace ) {
|
484 |
+
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
485 |
+
$i++;
|
486 |
+
}
|
487 |
+
unset( $replace );
|
488 |
+
unset( $i );
|
489 |
+
unset( $tmp );
|
490 |
+
|
491 |
+
// Something was changed
|
492 |
+
if( $row[$column] != $dataRow ) {
|
493 |
+
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
494 |
+
$upd = true;
|
495 |
+
}
|
496 |
+
}
|
497 |
+
|
498 |
+
// Determine what to do with updates.
|
499 |
+
if( $args['dry_run'] === 'on' ) {
|
500 |
+
// Don't do anything if a dry run
|
501 |
+
} elseif( $upd && !empty( $where_sql ) ) {
|
502 |
+
// If there are changes to make, run the query.
|
503 |
+
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
504 |
+
$result = $this->db->query( $sql );
|
505 |
+
|
506 |
+
if( !$result ) {
|
507 |
+
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
508 |
+
}
|
509 |
+
}
|
510 |
+
} // end row loop
|
511 |
+
unset( $row );
|
512 |
+
unset( $update_sql );
|
513 |
+
unset( $where_sql );
|
514 |
+
unset( $sql );
|
515 |
+
|
516 |
+
|
517 |
+
// DB Flush
|
518 |
+
$this->db->flush();
|
519 |
+
return true;
|
520 |
+
}
|
521 |
+
|
522 |
+
/**
|
523 |
+
* Get path to multisite image folder e.g. wp-content/blogs.dir/ID/files or wp-content/uploads/sites/ID
|
524 |
+
* @return string
|
525 |
+
*/
|
526 |
+
private function getImagePathLive() {
|
527 |
+
// Check first which structure is used
|
528 |
+
$uploads = wp_upload_dir();
|
529 |
+
$basedir = $uploads['basedir'];
|
530 |
+
$blogId = get_current_blog_id();
|
531 |
+
|
532 |
+
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
533 |
+
// Since WP 3.5
|
534 |
+
$path = $blogId > 1 ?
|
535 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR :
|
536 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
537 |
+
} else {
|
538 |
+
// old blog structure
|
539 |
+
$path = $blogId > 1 ?
|
540 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR :
|
541 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
542 |
+
}
|
543 |
+
return $path;
|
544 |
+
}
|
545 |
+
|
546 |
+
/**
|
547 |
+
* Get path to staging site image path wp-content/uploads
|
548 |
+
* @return string
|
549 |
+
*/
|
550 |
+
private function getImagePathStaging() {
|
551 |
+
return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
552 |
+
}
|
553 |
+
|
554 |
+
/**
|
555 |
+
* Adapted from interconnect/it's search/replace script.
|
556 |
+
*
|
557 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
558 |
+
*
|
559 |
+
* Take a serialised array and unserialise it replacing elements as needed and
|
560 |
+
* unserialising any subordinate arrays and performing the replace on those too.
|
561 |
+
*
|
562 |
+
* @access private
|
563 |
+
* @param string $from String we're looking to replace.
|
564 |
+
* @param string $to What we want it to be replaced with
|
565 |
+
* @param array $data Used to pass any subordinate arrays back to in.
|
566 |
+
* @param boolean $serialized Does the array passed via $data need serialising.
|
567 |
+
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
568 |
+
*
|
569 |
+
* @return string|array The original array with all elements replaced as needed.
|
570 |
+
*/
|
571 |
+
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
572 |
+
try {
|
573 |
+
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
574 |
+
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
575 |
+
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
576 |
+
} elseif( is_array( $data ) ) {
|
577 |
+
$tmp = array();
|
578 |
+
foreach ( $data as $key => $value ) {
|
579 |
+
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
580 |
+
}
|
581 |
+
|
582 |
+
$data = $tmp;
|
583 |
+
unset( $tmp );
|
584 |
+
} elseif( is_object( $data ) ) {
|
585 |
+
$tmp = $data;
|
586 |
+
$props = get_object_vars( $data );
|
587 |
+
foreach ( $props as $key => $value ) {
|
588 |
+
if( $key === '' || ord( $key[0] ) === 0 ) {
|
589 |
+
continue;
|
590 |
+
}
|
591 |
+
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
592 |
+
}
|
593 |
+
|
594 |
+
$data = $tmp;
|
595 |
+
unset( $tmp );
|
596 |
+
} else {
|
597 |
+
if( is_string( $data ) ) {
|
598 |
+
if( !empty( $from ) && !empty( $to ) ) {
|
599 |
+
$data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
600 |
+
}
|
601 |
+
}
|
602 |
+
}
|
603 |
+
|
604 |
+
if( $serialized ) {
|
605 |
+
return serialize( $data );
|
606 |
+
}
|
607 |
+
} catch ( Exception $error ) {
|
608 |
+
|
609 |
+
}
|
610 |
+
|
611 |
+
return $data;
|
612 |
+
}
|
613 |
+
|
614 |
+
/**
|
615 |
+
* Check if the object is a valid one and not __PHP_Incomplete_Class_Name
|
616 |
+
* Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
|
617 |
+
* @return boolean
|
618 |
+
*/
|
619 |
// private function isValidObject( $data ) {
|
620 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
621 |
// return false;
|
623 |
//
|
624 |
// $invalid_class_props = get_object_vars( $data );
|
625 |
//
|
626 |
+
// if (!isset($invalid_class_props['__PHP_Incomplete_Class_Name'])){
|
627 |
// // Assume it must be an valid object
|
628 |
// return true;
|
629 |
// }
|
638 |
// return true;
|
639 |
// }
|
640 |
|
641 |
+
/**
|
642 |
+
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
643 |
+
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
644 |
+
* @access public
|
645 |
+
* @param string $input The string to escape.
|
646 |
+
* @return string
|
647 |
+
*/
|
648 |
+
private function mysql_escape_mimic( $input ) {
|
649 |
+
if( is_array( $input ) ) {
|
650 |
+
return array_map( __METHOD__, $input );
|
651 |
+
}
|
652 |
+
if( !empty( $input ) && is_string( $input ) ) {
|
653 |
+
return str_replace( array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $input );
|
654 |
+
}
|
655 |
+
|
656 |
+
return $input;
|
657 |
+
}
|
658 |
+
|
659 |
+
/**
|
660 |
+
* Return unserialized object or array
|
661 |
+
*
|
662 |
+
* @param string $serialized_string Serialized string.
|
663 |
+
* @param string $method The name of the caller method.
|
664 |
+
*
|
665 |
+
* @return mixed, false on failure
|
666 |
+
*/
|
667 |
+
private static function unserialize( $serialized_string ) {
|
668 |
+
if( !is_serialized( $serialized_string ) ) {
|
669 |
+
return false;
|
670 |
+
}
|
671 |
+
|
672 |
+
$serialized_string = trim( $serialized_string );
|
673 |
+
$unserialized_string = @unserialize( $serialized_string );
|
674 |
+
|
675 |
+
return $unserialized_string;
|
676 |
+
}
|
677 |
+
|
678 |
+
/**
|
679 |
+
* Wrapper for str_replace
|
680 |
+
*
|
681 |
+
* @param string $from
|
682 |
+
* @param string $to
|
683 |
+
* @param string $data
|
684 |
+
* @param string|bool $case_insensitive
|
685 |
+
*
|
686 |
+
* @return string
|
687 |
+
*/
|
688 |
+
private function str_replace( $from, $to, $data, $case_insensitive = false ) {
|
689 |
+
|
690 |
+
// Add filter
|
691 |
+
$excludes = apply_filters( 'wpstg_clone_searchreplace_excl', array() );
|
692 |
+
|
693 |
+
// Build pattern
|
694 |
+
$regexExclude = '';
|
695 |
+
foreach ( $excludes as $exclude ) {
|
696 |
+
$regexExclude .= $exclude . '(*SKIP)(FAIL)|';
|
697 |
+
}
|
698 |
+
|
699 |
+
if( 'on' === $case_insensitive ) {
|
700 |
+
//$data = str_ireplace( $from, $to, $data );
|
701 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#i', $to, $data );
|
702 |
+
} else {
|
703 |
+
//$data = str_replace( $from, $to, $data );
|
704 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#', $to, $data );
|
705 |
+
}
|
706 |
+
|
707 |
+
return $data;
|
708 |
+
}
|
709 |
+
|
710 |
+
/**
|
711 |
+
* Set the job
|
712 |
+
* @param string $table
|
713 |
+
*/
|
714 |
+
private function setJob( $table ) {
|
715 |
+
if( !empty( $this->options->job->current ) ) {
|
716 |
+
return;
|
717 |
+
}
|
718 |
+
|
719 |
+
$this->options->job->current = $table;
|
720 |
+
$this->options->job->start = 0;
|
721 |
+
}
|
722 |
+
|
723 |
+
/**
|
724 |
+
* Start Job
|
725 |
+
* @param string $new
|
726 |
+
* @param string $old
|
727 |
+
* @return bool
|
728 |
+
*/
|
729 |
+
private function startJob( $new, $old ) {
|
730 |
+
|
731 |
+
$this->options->job->total = 0;
|
732 |
+
|
733 |
+
if( 0 != $this->options->job->start ) {
|
734 |
+
return true;
|
735 |
+
}
|
736 |
+
|
737 |
+
// Table does not exists
|
738 |
+
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
|
739 |
+
if( !$result || 0 === $result ) {
|
740 |
+
return false;
|
741 |
+
}
|
742 |
+
|
743 |
+
$this->options->job->total = ( int ) $this->db->get_var( "SELECT COUNT(1) FROM {$old}" );
|
744 |
+
|
745 |
+
if( 0 == $this->options->job->total ) {
|
746 |
+
$this->finishStep();
|
747 |
+
return false;
|
748 |
+
}
|
749 |
+
|
750 |
+
return true;
|
751 |
+
}
|
752 |
+
|
753 |
+
/**
|
754 |
+
* Finish the step
|
755 |
+
*/
|
756 |
+
private function finishStep() {
|
757 |
+
// This job is not finished yet
|
758 |
+
if( $this->options->job->total > $this->options->job->start ) {
|
759 |
+
return false;
|
760 |
+
}
|
761 |
+
|
762 |
+
// Add it to cloned tables listing
|
763 |
+
$this->options->clonedTables[] = $this->options->tables[$this->options->currentStep];
|
764 |
+
|
765 |
+
// Reset job
|
766 |
+
$this->options->job = new \stdClass();
|
767 |
+
|
768 |
+
return true;
|
769 |
+
}
|
770 |
+
|
771 |
+
/**
|
772 |
+
* Drop table if necessary
|
773 |
+
* @param string $new
|
774 |
+
*/
|
775 |
+
private function dropTable( $new ) {
|
776 |
+
$old = $this->db->get_var( $this->db->prepare( "SHOW TABLES LIKE %s", $new ) );
|
777 |
+
|
778 |
+
if( !$this->shouldDropTable( $new, $old ) ) {
|
779 |
+
return;
|
780 |
+
}
|
781 |
+
|
782 |
+
$this->log( "DB Processing: {$new} already exists, dropping it first" );
|
783 |
+
$this->db->query( "DROP TABLE {$new}" );
|
784 |
+
}
|
785 |
+
|
786 |
+
/**
|
787 |
+
* Check if table needs to be dropped
|
788 |
+
* @param string $new
|
789 |
+
* @param string $old
|
790 |
+
* @return bool
|
791 |
+
*/
|
792 |
+
private function shouldDropTable( $new, $old ) {
|
793 |
+
return (
|
794 |
+
$old == $new &&
|
795 |
+
(
|
796 |
+
!isset( $this->options->job->current ) ||
|
797 |
+
!isset( $this->options->job->start ) ||
|
798 |
+
0 == $this->options->job->start
|
799 |
+
)
|
800 |
+
);
|
801 |
+
}
|
802 |
+
|
803 |
+
/**
|
804 |
+
* Check if WP is installed in subdir
|
805 |
+
* @return boolean
|
806 |
+
*/
|
807 |
+
private function isSubDir() {
|
808 |
+
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
809 |
+
// This is happening much more often than you would expect
|
810 |
+
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
811 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
812 |
+
|
813 |
+
if( $home !== $siteurl ) {
|
814 |
+
return true;
|
815 |
+
}
|
816 |
+
return false;
|
817 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
818 |
|
819 |
}
|
@@ -4,13 +4,11 @@ namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
12 |
-
use WPStaging\Utils\Helper;
|
13 |
-
use WPStaging\Utils\Multisite;
|
14 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
15 |
|
16 |
/**
|
@@ -19,504 +17,609 @@ use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
|
19 |
*/
|
20 |
class SearchReplaceExternal extends JobExecutable {
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
//
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
// }
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
199 |
}
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
333 |
}
|
334 |
|
335 |
-
// Skip
|
336 |
-
if( 'on'
|
337 |
-
|
338 |
}
|
339 |
|
340 |
-
|
341 |
-
|
342 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
343 |
}
|
344 |
|
345 |
-
//
|
346 |
-
if( $
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
'wpstg_existing_clones' === $dataRow ||
|
357 |
-
'wpstg_settings' === $dataRow ||
|
358 |
-
'wpstg_license_status' === $dataRow ||
|
359 |
-
'siteurl' === $dataRow ||
|
360 |
-
'home' === $dataRow
|
361 |
-
) {
|
362 |
-
$should_skip = true;
|
363 |
-
}
|
364 |
}
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
} else {
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
}
|
380 |
-
|
381 |
-
// Run a search replace on the data row and respect the serialisation.
|
382 |
-
$i = 0;
|
383 |
-
foreach ( $tmp['search_for'] as $replace ) {
|
384 |
-
//$this->log( "Search for: {$tmp['search_for'][$i]} Replace with {$tmp['replace_with'][$i]}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
385 |
-
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
386 |
-
$i++;
|
387 |
-
}
|
388 |
-
unset( $replace );
|
389 |
-
unset( $i );
|
390 |
-
unset( $tmp );
|
391 |
-
|
392 |
-
// Something was changed
|
393 |
-
if( $row[$column] != $dataRow ) {
|
394 |
-
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
395 |
-
$upd = true;
|
396 |
-
}
|
397 |
-
}
|
398 |
-
|
399 |
-
// Determine what to do with updates.
|
400 |
-
if( $args['dry_run'] === 'on' ) {
|
401 |
-
// Don't do anything if a dry run
|
402 |
-
} elseif( $upd && !empty( $where_sql ) ) {
|
403 |
-
// If there are changes to make, run the query.
|
404 |
-
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
405 |
-
$result = $this->db->query( $sql );
|
406 |
-
|
407 |
-
if( !$result ) {
|
408 |
-
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
409 |
-
}
|
410 |
-
}
|
411 |
-
} // end row loop
|
412 |
-
unset( $row );
|
413 |
-
unset( $update_sql );
|
414 |
-
unset( $where_sql );
|
415 |
-
unset( $sql );
|
416 |
-
|
417 |
-
|
418 |
-
// DB Flush
|
419 |
-
$this->db->flush();
|
420 |
-
return true;
|
421 |
-
}
|
422 |
-
|
423 |
-
/**
|
424 |
-
* Get path to multisite image folder e.g. wp-content/blogs.dir/ID/files or wp-content/uploads/sites/ID
|
425 |
-
* @return string
|
426 |
-
*/
|
427 |
-
private function getImagePathLive() {
|
428 |
-
// Check first which structure is used
|
429 |
-
$uploads = wp_upload_dir();
|
430 |
-
$basedir = $uploads['basedir'];
|
431 |
-
$blogId = get_current_blog_id();
|
432 |
-
|
433 |
-
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
434 |
-
// Since WP 3.5
|
435 |
-
$path = $blogId > 1 ?
|
436 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR :
|
437 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
438 |
-
} else {
|
439 |
-
// old blog structure
|
440 |
-
$path = $blogId > 1 ?
|
441 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR :
|
442 |
-
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
443 |
-
}
|
444 |
-
return $path;
|
445 |
-
}
|
446 |
-
|
447 |
-
/**
|
448 |
-
* Get path to staging site image path wp-content/uploads
|
449 |
-
* @return string
|
450 |
-
*/
|
451 |
-
private function getImagePathStaging() {
|
452 |
-
return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
453 |
-
}
|
454 |
-
|
455 |
-
/**
|
456 |
-
* Adapted from interconnect/it's search/replace script.
|
457 |
-
*
|
458 |
-
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
459 |
-
*
|
460 |
-
* Take a serialised array and unserialise it replacing elements as needed and
|
461 |
-
* unserialising any subordinate arrays and performing the replace on those too.
|
462 |
-
*
|
463 |
-
* @access private
|
464 |
-
* @param string $from String we're looking to replace.
|
465 |
-
* @param string $to What we want it to be replaced with
|
466 |
-
* @param array $data Used to pass any subordinate arrays back to in.
|
467 |
-
* @param boolean $serialized Does the array passed via $data need serialising.
|
468 |
-
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
469 |
-
*
|
470 |
-
* @return string|array The original array with all elements replaced as needed.
|
471 |
-
*/
|
472 |
-
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
473 |
-
try {
|
474 |
-
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
475 |
-
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
476 |
-
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
477 |
-
} elseif( is_array( $data ) ) {
|
478 |
-
$tmp = array();
|
479 |
-
foreach ( $data as $key => $value ) {
|
480 |
-
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
481 |
-
}
|
482 |
-
|
483 |
-
$data = $tmp;
|
484 |
-
unset( $tmp );
|
485 |
-
} elseif( is_object( $data ) ) {
|
486 |
-
$tmp = $data;
|
487 |
-
$props = get_object_vars( $data );
|
488 |
-
foreach ( $props as $key => $value ) {
|
489 |
-
if( $key === '' || ord( $key[0] ) === 0 ) {
|
490 |
-
continue;
|
491 |
-
}
|
492 |
-
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
493 |
}
|
494 |
|
495 |
-
$
|
496 |
-
|
497 |
-
} else {
|
498 |
-
if( is_string( $data ) ) {
|
499 |
-
if( !empty( $from ) && !empty( $to ) ) {
|
500 |
-
$data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
501 |
-
}
|
502 |
}
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
/**
|
516 |
-
* Check if the object is a valid one and not __PHP_Incomplete_Class_Name
|
517 |
-
* Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
|
518 |
-
* @return boolean
|
519 |
-
*/
|
520 |
// private function isValidObject( $data ) {
|
521 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
522 |
// return false;
|
@@ -539,189 +642,207 @@ class SearchReplaceExternal extends JobExecutable {
|
|
539 |
// return true;
|
540 |
// }
|
541 |
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
|
689 |
-
|
690 |
-
|
691 |
-
|
692 |
-
|
693 |
-
|
694 |
-
|
695 |
-
|
696 |
-
|
697 |
-
|
698 |
-
|
699 |
-
|
700 |
-
|
701 |
-
|
702 |
-
|
703 |
-
|
704 |
-
|
705 |
-
|
706 |
-
|
707 |
-
|
708 |
-
|
709 |
-
|
710 |
-
|
711 |
-
|
712 |
-
|
713 |
-
|
714 |
-
|
715 |
-
|
716 |
-
|
717 |
-
|
718 |
-
|
719 |
-
|
720 |
-
|
721 |
-
|
722 |
-
|
723 |
-
|
724 |
-
|
725 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
726 |
|
727 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
11 |
use WPStaging\Utils\Strings;
|
|
|
|
|
12 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
13 |
|
14 |
/**
|
17 |
*/
|
18 |
class SearchReplaceExternal extends JobExecutable {
|
19 |
|
20 |
+
/**
|
21 |
+
* @var int
|
22 |
+
*/
|
23 |
+
private $total = 0;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Staging Site DB
|
27 |
+
* @var \WPDB
|
28 |
+
*/
|
29 |
+
private $stagingDb;
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Production Site DB
|
33 |
+
* @var \WPDB
|
34 |
+
*/
|
35 |
+
private $productionDb;
|
36 |
+
|
37 |
+
/**
|
38 |
+
*
|
39 |
+
* @var string
|
40 |
+
*/
|
41 |
+
private $sourceHostname;
|
42 |
+
|
43 |
+
/**
|
44 |
+
*
|
45 |
+
* @var string
|
46 |
+
*/
|
47 |
+
private $destinationHostname;
|
48 |
+
|
49 |
+
/**
|
50 |
+
*
|
51 |
+
* @var Obj
|
52 |
+
*/
|
53 |
+
private $strings;
|
54 |
+
|
55 |
+
/**
|
56 |
+
* The prefix of the new database tables which are used for the live site after updating tables
|
57 |
+
* @var string
|
58 |
+
*/
|
59 |
+
public $tmpPrefix;
|
60 |
+
|
61 |
+
/**
|
62 |
+
* Initialize
|
63 |
+
*/
|
64 |
+
public function initialize() {
|
65 |
+
$this->total = count( $this->options->tables );
|
66 |
+
$this->stagingDb = $this->getStagingDB();
|
67 |
+
$this->productionDb = WPStaging::getInstance()->get( "wpdb" );
|
68 |
+
$this->tmpPrefix = $this->options->prefix;
|
69 |
+
$this->strings = new Strings();
|
70 |
+
$this->sourceHostname = $this->getSourceHostname();
|
71 |
+
$this->destinationHostname = $this->getDestinationHostname();
|
72 |
+
}
|
73 |
+
|
74 |
+
/**
|
75 |
+
* Get database object to interact with
|
76 |
+
*/
|
77 |
+
private function getStagingDB() {
|
78 |
+
return new \wpdb( $this->options->databaseUser, $this->options->databasePassword, $this->options->databaseDatabase, $this->options->databaseServer );
|
79 |
+
}
|
80 |
+
|
81 |
+
public function start() {
|
82 |
+
// Skip job. Nothing to do
|
83 |
+
if( $this->options->totalSteps === 0 ) {
|
84 |
+
$this->prepareResponse( true, false );
|
85 |
+
}
|
86 |
+
|
87 |
+
$this->run();
|
88 |
+
|
89 |
+
// Save option, progress
|
90 |
+
$this->saveOptions();
|
91 |
+
|
92 |
+
return ( object ) $this->response;
|
93 |
+
}
|
94 |
+
|
95 |
+
/**
|
96 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
97 |
+
* @return void
|
98 |
+
*/
|
99 |
+
protected function calculateTotalSteps() {
|
100 |
+
$this->options->totalSteps = $this->total;
|
101 |
+
}
|
102 |
+
|
103 |
+
/**
|
104 |
+
* Execute the Current Step
|
105 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
106 |
+
* @return bool
|
107 |
+
*/
|
108 |
+
protected function execute() {
|
109 |
+
// Over limits threshold
|
110 |
+
if( $this->isOverThreshold() ) {
|
111 |
+
// Prepare response and save current progress
|
112 |
+
$this->prepareResponse( false, false );
|
113 |
+
$this->saveOptions();
|
114 |
+
return false;
|
115 |
+
}
|
116 |
+
|
117 |
+
// No more steps, finished
|
118 |
+
if( $this->options->currentStep > $this->total || !isset( $this->options->tables[$this->options->currentStep] ) ) {
|
119 |
+
$this->prepareResponse( true, false );
|
120 |
+
return false;
|
121 |
+
}
|
122 |
+
|
123 |
+
// Table is excluded
|
124 |
+
if( in_array( $this->options->tables[$this->options->currentStep], $this->options->excludedTables ) ) {
|
125 |
+
$this->prepareResponse();
|
126 |
+
return true;
|
127 |
+
}
|
128 |
+
|
129 |
+
// Search & Replace
|
130 |
+
if( !$this->stopExecution() && !$this->updateTable( $this->options->tables[$this->options->currentStep] ) ) {
|
131 |
+
// Prepare Response
|
132 |
+
$this->prepareResponse( false, false );
|
133 |
+
|
134 |
+
// Not finished
|
135 |
+
return true;
|
136 |
+
}
|
137 |
+
|
138 |
+
|
139 |
+
// Prepare Response
|
140 |
+
$this->prepareResponse();
|
141 |
+
|
142 |
+
// Not finished
|
143 |
+
return true;
|
144 |
+
}
|
145 |
+
|
146 |
+
/**
|
147 |
+
* Stop Execution immediately
|
148 |
+
* return mixed bool | json
|
149 |
+
*/
|
150 |
+
private function stopExecution() {
|
151 |
+
// if( $this->stagingDb->prefix == $this->tmpPrefix ) {
|
152 |
+
// $this->returnException( 'Fatal Error 9: Prefix ' . $this->stagingDb->prefix . ' is used for the live site hence it can not be used for the staging site as well. Please ask support@wp-staging.com how to resolve this.' );
|
153 |
// }
|
154 |
+
return false;
|
155 |
+
}
|
156 |
+
|
157 |
+
/**
|
158 |
+
* Copy Tables
|
159 |
+
* @param string $tableName
|
160 |
+
* @return bool
|
161 |
+
*/
|
162 |
+
private function updateTable( $tableName ) {
|
163 |
+
$strings = new Strings();
|
164 |
+
$table = $strings->str_replace_first( $this->productionDb->prefix, '', $tableName );
|
165 |
+
$newTableName = $this->tmpPrefix . $table;
|
166 |
+
|
167 |
+
// Save current job
|
168 |
+
$this->setJob( $newTableName );
|
169 |
+
|
170 |
+
// Beginning of the job
|
171 |
+
if( !$this->startJob( $newTableName, $tableName ) ) {
|
172 |
+
return true;
|
173 |
+
}
|
174 |
+
// Copy data
|
175 |
+
$this->startReplace( $newTableName );
|
176 |
+
|
177 |
+
// Finish the step
|
178 |
+
return $this->finishStep();
|
179 |
+
}
|
180 |
+
|
181 |
+
/**
|
182 |
+
* Get source Hostname depending on wheather WP has been installed in sub dir or not
|
183 |
+
* @return type
|
184 |
+
*/
|
185 |
+
private function getSourceHostname() {
|
186 |
+
|
187 |
+
if( $this->isSubDir() ) {
|
188 |
+
return trailingslashit( $this->multisiteHomeUrlWithoutScheme ) . '/' . $this->getSubDir();
|
189 |
+
}
|
190 |
+
return $this->multisiteHomeUrlWithoutScheme;
|
191 |
+
}
|
192 |
+
|
193 |
+
/**
|
194 |
+
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
195 |
+
* Retun host name without scheme
|
196 |
+
* @return type
|
197 |
+
*/
|
198 |
+
private function getDestinationHostname() {
|
199 |
+
|
200 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
201 |
+
return $this->strings->getUrlWithoutScheme( $this->options->cloneHostname );
|
202 |
+
}
|
203 |
+
|
204 |
+
if( $this->isSubDir() ) {
|
205 |
+
return trailingslashit( $this->strings->getUrlWithoutScheme( $this->multisiteDomainWithoutScheme ) ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
206 |
+
}
|
207 |
+
return trailingslashit( $this->strings->getUrlWithoutScheme( $this->multisiteDomainWithoutScheme ) ) . $this->options->cloneDirectoryName;
|
208 |
+
}
|
209 |
+
|
210 |
+
/**
|
211 |
+
* Get the install sub directory if WP is installed in sub directory
|
212 |
+
* @return string
|
213 |
+
*/
|
214 |
+
private function getSubDir() {
|
215 |
+
$home = get_option( 'home' );
|
216 |
+
$siteurl = get_option( 'siteurl' );
|
217 |
+
|
218 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
219 |
+
return '';
|
220 |
+
}
|
221 |
+
|
222 |
+
$dir = str_replace( $home, '', $siteurl );
|
223 |
+
return str_replace( '/', '', $dir );
|
224 |
+
}
|
225 |
+
|
226 |
+
/**
|
227 |
+
* Start search replace job
|
228 |
+
* @param string $new
|
229 |
+
* @param string $old
|
230 |
+
*/
|
231 |
+
private function startReplace( $table ) {
|
232 |
+
$rows = $this->options->job->start + $this->settings->querySRLimit;
|
233 |
+
$this->log(
|
234 |
+
"DB Processing: Table {$table} {$this->options->job->start} to {$rows} records"
|
235 |
+
);
|
236 |
+
|
237 |
+
// Search & Replace
|
238 |
+
$this->searchReplace( $table, $rows, array() );
|
239 |
+
|
240 |
+
// Set new offset
|
241 |
+
$this->options->job->start += $this->settings->querySRLimit;
|
242 |
+
}
|
243 |
+
|
244 |
+
/**
|
245 |
+
* Returns the number of pages in a table.
|
246 |
+
* @access public
|
247 |
+
* @return int
|
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 ) {
|
255 |
+
return 0;
|
256 |
+
}
|
257 |
+
|
258 |
+
$table = esc_sql( $table );
|
259 |
+
$rows = $this->productionDb->get_var( "SELECT COUNT(*) FROM $table" );
|
260 |
+
$pages = ceil( $rows / $this->settings->querySRLimit );
|
261 |
+
return absint( $pages );
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Gets the columns in a table.
|
266 |
+
* @access public
|
267 |
+
* @param string $table The table to check.
|
268 |
+
* @return array
|
269 |
+
*/
|
270 |
+
private function get_columns( $table ) {
|
271 |
+
$primary_key = null;
|
272 |
+
$columns = array();
|
273 |
+
$fields = $this->stagingDb->get_results( 'DESCRIBE ' . $table );
|
274 |
+
if( is_array( $fields ) ) {
|
275 |
+
foreach ( $fields as $column ) {
|
276 |
+
$columns[] = $column->Field;
|
277 |
+
if( $column->Key == 'PRI' ) {
|
278 |
+
$primary_key = $column->Field;
|
279 |
+
}
|
280 |
}
|
281 |
+
}
|
282 |
+
return array($primary_key, $columns);
|
283 |
+
}
|
284 |
+
|
285 |
+
/**
|
286 |
+
* Return absolute destination path
|
287 |
+
* @return string
|
288 |
+
*/
|
289 |
+
// private function getAbsDestination() {
|
290 |
+
// if( empty( $this->options->cloneDir ) ) {
|
291 |
+
// return \WPStaging\WPStaging::getWPpath();
|
292 |
+
// }
|
293 |
+
// return trailingslashit( $this->options->cloneDir );
|
294 |
+
// }
|
295 |
+
|
296 |
+
/**
|
297 |
+
* Adapated from interconnect/it's search/replace script, adapted from Better Search Replace
|
298 |
+
*
|
299 |
+
* Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions,
|
300 |
+
* and to be compatible with batch processing.
|
301 |
+
*
|
302 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
303 |
+
*
|
304 |
+
* @access public
|
305 |
+
* @param string $table The table to run the replacement on.
|
306 |
+
* @param int $page The page/block to begin the query on.
|
307 |
+
* @param array $args An associative array containing arguments for this run.
|
308 |
+
* @return array
|
309 |
+
*/
|
310 |
+
private function searchReplace( $table, $page, $args ) {
|
311 |
+
|
312 |
+
if( $this->thirdParty->isSearchReplaceExcluded( $table ) ) {
|
313 |
+
$this->log( "DB Processing: Skip {$table}", \WPStaging\Utils\Logger::TYPE_INFO );
|
314 |
+
return true;
|
315 |
+
}
|
316 |
+
|
317 |
+
// Load up the default settings for this chunk.
|
318 |
+
$table = esc_sql( $table );
|
319 |
+
$current_page = $this->options->job->start + $this->settings->querySRLimit;
|
320 |
+
$pages = $this->get_pages_in_table( $table );
|
321 |
+
|
322 |
+
|
323 |
+
// Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
|
324 |
+
$args['search_for'] = array(
|
325 |
+
'//' . $this->sourceHostname,
|
326 |
+
ABSPATH,
|
327 |
+
'\/\/' . str_replace( '/', '\/', $this->sourceHostname ), // // Used by revslider and several visual editors
|
328 |
+
$this->getImagePathLive()
|
329 |
+
);
|
330 |
+
|
331 |
+
|
332 |
+
$args['replace_with'] = array(
|
333 |
+
'//' . $this->destinationHostname,
|
334 |
+
$this->options->destinationDir,
|
335 |
+
'\/\/' . str_replace( '/', '\/', $this->destinationHostname ), // Used by revslider and several visual editors
|
336 |
+
$this->getImagePathStaging()
|
337 |
+
);
|
338 |
+
|
339 |
+
// if( $this->isSubDir() ) {
|
340 |
+
// // Search URL example.com/staging and root path to staging site /var/www/htdocs/staging
|
341 |
+
// $args['search_for'] = array(
|
342 |
+
// '//' . rtrim( $this->multisiteHomeUrlWithoutScheme, "/" ) . $this->getSubDir(),
|
343 |
+
// ABSPATH,
|
344 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ) . str_replace( '/', '\/', $this->getSubDir() ), // // Used by revslider and several visual editors
|
345 |
+
// $this->getImagePathLive()
|
346 |
+
// );
|
347 |
+
//
|
348 |
+
//
|
349 |
+
// $args['replace_with'] = array(
|
350 |
+
// '//' . rtrim( $this->multisiteDomainWithoutScheme, "/" ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName,
|
351 |
+
// rtrim( $this->getAbsDestination(), '/' ) . '/' . $this->options->cloneDirectoryName,
|
352 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, "/" ) ) . str_replace( '/', '\/', $this->getSubDir() ) . '\/' . $this->options->cloneDirectoryName, // Used by revslider and several visual editors
|
353 |
+
// $this->getImagePathStaging()
|
354 |
+
// );
|
355 |
+
// } else {
|
356 |
+
// $args['search_for'] = array(
|
357 |
+
// '//' . rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ),
|
358 |
+
// ABSPATH,
|
359 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteHomeUrlWithoutScheme, '/' ) ),
|
360 |
+
// $this->getImagePathLive()
|
361 |
+
// );
|
362 |
+
// $args['replace_with'] = array(
|
363 |
+
// '//' . rtrim( $this->multisiteDomainWithoutScheme, '/' ) . '/' . $this->options->cloneDirectoryName,
|
364 |
+
// rtrim( $this->getAbsDestination(), '/' ) . '/' . $this->options->cloneDirectoryName,
|
365 |
+
// str_replace( '/', '\/', rtrim( $this->multisiteDomainWithoutScheme, '/' ) ) . '\/' . $this->options->cloneDirectoryName,
|
366 |
+
// $this->getImagePathStaging()
|
367 |
+
// );
|
368 |
+
// }
|
369 |
+
|
370 |
+
$args['replace_guids'] = 'off';
|
371 |
+
$args['dry_run'] = 'off';
|
372 |
+
$args['case_insensitive'] = false;
|
373 |
+
$args['replace_mails'] = 'off';
|
374 |
+
$args['skip_transients'] = 'on';
|
375 |
+
|
376 |
+
|
377 |
+
// Allow filtering of search & replace parameters
|
378 |
+
$args = apply_filters( 'wpstg_clone_searchreplace_params', $args );
|
379 |
+
|
380 |
+
// Get a list of columns in this table.
|
381 |
+
list( $primary_key, $columns ) = $this->get_columns( $table );
|
382 |
+
|
383 |
+
// Bail out early if there isn't a primary key.
|
384 |
+
// We commented this to search & replace through tables which have no primary keys like wp_revslider_slides
|
385 |
+
// @todo test this carefully. If it causes (performance) issues we need to activate it again!
|
386 |
+
// @since 2.4.4
|
387 |
+
// if( null === $primary_key ) {
|
388 |
+
// return false;
|
389 |
+
// }
|
390 |
+
|
391 |
+
$current_row = 0;
|
392 |
+
$start = $this->options->job->start;
|
393 |
+
$end = $this->settings->querySRLimit;
|
394 |
+
|
395 |
+
// Grab the content of the table.
|
396 |
+
$data = $this->stagingDb->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
397 |
+
|
398 |
+
// Filter certain rows (of other plugins)
|
399 |
+
$filter = array(
|
400 |
+
'Admin_custome_login_Slidshow',
|
401 |
+
'Admin_custome_login_Social',
|
402 |
+
'Admin_custome_login_logo',
|
403 |
+
'Admin_custome_login_text',
|
404 |
+
'Admin_custome_login_login',
|
405 |
+
'Admin_custome_login_top',
|
406 |
+
'Admin_custome_login_dashboard',
|
407 |
+
'Admin_custome_login_Version',
|
408 |
+
'upload_path',
|
409 |
+
);
|
410 |
+
|
411 |
+
$filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
|
412 |
+
|
413 |
+
// Loop through the data.
|
414 |
+
foreach ( $data as $row ) {
|
415 |
+
$current_row++;
|
416 |
+
$update_sql = array();
|
417 |
+
$where_sql = array();
|
418 |
+
$upd = false;
|
419 |
+
|
420 |
+
// Skip rows below
|
421 |
+
if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
|
422 |
+
continue;
|
423 |
}
|
424 |
|
425 |
+
// Skip rows with transients (They can store huge data and we need to save memory)
|
426 |
+
if( isset( $row['option_name'] ) && 'on' === $args['skip_transients'] && false !== strpos( $row['option_name'], '_transient' ) ) {
|
427 |
+
continue;
|
428 |
}
|
429 |
|
430 |
+
foreach ( $columns as $column ) {
|
431 |
+
|
432 |
+
$dataRow = $row[$column];
|
433 |
+
|
434 |
+
if( $column == $primary_key ) {
|
435 |
+
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
436 |
+
continue;
|
437 |
+
}
|
438 |
+
|
439 |
+
// Skip GUIDs by default.
|
440 |
+
if( 'on' !== $args['replace_guids'] && 'guid' == $column ) {
|
441 |
+
continue;
|
442 |
+
}
|
443 |
+
|
444 |
+
// Skip mail addresses
|
445 |
+
if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' . $this->multisiteDomainWithoutScheme ) ) {
|
446 |
+
continue;
|
447 |
+
}
|
448 |
+
|
449 |
+
// Check options table
|
450 |
+
if( $this->options->prefix . 'options' === $table ) {
|
451 |
+
|
452 |
+
// Skip certain options
|
453 |
+
if( isset( $should_skip ) && true === $should_skip ) {
|
454 |
+
$should_skip = false;
|
455 |
+
continue;
|
456 |
+
}
|
457 |
+
|
458 |
+
// Skip this row
|
459 |
+
if( 'wpstg_existing_clones_beta' === $dataRow ||
|
460 |
+
'wpstg_existing_clones' === $dataRow ||
|
461 |
+
'wpstg_settings' === $dataRow ||
|
462 |
+
'wpstg_license_status' === $dataRow ||
|
463 |
+
'siteurl' === $dataRow ||
|
464 |
+
'home' === $dataRow
|
465 |
+
) {
|
466 |
+
$should_skip = true;
|
467 |
+
}
|
468 |
+
}
|
469 |
+
|
470 |
+
// Check the path delimiter for / or \/ and remove one of those which prevents from resulting in wrong syntax like domain.com/staging\/.
|
471 |
+
// 1. local.wordpress.test -> local.wordpress.test/staging
|
472 |
+
// 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
|
473 |
+
$tmp = $args;
|
474 |
+
if( false === strpos( $dataRow, $tmp['search_for'][0] ) ) {
|
475 |
+
array_shift( $tmp['search_for'] ); // rtrim( $this->homeUrl, '/' ),
|
476 |
+
array_shift( $tmp['replace_with'] ); // rtrim( $this->homeUrl, '/' ) . '/' . $this->options->cloneDirectoryName,
|
477 |
+
} else {
|
478 |
+
unset( $tmp['search_for'][1] );
|
479 |
+
unset( $tmp['replace_with'][1] );
|
480 |
+
// recount array
|
481 |
+
$tmp['search_for'] = array_values( $tmp['search_for'] );
|
482 |
+
$tmp['replace_with'] = array_values( $tmp['replace_with'] );
|
483 |
+
}
|
484 |
+
|
485 |
+
// Run a search replace on the data row and respect the serialisation.
|
486 |
+
$i = 0;
|
487 |
+
foreach ( $tmp['search_for'] as $replace ) {
|
488 |
+
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
489 |
+
$i++;
|
490 |
+
}
|
491 |
+
unset( $replace );
|
492 |
+
unset( $i );
|
493 |
+
unset( $tmp );
|
494 |
+
|
495 |
+
// Something was changed
|
496 |
+
if( $row[$column] != $dataRow ) {
|
497 |
+
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
498 |
+
$upd = true;
|
499 |
+
}
|
500 |
}
|
501 |
|
502 |
+
// Determine what to do with updates.
|
503 |
+
if( $args['dry_run'] === 'on' ) {
|
504 |
+
// Don't do anything if a dry run
|
505 |
+
} elseif( $upd && !empty( $where_sql ) ) {
|
506 |
+
// If there are changes to make, run the query.
|
507 |
+
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
508 |
+
$result = $this->stagingDb->query( $sql );
|
509 |
+
|
510 |
+
if( !$result ) {
|
511 |
+
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
512 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
513 |
}
|
514 |
+
} // end row loop
|
515 |
+
unset( $row );
|
516 |
+
unset( $update_sql );
|
517 |
+
unset( $where_sql );
|
518 |
+
unset( $sql );
|
519 |
+
|
520 |
+
|
521 |
+
// DB Flush
|
522 |
+
$this->stagingDb->flush();
|
523 |
+
return true;
|
524 |
+
}
|
525 |
+
|
526 |
+
/**
|
527 |
+
* Get path to multisite image folder e.g. wp-content/blogs.dir/ID/files or wp-content/uploads/sites/ID
|
528 |
+
* @return string
|
529 |
+
*/
|
530 |
+
private function getImagePathLive() {
|
531 |
+
// Check first which structure is used
|
532 |
+
$uploads = wp_upload_dir();
|
533 |
+
$basedir = $uploads['basedir'];
|
534 |
+
$blogId = get_current_blog_id();
|
535 |
+
|
536 |
+
if( false === strpos( $basedir, 'blogs.dir' ) ) {
|
537 |
+
// Since WP 3.5
|
538 |
+
$path = $blogId > 1 ?
|
539 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR :
|
540 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
541 |
+
} else {
|
542 |
+
// old blog structure
|
543 |
+
$path = $blogId > 1 ?
|
544 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files' . DIRECTORY_SEPARATOR :
|
545 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
546 |
+
}
|
547 |
+
return $path;
|
548 |
+
}
|
549 |
+
|
550 |
+
/**
|
551 |
+
* Get path to staging site image path wp-content/uploads
|
552 |
+
* @return string
|
553 |
+
*/
|
554 |
+
private function getImagePathStaging() {
|
555 |
+
return 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR;
|
556 |
+
}
|
557 |
+
|
558 |
+
/**
|
559 |
+
* Adapted from interconnect/it's search/replace script.
|
560 |
+
*
|
561 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
562 |
+
*
|
563 |
+
* Take a serialised array and unserialise it replacing elements as needed and
|
564 |
+
* unserialising any subordinate arrays and performing the replace on those too.
|
565 |
+
*
|
566 |
+
* @access private
|
567 |
+
* @param string $from String we're looking to replace.
|
568 |
+
* @param string $to What we want it to be replaced with
|
569 |
+
* @param array $data Used to pass any subordinate arrays back to in.
|
570 |
+
* @param boolean $serialized Does the array passed via $data need serialising.
|
571 |
+
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
572 |
+
*
|
573 |
+
* @return string|array The original array with all elements replaced as needed.
|
574 |
+
*/
|
575 |
+
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
576 |
+
try {
|
577 |
+
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
578 |
+
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
579 |
+
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
580 |
+
} elseif( is_array( $data ) ) {
|
581 |
+
$tmp = array();
|
582 |
+
foreach ( $data as $key => $value ) {
|
583 |
+
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
584 |
+
}
|
585 |
+
|
586 |
+
$data = $tmp;
|
587 |
+
unset( $tmp );
|
588 |
+
} elseif( is_object( $data ) ) {
|
589 |
+
$tmp = $data;
|
590 |
+
$props = get_object_vars( $data );
|
591 |
+
foreach ( $props as $key => $value ) {
|
592 |
+
if( $key === '' || ord( $key[0] ) === 0 ) {
|
593 |
+
continue;
|
594 |
+
}
|
595 |
+
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
596 |
+
}
|
597 |
+
|
598 |
+
$data = $tmp;
|
599 |
+
unset( $tmp );
|
600 |
} else {
|
601 |
+
if( is_string( $data ) ) {
|
602 |
+
if( !empty( $from ) && !empty( $to ) ) {
|
603 |
+
$data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
604 |
+
}
|
605 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
606 |
}
|
607 |
|
608 |
+
if( $serialized ) {
|
609 |
+
return serialize( $data );
|
|
|
|
|
|
|
|
|
|
|
610 |
}
|
611 |
+
} catch ( Exception $error ) {
|
612 |
+
|
613 |
+
}
|
614 |
+
|
615 |
+
return $data;
|
616 |
+
}
|
617 |
+
|
618 |
+
/**
|
619 |
+
* Check if the object is a valid one and not __PHP_Incomplete_Class_Name
|
620 |
+
* Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
|
621 |
+
* @return boolean
|
622 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
623 |
// private function isValidObject( $data ) {
|
624 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
625 |
// return false;
|
642 |
// return true;
|
643 |
// }
|
644 |
|
645 |
+
/**
|
646 |
+
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
647 |
+
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
648 |
+
* @access public
|
649 |
+
* @param string $input The string to escape.
|
650 |
+
* @return string
|
651 |
+
*/
|
652 |
+
private function mysql_escape_mimic( $input ) {
|
653 |
+
if( is_array( $input ) ) {
|
654 |
+
return array_map( __METHOD__, $input );
|
655 |
+
}
|
656 |
+
if( !empty( $input ) && is_string( $input ) ) {
|
657 |
+
return str_replace( array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $input );
|
658 |
+
}
|
659 |
+
|
660 |
+
return $input;
|
661 |
+
}
|
662 |
+
|
663 |
+
/**
|
664 |
+
* Return unserialized object or array
|
665 |
+
*
|
666 |
+
* @param string $serialized_string Serialized string.
|
667 |
+
* @param string $method The name of the caller method.
|
668 |
+
*
|
669 |
+
* @return mixed, false on failure
|
670 |
+
*/
|
671 |
+
private static function unserialize( $serialized_string ) {
|
672 |
+
if( !is_serialized( $serialized_string ) ) {
|
673 |
+
return false;
|
674 |
+
}
|
675 |
+
|
676 |
+
$serialized_string = trim( $serialized_string );
|
677 |
+
$unserialized_string = @unserialize( $serialized_string );
|
678 |
+
|
679 |
+
return $unserialized_string;
|
680 |
+
}
|
681 |
+
|
682 |
+
/**
|
683 |
+
* Wrapper for str_replace
|
684 |
+
*
|
685 |
+
* @param string $from
|
686 |
+
* @param string $to
|
687 |
+
* @param string $data
|
688 |
+
* @param string|bool $case_insensitive
|
689 |
+
*
|
690 |
+
* @return string
|
691 |
+
*/
|
692 |
+
private function str_replace( $from, $to, $data, $case_insensitive = false ) {
|
693 |
+
|
694 |
+
// Add filter
|
695 |
+
$excludes = apply_filters( 'wpstg_clone_searchreplace_excl', array() );
|
696 |
+
|
697 |
+
// Build pattern
|
698 |
+
$regexExclude = '';
|
699 |
+
foreach ( $excludes as $exclude ) {
|
700 |
+
$regexExclude .= $exclude . '(*SKIP)(FAIL)|';
|
701 |
+
}
|
702 |
+
|
703 |
+
if( 'on' === $case_insensitive ) {
|
704 |
+
//$data = str_ireplace( $from, $to, $data );
|
705 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#i', $to, $data );
|
706 |
+
} else {
|
707 |
+
//$data = str_replace( $from, $to, $data );
|
708 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#', $to, $data );
|
709 |
+
}
|
710 |
+
|
711 |
+
return $data;
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Set the job
|
716 |
+
* @param string $table
|
717 |
+
*/
|
718 |
+
private function setJob( $table ) {
|
719 |
+
if( !empty( $this->options->job->current ) ) {
|
720 |
+
return;
|
721 |
+
}
|
722 |
+
|
723 |
+
$this->options->job->current = $table;
|
724 |
+
$this->options->job->start = 0;
|
725 |
+
}
|
726 |
+
|
727 |
+
/**
|
728 |
+
* Start Job
|
729 |
+
* @param string $new
|
730 |
+
* @param string $old
|
731 |
+
* @return bool
|
732 |
+
*/
|
733 |
+
private function startJob( $new, $old ) {
|
734 |
+
|
735 |
+
if( $this->isExcludedTable( $new ) ) {
|
736 |
+
return false;
|
737 |
+
}
|
738 |
+
|
739 |
+
// Table does not exists
|
740 |
+
$result = $this->productionDb->query( "SHOW TABLES LIKE '{$old}'" );
|
741 |
+
if( !$result || 0 === $result ) {
|
742 |
+
return false;
|
743 |
+
}
|
744 |
+
|
745 |
+
if( 0 != $this->options->job->start ) {
|
746 |
+
return true;
|
747 |
+
}
|
748 |
+
|
749 |
+
$this->options->job->total = ( int ) $this->productionDb->get_var( "SELECT COUNT(1) FROM {$old}" );
|
750 |
+
|
751 |
+
if( 0 == $this->options->job->total ) {
|
752 |
+
$this->finishStep();
|
753 |
+
return false;
|
754 |
+
}
|
755 |
+
|
756 |
+
return true;
|
757 |
+
}
|
758 |
+
|
759 |
+
/**
|
760 |
+
* Is table excluded from search replace processing?
|
761 |
+
* @param string $table
|
762 |
+
* @return boolean
|
763 |
+
*/
|
764 |
+
private function isExcludedTable( $table ) {
|
765 |
+
|
766 |
+
$customTables = apply_filters( 'wpstg_clone_searchreplace_tables_exclude', array() );
|
767 |
+
$defaultTables = array('blogs');
|
768 |
+
|
769 |
+
$tables = array_merge( $customTables, $defaultTables );
|
770 |
+
|
771 |
+
$excludedTables = array();
|
772 |
+
foreach ( $tables as $key => $value ) {
|
773 |
+
$excludedTables[] = $this->options->prefix . $value;
|
774 |
+
}
|
775 |
+
|
776 |
+
if( in_array( $table, $excludedTables ) ) {
|
777 |
+
return true;
|
778 |
+
}
|
779 |
+
return false;
|
780 |
+
}
|
781 |
+
|
782 |
+
/**
|
783 |
+
* Finish the step
|
784 |
+
*/
|
785 |
+
private function finishStep() {
|
786 |
+
// This job is not finished yet
|
787 |
+
if( $this->options->job->total > $this->options->job->start ) {
|
788 |
+
return false;
|
789 |
+
}
|
790 |
+
|
791 |
+
// Add it to cloned tables listing
|
792 |
+
$this->options->clonedTables[] = $this->options->tables[$this->options->currentStep];
|
793 |
+
|
794 |
+
// Reset job
|
795 |
+
$this->options->job = new \stdClass();
|
796 |
+
|
797 |
+
return true;
|
798 |
+
}
|
799 |
+
|
800 |
+
/**
|
801 |
+
* Drop table if necessary
|
802 |
+
* @param string $new
|
803 |
+
*/
|
804 |
+
private function dropTable( $new ) {
|
805 |
+
$old = $this->stagingDb->get_var( $this->stagingDb->prepare( "SHOW TABLES LIKE %s", $new ) );
|
806 |
+
|
807 |
+
if( !$this->shouldDropTable( $new, $old ) ) {
|
808 |
+
return;
|
809 |
+
}
|
810 |
+
|
811 |
+
$this->log( "DB Processing: {$new} already exists, dropping it first" );
|
812 |
+
$this->stagingDb->query( "DROP TABLE {$new}" );
|
813 |
+
}
|
814 |
+
|
815 |
+
/**
|
816 |
+
* Check if table needs to be dropped
|
817 |
+
* @param string $new
|
818 |
+
* @param string $old
|
819 |
+
* @return bool
|
820 |
+
*/
|
821 |
+
private function shouldDropTable( $new, $old ) {
|
822 |
+
return (
|
823 |
+
$old == $new &&
|
824 |
+
(
|
825 |
+
!isset( $this->options->job->current ) ||
|
826 |
+
!isset( $this->options->job->start ) ||
|
827 |
+
0 == $this->options->job->start
|
828 |
+
)
|
829 |
+
);
|
830 |
+
}
|
831 |
+
|
832 |
+
/**
|
833 |
+
* Check if WP is installed in subdir
|
834 |
+
* @return boolean
|
835 |
+
*/
|
836 |
+
private function isSubDir() {
|
837 |
+
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
838 |
+
// This is happening much more often than you would expect
|
839 |
+
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
840 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
841 |
+
|
842 |
+
if( $home !== $siteurl ) {
|
843 |
+
return true;
|
844 |
+
}
|
845 |
+
return false;
|
846 |
+
}
|
847 |
|
848 |
}
|
@@ -4,7 +4,7 @@ namespace WPStaging\Backend\Modules\Jobs;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
@@ -17,467 +17,523 @@ use WPStaging\Utils\Helper;
|
|
17 |
*/
|
18 |
class SearchReplace extends JobExecutable {
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
$
|
196 |
-
|
197 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
198 |
}
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
$
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
'upload_path',
|
297 |
-
);
|
298 |
-
|
299 |
-
$filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
|
300 |
-
|
301 |
-
// Loop through the data.
|
302 |
-
foreach ( $data as $row ) {
|
303 |
-
$current_row++;
|
304 |
-
$update_sql = array();
|
305 |
-
$where_sql = array();
|
306 |
-
$upd = false;
|
307 |
-
|
308 |
-
// Skip rows below
|
309 |
-
if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
|
310 |
-
continue;
|
311 |
-
}
|
312 |
-
|
313 |
-
// Skip rows with transients (They can store huge data and we need to save memory)
|
314 |
-
if( isset( $row['option_name'] ) && 'on' === $args['skip_transients'] && false !== strpos( $row['option_name'], '_transient' ) ) {
|
315 |
-
continue;
|
316 |
-
}
|
317 |
-
|
318 |
-
foreach ( $columns as $column ) {
|
319 |
-
|
320 |
-
$dataRow = $row[$column];
|
321 |
-
|
322 |
-
if( $column == $primary_key ) {
|
323 |
-
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
324 |
-
continue;
|
325 |
}
|
326 |
|
327 |
-
// Skip
|
328 |
-
if( 'on'
|
329 |
-
|
330 |
}
|
331 |
|
332 |
-
|
333 |
-
|
334 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
335 |
}
|
336 |
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
if( 'wpstg_existing_clones_beta' === $dataRow ||
|
349 |
-
'wpstg_existing_clones' === $dataRow ||
|
350 |
-
'wpstg_settings' === $dataRow ||
|
351 |
-
'wpstg_license_status' === $dataRow ||
|
352 |
-
'siteurl' === $dataRow ||
|
353 |
-
'home' === $dataRow
|
354 |
-
) {
|
355 |
-
$should_skip = true;
|
356 |
-
}
|
357 |
}
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
} else {
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
}
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
// Run a search replace on the data row and respect the serialisation.
|
376 |
-
$i = 0;
|
377 |
-
foreach ( $tmp['search_for'] as $replace ) {
|
378 |
-
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
379 |
-
$i++;
|
380 |
-
}
|
381 |
-
unset( $replace );
|
382 |
-
unset( $i );
|
383 |
-
unset( $tmp );
|
384 |
-
|
385 |
-
// Something was changed
|
386 |
-
if( $row[$column] != $dataRow ) {
|
387 |
-
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
388 |
-
$upd = true;
|
389 |
-
}
|
390 |
-
}
|
391 |
-
|
392 |
-
// Determine what to do with updates.
|
393 |
-
if( $args['dry_run'] === 'on' ) {
|
394 |
-
// Don't do anything if a dry run
|
395 |
-
} elseif( $upd && !empty( $where_sql ) ) {
|
396 |
-
// If there are changes to make, run the query.
|
397 |
-
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
398 |
-
$result = $this->db->query( $sql );
|
399 |
-
|
400 |
-
if( !$result ) {
|
401 |
-
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
402 |
-
}
|
403 |
-
}
|
404 |
-
} // end row loop
|
405 |
-
unset( $row );
|
406 |
-
unset( $update_sql );
|
407 |
-
unset( $where_sql );
|
408 |
-
unset( $sql );
|
409 |
-
|
410 |
-
|
411 |
-
// DB Flush
|
412 |
-
$this->db->flush();
|
413 |
-
return true;
|
414 |
-
}
|
415 |
-
|
416 |
-
/**
|
417 |
-
* Adapted from interconnect/it's search/replace script.
|
418 |
-
*
|
419 |
-
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
420 |
-
*
|
421 |
-
* Take a serialised array and unserialise it replacing elements as needed and
|
422 |
-
* unserialising any subordinate arrays and performing the replace on those too.
|
423 |
-
*
|
424 |
-
* @access private
|
425 |
-
* @param string $from String we're looking to replace.
|
426 |
-
* @param string $to What we want it to be replaced with
|
427 |
-
* @param array $data Used to pass any subordinate arrays back to in.
|
428 |
-
* @param boolean $serialised Does the array passed via $data need serialising.
|
429 |
-
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
430 |
-
*
|
431 |
-
* @return string|array The original array with all elements replaced as needed.
|
432 |
-
*/
|
433 |
-
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
434 |
-
try {
|
435 |
-
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
436 |
-
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
437 |
-
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
438 |
-
} elseif( is_array( $data ) ) {
|
439 |
-
$tmp = array();
|
440 |
-
foreach ( $data as $key => $value ) {
|
441 |
-
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
442 |
-
}
|
443 |
-
|
444 |
-
$data = $tmp;
|
445 |
-
unset( $tmp );
|
446 |
-
} elseif( is_object( $data ) ) {
|
447 |
-
$tmp = $data;
|
448 |
-
$props = get_object_vars( $data );
|
449 |
-
foreach ( $props as $key => $value ) {
|
450 |
-
if( $key === '' || ord( $key[0] ) === 0 ) {
|
451 |
-
continue;
|
452 |
-
}
|
453 |
-
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
454 |
}
|
455 |
|
456 |
-
$
|
457 |
-
|
458 |
-
} else {
|
459 |
-
if( is_string( $data ) ) {
|
460 |
-
if( !empty( $from ) && !empty( $to ) ) {
|
461 |
-
$data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
462 |
-
}
|
463 |
}
|
464 |
-
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
-
|
473 |
-
|
474 |
-
|
475 |
-
|
476 |
-
/**
|
477 |
-
* Check if the object is a valid one and not __PHP_Incomplete_Class_Name
|
478 |
-
* Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
|
479 |
-
* @return boolean
|
480 |
-
*/
|
481 |
// private function isValidObject($data){
|
482 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
483 |
// return false;
|
@@ -500,189 +556,207 @@ class SearchReplace extends JobExecutable {
|
|
500 |
// return true;
|
501 |
// }
|
502 |
|
503 |
-
|
504 |
-
|
505 |
-
|
506 |
-
|
507 |
-
|
508 |
-
|
509 |
-
|
510 |
-
|
511 |
-
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
-
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
|
524 |
-
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
-
|
529 |
-
|
530 |
-
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
-
|
535 |
-
|
536 |
-
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
-
|
543 |
-
|
544 |
-
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
-
|
549 |
-
|
550 |
-
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
-
|
561 |
-
|
562 |
-
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
-
|
567 |
-
|
568 |
-
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
-
|
573 |
-
|
574 |
-
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
-
|
583 |
-
|
584 |
-
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
-
|
592 |
-
|
593 |
-
|
594 |
-
|
595 |
-
|
596 |
-
|
597 |
-
|
598 |
-
|
599 |
-
|
600 |
-
|
601 |
-
|
602 |
-
|
603 |
-
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
-
|
608 |
-
|
609 |
-
|
610 |
-
|
611 |
-
|
612 |
-
|
613 |
-
|
614 |
-
|
615 |
-
|
616 |
-
|
617 |
-
|
618 |
-
|
619 |
-
|
620 |
-
|
621 |
-
|
622 |
-
|
623 |
-
|
624 |
-
|
625 |
-
|
626 |
-
|
627 |
-
|
628 |
-
|
629 |
-
|
630 |
-
|
631 |
-
|
632 |
-
|
633 |
-
|
634 |
-
|
635 |
-
|
636 |
-
|
637 |
-
|
638 |
-
|
639 |
-
|
640 |
-
|
641 |
-
|
642 |
-
|
643 |
-
|
644 |
-
|
645 |
-
|
646 |
-
|
647 |
-
|
648 |
-
|
649 |
-
|
650 |
-
|
651 |
-
|
652 |
-
|
653 |
-
|
654 |
-
|
655 |
-
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
-
|
660 |
-
|
661 |
-
|
662 |
-
|
663 |
-
|
664 |
-
|
665 |
-
|
666 |
-
|
667 |
-
|
668 |
-
|
669 |
-
|
670 |
-
|
671 |
-
|
672 |
-
|
673 |
-
|
674 |
-
|
675 |
-
|
676 |
-
|
677 |
-
|
678 |
-
|
679 |
-
|
680 |
-
|
681 |
-
|
682 |
-
|
683 |
-
|
684 |
-
|
685 |
-
|
686 |
-
|
687 |
-
|
688 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
use WPStaging\WPStaging;
|
17 |
*/
|
18 |
class SearchReplace extends JobExecutable {
|
19 |
|
20 |
+
/**
|
21 |
+
* @var int
|
22 |
+
*/
|
23 |
+
private $total = 0;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Site DB
|
27 |
+
* @var \WPDB
|
28 |
+
*/
|
29 |
+
public $db;
|
30 |
+
|
31 |
+
|
32 |
+
/**
|
33 |
+
*
|
34 |
+
* @var string
|
35 |
+
*/
|
36 |
+
private $sourceHostname;
|
37 |
+
|
38 |
+
/**
|
39 |
+
*
|
40 |
+
* @var string
|
41 |
+
*/
|
42 |
+
private $destinationHostname;
|
43 |
+
|
44 |
+
/**
|
45 |
+
*
|
46 |
+
* @var Obj
|
47 |
+
*/
|
48 |
+
private $strings;
|
49 |
+
|
50 |
+
/**
|
51 |
+
* The prefix of the new database tables which are used for the live site after updating tables
|
52 |
+
* @var string
|
53 |
+
*/
|
54 |
+
public $tmpPrefix;
|
55 |
+
|
56 |
+
/**
|
57 |
+
* Initialize
|
58 |
+
*/
|
59 |
+
public function initialize() {
|
60 |
+
$this->total = count( $this->options->tables );
|
61 |
+
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
62 |
+
$this->tmpPrefix = $this->options->prefix;
|
63 |
+
$this->strings = new Strings();
|
64 |
+
$this->sourceHostname = $this->getSourceHostname();
|
65 |
+
$this->destinationHostname = $this->getDestinationHostname();
|
66 |
+
}
|
67 |
+
|
68 |
+
public function start() {
|
69 |
+
// Skip job. Nothing to do
|
70 |
+
if( $this->options->totalSteps === 0 ) {
|
71 |
+
$this->prepareResponse( true, false );
|
72 |
+
}
|
73 |
+
|
74 |
+
$this->run();
|
75 |
+
|
76 |
+
// Save option, progress
|
77 |
+
$this->saveOptions();
|
78 |
+
|
79 |
+
return ( object ) $this->response;
|
80 |
+
}
|
81 |
+
|
82 |
+
/**
|
83 |
+
* Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
|
84 |
+
* @return void
|
85 |
+
*/
|
86 |
+
protected function calculateTotalSteps() {
|
87 |
+
$this->options->totalSteps = $this->total;
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* Execute the Current Step
|
92 |
+
* Returns false when over threshold limits are hit or when the job is done, true otherwise
|
93 |
+
* @return bool
|
94 |
+
*/
|
95 |
+
protected function execute() {
|
96 |
+
// Over limits threshold
|
97 |
+
if( $this->isOverThreshold() ) {
|
98 |
+
// Prepare response and save current progress
|
99 |
+
$this->prepareResponse( false, false );
|
100 |
+
$this->saveOptions();
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
+
// No more steps, finished
|
105 |
+
if( $this->options->currentStep > $this->total || !isset( $this->options->tables[$this->options->currentStep] ) ) {
|
106 |
+
$this->prepareResponse( true, false );
|
107 |
+
return false;
|
108 |
+
}
|
109 |
+
|
110 |
+
// Table is excluded
|
111 |
+
if( in_array( $this->options->tables[$this->options->currentStep], $this->options->excludedTables ) ) {
|
112 |
+
$this->prepareResponse();
|
113 |
+
return true;
|
114 |
+
}
|
115 |
+
|
116 |
+
// Search & Replace
|
117 |
+
if( !$this->stopExecution() && !$this->updateTable( $this->options->tables[$this->options->currentStep] ) ) {
|
118 |
+
// Prepare Response
|
119 |
+
$this->prepareResponse( false, false );
|
120 |
+
|
121 |
+
// Not finished
|
122 |
+
return true;
|
123 |
+
}
|
124 |
+
|
125 |
+
|
126 |
+
// Prepare Response
|
127 |
+
$this->prepareResponse();
|
128 |
+
|
129 |
+
// Not finished
|
130 |
+
return true;
|
131 |
+
}
|
132 |
+
|
133 |
+
/**
|
134 |
+
* Stop Execution immediately
|
135 |
+
* return mixed bool | json
|
136 |
+
*/
|
137 |
+
private function stopExecution() {
|
138 |
+
if( $this->db->prefix == $this->tmpPrefix ) {
|
139 |
+
$this->returnException( 'Fatal Error 9: Prefix ' . $this->db->prefix . ' is used for the live site hence it can not be used for the staging site as well. Please ask support@wp-staging.com how to resolve this.' );
|
140 |
+
}
|
141 |
+
return false;
|
142 |
+
}
|
143 |
+
|
144 |
+
/**
|
145 |
+
* Copy Tables
|
146 |
+
* @param string $tableName
|
147 |
+
* @return bool
|
148 |
+
*/
|
149 |
+
private function updateTable( $tableName ) {
|
150 |
+
$strings = new Strings();
|
151 |
+
$table = $strings->str_replace_first( $this->db->prefix, '', $tableName );
|
152 |
+
$newTableName = $this->tmpPrefix . $table;
|
153 |
+
|
154 |
+
// Save current job
|
155 |
+
$this->setJob( $newTableName );
|
156 |
+
|
157 |
+
// Beginning of the job
|
158 |
+
if( !$this->startJob( $newTableName, $tableName ) ) {
|
159 |
+
return true;
|
160 |
+
}
|
161 |
+
// Copy data
|
162 |
+
$this->startReplace( $newTableName );
|
163 |
+
|
164 |
+
// Finish the step
|
165 |
+
return $this->finishStep();
|
166 |
+
}
|
167 |
+
|
168 |
+
/**
|
169 |
+
* Get source Hostname depending on wheather WP has been installed in sub dir or not
|
170 |
+
* @return type
|
171 |
+
*/
|
172 |
+
private function getSourceHostname() {
|
173 |
+
// default
|
174 |
+
$host = $this->options->homeHostname;
|
175 |
+
|
176 |
+
if( $this->isSubDir() ) {
|
177 |
+
$host = trailingslashit($this->options->homeHostname) . $this->getSubDir();
|
178 |
+
}
|
179 |
+
return $this->strings->getUrlWithoutScheme( $host );
|
180 |
+
}
|
181 |
+
|
182 |
+
/**
|
183 |
+
* Get destination Hostname depending on wheather WP has been installed in sub dir or not
|
184 |
+
* @return type
|
185 |
+
*/
|
186 |
+
private function getDestinationHostname() {
|
187 |
+
// default
|
188 |
+
$host = trailingslashit( $this->options->destinationHostname ) . $this->options->cloneDirectoryName;
|
189 |
+
|
190 |
+
if( !empty( $this->options->cloneHostname ) ) {
|
191 |
+
$host = $this->options->cloneHostname;
|
192 |
+
}
|
193 |
+
|
194 |
+
if( $this->isSubDir() ) {
|
195 |
+
$host = trailingslashit( $this->options->destinationHostname ) . $this->getSubDir() . '/' . $this->options->cloneDirectoryName;
|
196 |
+
}
|
197 |
+
return $this->strings->getUrlWithoutScheme( $host );
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Get the install sub directory if WP is installed in sub directory
|
202 |
+
* @return string
|
203 |
+
*/
|
204 |
+
private function getSubDir() {
|
205 |
+
$home = get_option( 'home' );
|
206 |
+
$siteurl = get_option( 'siteurl' );
|
207 |
+
|
208 |
+
if( empty( $home ) || empty( $siteurl ) ) {
|
209 |
+
return '';
|
210 |
+
}
|
211 |
+
|
212 |
+
$dir = str_replace( $home, '', $siteurl );
|
213 |
+
return str_replace( '/', '', $dir );
|
214 |
+
}
|
215 |
+
|
216 |
+
/**
|
217 |
+
* Start search replace job
|
218 |
+
* @param string $new
|
219 |
+
* @param string $old
|
220 |
+
*/
|
221 |
+
private function startReplace( $table ) {
|
222 |
+
$rows = $this->options->job->start + $this->settings->querySRLimit;
|
223 |
+
$this->log(
|
224 |
+
"DB Processing: Table {$table} {$this->options->job->start} to {$rows} records"
|
225 |
+
);
|
226 |
+
|
227 |
+
// Search & Replace
|
228 |
+
$this->searchReplace( $table, $rows, array() );
|
229 |
+
|
230 |
+
// Set new offset
|
231 |
+
$this->options->job->start += $this->settings->querySRLimit;
|
232 |
+
}
|
233 |
+
|
234 |
+
/**
|
235 |
+
* Returns the number of pages in a table.
|
236 |
+
* @access public
|
237 |
+
* @return int
|
238 |
+
*/
|
239 |
+
private function get_pages_in_table( $table ) {
|
240 |
+
|
241 |
+
// Table does not exists
|
242 |
+
$table = str_replace( $this->options->prefix . '.', null, $table );
|
243 |
+
$result = $this->db->query( "SHOW TABLES LIKE '{$table}'" );
|
244 |
+
if( !$result || 0 === $result ) {
|
245 |
+
return 0;
|
246 |
+
}
|
247 |
+
|
248 |
+
$table = esc_sql( $table );
|
249 |
+
$rows = $this->db->get_var( "SELECT COUNT(*) FROM $table" );
|
250 |
+
$pages = ceil( $rows / $this->settings->querySRLimit );
|
251 |
+
return absint( $pages );
|
252 |
+
}
|
253 |
+
|
254 |
+
/**
|
255 |
+
* Gets the columns in a table.
|
256 |
+
* @access public
|
257 |
+
* @param string $table The table to check.
|
258 |
+
* @return array
|
259 |
+
*/
|
260 |
+
private function get_columns( $table ) {
|
261 |
+
$primary_key = null;
|
262 |
+
$columns = array();
|
263 |
+
$fields = $this->db->get_results( 'DESCRIBE ' . $table );
|
264 |
+
if( is_array( $fields ) ) {
|
265 |
+
foreach ( $fields as $column ) {
|
266 |
+
$columns[] = $column->Field;
|
267 |
+
if( $column->Key == 'PRI' ) {
|
268 |
+
$primary_key = $column->Field;
|
269 |
+
}
|
270 |
}
|
271 |
+
}
|
272 |
+
return array($primary_key, $columns);
|
273 |
+
}
|
274 |
+
|
275 |
+
/**
|
276 |
+
* Adapated from interconnect/it's search/replace script, adapted from Better Search Replace
|
277 |
+
*
|
278 |
+
* Modified to use WordPress wpdb functions instead of PHP's native mysql/pdo functions,
|
279 |
+
* and to be compatible with batch processing.
|
280 |
+
*
|
281 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
282 |
+
*
|
283 |
+
* @access public
|
284 |
+
* @param string $table The table to run the replacement on.
|
285 |
+
* @param int $page The page/block to begin the query on.
|
286 |
+
* @param array $args An associative array containing arguments for this run.
|
287 |
+
* @return array
|
288 |
+
*/
|
289 |
+
private function searchReplace( $table, $page, $args ) {
|
290 |
+
|
291 |
+
if( $this->thirdParty->isSearchReplaceExcluded( $table ) ) {
|
292 |
+
$this->log( "DB Processing: Skip {$table}", \WPStaging\Utils\Logger::TYPE_INFO );
|
293 |
+
return true;
|
294 |
+
}
|
295 |
+
|
296 |
+
// Load up the default settings for this chunk.
|
297 |
+
$table = esc_sql( $table );
|
298 |
+
$current_page = $this->options->job->start + $this->settings->querySRLimit;
|
299 |
+
$pages = $this->get_pages_in_table( $table );
|
300 |
+
|
301 |
+
|
302 |
+
$args['search_for'] = array(
|
303 |
+
'\/\/' . str_replace( '/', '\/', $this->sourceHostname ), // Escaped \/ used by revslider and several visual editors
|
304 |
+
'//' . $this->sourceHostname,
|
305 |
+
rtrim( ABSPATH, '/' ),
|
306 |
+
);
|
307 |
+
|
308 |
+
$args['replace_with'] = array(
|
309 |
+
'\/\/' . str_replace( '/', '\/', $this->destinationHostname ),
|
310 |
+
'//' . $this->destinationHostname,
|
311 |
+
$this->options->destinationDir,
|
312 |
+
);
|
313 |
+
|
314 |
+
|
315 |
+
$args['replace_guids'] = 'off';
|
316 |
+
$args['dry_run'] = 'off';
|
317 |
+
$args['case_insensitive'] = false;
|
318 |
+
$args['replace_mails'] = 'off';
|
319 |
+
$args['skip_transients'] = 'on';
|
320 |
+
|
321 |
+
|
322 |
+
// Allow filtering of search & replace parameters
|
323 |
+
$args = apply_filters( 'wpstg_clone_searchreplace_params', $args );
|
324 |
+
|
325 |
+
// Get a list of columns in this table.
|
326 |
+
list( $primary_key, $columns ) = $this->get_columns( $table );
|
327 |
+
|
328 |
+
// Bail out early if there isn't a primary key.
|
329 |
+
// We commented this to search & replace through tables which have no primary keys like wp_revslider_slides
|
330 |
+
// @todo test this carefully. If it causes (performance) issues we need to activate it again!
|
331 |
+
// @since 2.4.4
|
332 |
+
// if( null === $primary_key ) {
|
333 |
+
// return false;
|
334 |
+
// }
|
335 |
+
|
336 |
+
$current_row = 0;
|
337 |
+
$start = $this->options->job->start;
|
338 |
+
$end = $this->settings->querySRLimit;
|
339 |
+
|
340 |
+
// Grab the content of the table.
|
341 |
+
$data = $this->db->get_results( "SELECT * FROM $table LIMIT $start, $end", ARRAY_A );
|
342 |
+
|
343 |
+
// Filter certain rows (of other plugins)
|
344 |
+
$filter = array(
|
345 |
+
'Admin_custome_login_Slidshow',
|
346 |
+
'Admin_custome_login_Social',
|
347 |
+
'Admin_custome_login_logo',
|
348 |
+
'Admin_custome_login_text',
|
349 |
+
'Admin_custome_login_login',
|
350 |
+
'Admin_custome_login_top',
|
351 |
+
'Admin_custome_login_dashboard',
|
352 |
+
'Admin_custome_login_Version',
|
353 |
+
'upload_path',
|
354 |
+
);
|
355 |
+
|
356 |
+
$filter = apply_filters( 'wpstg_clone_searchreplace_excl_rows', $filter );
|
357 |
+
|
358 |
+
// Loop through the data.
|
359 |
+
foreach ( $data as $row ) {
|
360 |
+
$current_row++;
|
361 |
+
$update_sql = array();
|
362 |
+
$where_sql = array();
|
363 |
+
$upd = false;
|
364 |
+
|
365 |
+
// Skip rows below
|
366 |
+
if( isset( $row['option_name'] ) && in_array( $row['option_name'], $filter ) ) {
|
367 |
+
continue;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
368 |
}
|
369 |
|
370 |
+
// Skip rows with transients (They can store huge data and we need to save memory)
|
371 |
+
if( isset( $row['option_name'] ) && 'on' === $args['skip_transients'] && false !== strpos( $row['option_name'], '_transient' ) ) {
|
372 |
+
continue;
|
373 |
}
|
374 |
|
375 |
+
foreach ( $columns as $column ) {
|
376 |
+
|
377 |
+
$dataRow = $row[$column];
|
378 |
+
|
379 |
+
if( $column == $primary_key ) {
|
380 |
+
$where_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
381 |
+
continue;
|
382 |
+
}
|
383 |
+
|
384 |
+
// Skip GUIDs by default.
|
385 |
+
if( 'on' !== $args['replace_guids'] && 'guid' == $column ) {
|
386 |
+
continue;
|
387 |
+
}
|
388 |
+
|
389 |
+
// Skip mail addresses
|
390 |
+
if( 'off' === $args['replace_mails'] && false !== strpos( $dataRow, '@' .$this->options->homeHostname ) ) {
|
391 |
+
continue;
|
392 |
+
}
|
393 |
+
|
394 |
+
|
395 |
+
// Check options table
|
396 |
+
if( $this->options->prefix . 'options' === $table ) {
|
397 |
+
|
398 |
+
// Skip certain options
|
399 |
+
if( isset( $should_skip ) && true === $should_skip ) {
|
400 |
+
$should_skip = false;
|
401 |
+
continue;
|
402 |
+
}
|
403 |
+
|
404 |
+
// Skip this row
|
405 |
+
if( 'wpstg_existing_clones_beta' === $dataRow ||
|
406 |
+
'wpstg_existing_clones' === $dataRow ||
|
407 |
+
'wpstg_settings' === $dataRow ||
|
408 |
+
'wpstg_license_status' === $dataRow ||
|
409 |
+
'siteurl' === $dataRow ||
|
410 |
+
'home' === $dataRow
|
411 |
+
) {
|
412 |
+
$should_skip = true;
|
413 |
+
}
|
414 |
+
}
|
415 |
+
|
416 |
+
// Check the path delimiter for / or \/ and remove one of those which prevents from resulting in wrong syntax like domain.com/staging\/.
|
417 |
+
// 1. local.wordpress.test -> local.wordpress.test/staging
|
418 |
+
// 2. local.wordpress.test\/ -> local.wordpress.test\/staging\/
|
419 |
+
$tmp = $args;
|
420 |
+
if( false === strpos( $dataRow, $tmp['search_for'][0] ) ) {
|
421 |
+
array_shift( $tmp['search_for'] ); // rtrim( $this->options->homeHostname, '/' ),
|
422 |
+
array_shift( $tmp['replace_with'] ); // rtrim( $this->options->homeHostname, '/' ) . '/' . $this->options->cloneDirectoryName,
|
423 |
+
} else {
|
424 |
+
unset( $tmp['search_for'][1] );
|
425 |
+
unset( $tmp['replace_with'][1] );
|
426 |
+
// recount array
|
427 |
+
$tmp['search_for'] = array_values( $tmp['search_for'] );
|
428 |
+
$tmp['replace_with'] = array_values( $tmp['replace_with'] );
|
429 |
+
}
|
430 |
+
|
431 |
+
// Run a search replace on the data row and respect the serialisation.
|
432 |
+
$i = 0;
|
433 |
+
foreach ( $tmp['search_for'] as $replace ) {
|
434 |
+
$dataRow = $this->recursive_unserialize_replace( $tmp['search_for'][$i], $tmp['replace_with'][$i], $dataRow, false, $args['case_insensitive'] );
|
435 |
+
$i++;
|
436 |
+
}
|
437 |
+
unset( $replace );
|
438 |
+
unset( $i );
|
439 |
+
unset( $tmp );
|
440 |
+
|
441 |
+
// Something was changed
|
442 |
+
if( $row[$column] != $dataRow ) {
|
443 |
+
$update_sql[] = $column . ' = "' . $this->mysql_escape_mimic( $dataRow ) . '"';
|
444 |
+
$upd = true;
|
445 |
+
}
|
446 |
}
|
447 |
|
448 |
+
// Determine what to do with updates.
|
449 |
+
if( $args['dry_run'] === 'on' ) {
|
450 |
+
// Don't do anything if a dry run
|
451 |
+
} elseif( $upd && !empty( $where_sql ) ) {
|
452 |
+
// If there are changes to make, run the query.
|
453 |
+
$sql = 'UPDATE ' . $table . ' SET ' . implode( ', ', $update_sql ) . ' WHERE ' . implode( ' AND ', array_filter( $where_sql ) );
|
454 |
+
$result = $this->db->query( $sql );
|
455 |
+
|
456 |
+
if( !$result ) {
|
457 |
+
$this->log( "Error updating row {$current_row} SQL: {$sql}", \WPStaging\Utils\Logger::TYPE_ERROR );
|
458 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
459 |
}
|
460 |
+
} // end row loop
|
461 |
+
unset( $row );
|
462 |
+
unset( $update_sql );
|
463 |
+
unset( $where_sql );
|
464 |
+
unset( $sql );
|
465 |
+
|
466 |
+
|
467 |
+
// DB Flush
|
468 |
+
$this->db->flush();
|
469 |
+
return true;
|
470 |
+
}
|
471 |
+
|
472 |
+
/**
|
473 |
+
* Adapted from interconnect/it's search/replace script.
|
474 |
+
*
|
475 |
+
* @link https://interconnectit.com/products/search-and-replace-for-wordpress-databases/
|
476 |
+
*
|
477 |
+
* Take a serialised array and unserialise it replacing elements as needed and
|
478 |
+
* unserialising any subordinate arrays and performing the replace on those too.
|
479 |
+
*
|
480 |
+
* @access private
|
481 |
+
* @param string $from String we're looking to replace.
|
482 |
+
* @param string $to What we want it to be replaced with
|
483 |
+
* @param array $data Used to pass any subordinate arrays back to in.
|
484 |
+
* @param boolean $serialized Does the array passed via $data need serialising.
|
485 |
+
* @param sting|boolean $case_insensitive Set to 'on' if we should ignore case, false otherwise.
|
486 |
+
*
|
487 |
+
* @return string|array The original array with all elements replaced as needed.
|
488 |
+
*/
|
489 |
+
private function recursive_unserialize_replace( $from = '', $to = '', $data = '', $serialized = false, $case_insensitive = false ) {
|
490 |
+
try {
|
491 |
+
// Some unserialized data cannot be re-serialized eg. SimpleXMLElements
|
492 |
+
if( is_serialized( $data ) && ( $unserialized = @unserialize( $data ) ) !== false ) {
|
493 |
+
$data = $this->recursive_unserialize_replace( $from, $to, $unserialized, true, $case_insensitive );
|
494 |
+
} elseif( is_array( $data ) ) {
|
495 |
+
$tmp = array();
|
496 |
+
foreach ( $data as $key => $value ) {
|
497 |
+
$tmp[$key] = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
498 |
+
}
|
499 |
+
|
500 |
+
$data = $tmp;
|
501 |
+
unset( $tmp );
|
502 |
+
} elseif( is_object( $data ) ) {
|
503 |
+
$tmp = $data;
|
504 |
+
$props = get_object_vars( $data );
|
505 |
+
foreach ( $props as $key => $value ) {
|
506 |
+
if( $key === '' || ord( $key[0] ) === 0 ) {
|
507 |
+
continue;
|
508 |
+
}
|
509 |
+
$tmp->$key = $this->recursive_unserialize_replace( $from, $to, $value, false, $case_insensitive );
|
510 |
+
}
|
511 |
+
|
512 |
+
$data = $tmp;
|
513 |
+
unset( $tmp );
|
514 |
} else {
|
515 |
+
if( is_string( $data ) ) {
|
516 |
+
if( !empty( $from ) && !empty( $to ) ) {
|
517 |
+
$data = $this->str_replace( $from, $to, $data, $case_insensitive );
|
518 |
+
}
|
519 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
520 |
}
|
521 |
|
522 |
+
if( $serialized ) {
|
523 |
+
return serialize( $data );
|
|
|
|
|
|
|
|
|
|
|
524 |
}
|
525 |
+
} catch ( Exception $error ) {
|
526 |
+
|
527 |
+
}
|
528 |
+
|
529 |
+
return $data;
|
530 |
+
}
|
531 |
+
|
532 |
+
/**
|
533 |
+
* Check if the object is a valid one and not __PHP_Incomplete_Class_Name
|
534 |
+
* Can not use is_object alone because in php 7.2 it's returning true even though object is __PHP_Incomplete_Class_Name
|
535 |
+
* @return boolean
|
536 |
+
*/
|
|
|
|
|
|
|
|
|
|
|
537 |
// private function isValidObject($data){
|
538 |
// if( !is_object( $data ) || gettype( $data ) != 'object' ) {
|
539 |
// return false;
|
556 |
// return true;
|
557 |
// }
|
558 |
|
559 |
+
/**
|
560 |
+
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
561 |
+
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
562 |
+
* @access public
|
563 |
+
* @param string $input The string to escape.
|
564 |
+
* @return string
|
565 |
+
*/
|
566 |
+
private function mysql_escape_mimic( $input ) {
|
567 |
+
if( is_array( $input ) ) {
|
568 |
+
return array_map( __METHOD__, $input );
|
569 |
+
}
|
570 |
+
if( !empty( $input ) && is_string( $input ) ) {
|
571 |
+
return str_replace( array('\\', "\0", "\n", "\r", "'", '"', "\x1a"), array('\\\\', '\\0', '\\n', '\\r', "\\'", '\\"', '\\Z'), $input );
|
572 |
+
}
|
573 |
+
|
574 |
+
return $input;
|
575 |
+
}
|
576 |
+
|
577 |
+
/**
|
578 |
+
* Return unserialized object or array
|
579 |
+
*
|
580 |
+
* @param string $serialized_string Serialized string.
|
581 |
+
* @param string $method The name of the caller method.
|
582 |
+
*
|
583 |
+
* @return mixed, false on failure
|
584 |
+
*/
|
585 |
+
private static function unserialize( $serialized_string ) {
|
586 |
+
if( !is_serialized( $serialized_string ) ) {
|
587 |
+
return false;
|
588 |
+
}
|
589 |
+
|
590 |
+
$serialized_string = trim( $serialized_string );
|
591 |
+
$unserialized_string = @unserialize( $serialized_string );
|
592 |
+
|
593 |
+
return $unserialized_string;
|
594 |
+
}
|
595 |
+
|
596 |
+
/**
|
597 |
+
* Wrapper for str_replace
|
598 |
+
*
|
599 |
+
* @param string $from
|
600 |
+
* @param string $to
|
601 |
+
* @param string $data
|
602 |
+
* @param string|bool $case_insensitive
|
603 |
+
*
|
604 |
+
* @return string
|
605 |
+
*/
|
606 |
+
private function str_replace( $from, $to, $data, $case_insensitive = false ) {
|
607 |
+
|
608 |
+
// Add filter
|
609 |
+
$excludes = apply_filters( 'wpstg_clone_searchreplace_excl', array() );
|
610 |
+
|
611 |
+
// Build pattern
|
612 |
+
$regexExclude = '';
|
613 |
+
foreach ( $excludes as $exclude ) {
|
614 |
+
$regexExclude .= $exclude . '(*SKIP)(FAIL)|';
|
615 |
+
}
|
616 |
+
|
617 |
+
if( 'on' === $case_insensitive ) {
|
618 |
+
//$data = str_ireplace( $from, $to, $data );
|
619 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#i', $to, $data );
|
620 |
+
} else {
|
621 |
+
//$data = str_replace( $from, $to, $data );
|
622 |
+
$data = preg_replace( '#' . $regexExclude . preg_quote( $from ) . '#', $to, $data );
|
623 |
+
}
|
624 |
+
|
625 |
+
return $data;
|
626 |
+
}
|
627 |
+
|
628 |
+
/**
|
629 |
+
* Set the job
|
630 |
+
* @param string $table
|
631 |
+
*/
|
632 |
+
private function setJob( $table ) {
|
633 |
+
if( !empty( $this->options->job->current ) ) {
|
634 |
+
return;
|
635 |
+
}
|
636 |
+
|
637 |
+
$this->options->job->current = $table;
|
638 |
+
$this->options->job->start = 0;
|
639 |
+
}
|
640 |
+
|
641 |
+
/**
|
642 |
+
* Start Job
|
643 |
+
* @param string $new
|
644 |
+
* @param string $old
|
645 |
+
* @return bool
|
646 |
+
*/
|
647 |
+
private function startJob( $new, $old ) {
|
648 |
+
|
649 |
+
if( $this->isExcludedTable( $new ) ) {
|
650 |
+
return false;
|
651 |
+
}
|
652 |
+
|
653 |
+
// Table does not exists
|
654 |
+
$result = $this->db->query( "SHOW TABLES LIKE '{$old}'" );
|
655 |
+
if( !$result || 0 === $result ) {
|
656 |
+
return false;
|
657 |
+
}
|
658 |
+
|
659 |
+
if( 0 != $this->options->job->start ) {
|
660 |
+
return true;
|
661 |
+
}
|
662 |
+
|
663 |
+
$this->options->job->total = ( int ) $this->db->get_var( "SELECT COUNT(1) FROM {$old}" );
|
664 |
+
|
665 |
+
if( 0 == $this->options->job->total ) {
|
666 |
+
$this->finishStep();
|
667 |
+
return false;
|
668 |
+
}
|
669 |
+
|
670 |
+
return true;
|
671 |
+
}
|
672 |
+
|
673 |
+
/**
|
674 |
+
* Is table excluded from search replace processing?
|
675 |
+
* @param string $table
|
676 |
+
* @return boolean
|
677 |
+
*/
|
678 |
+
private function isExcludedTable( $table ) {
|
679 |
+
|
680 |
+
$customTables = apply_filters( 'wpstg_clone_searchreplace_tables_exclude', array() );
|
681 |
+
$defaultTables = array('blogs');
|
682 |
+
|
683 |
+
$tables = array_merge( $customTables, $defaultTables );
|
684 |
+
|
685 |
+
$excludedTables = array();
|
686 |
+
foreach ( $tables as $key => $value ) {
|
687 |
+
$excludedTables[] = $this->options->prefix . $value;
|
688 |
+
}
|
689 |
+
|
690 |
+
if( in_array( $table, $excludedTables ) ) {
|
691 |
+
return true;
|
692 |
+
}
|
693 |
+
return false;
|
694 |
+
}
|
695 |
+
|
696 |
+
/**
|
697 |
+
* Finish the step
|
698 |
+
*/
|
699 |
+
private function finishStep() {
|
700 |
+
// This job is not finished yet
|
701 |
+
if( $this->options->job->total > $this->options->job->start ) {
|
702 |
+
return false;
|
703 |
+
}
|
704 |
+
|
705 |
+
// Add it to cloned tables listing
|
706 |
+
$this->options->clonedTables[] = $this->options->tables[$this->options->currentStep];
|
707 |
+
|
708 |
+
// Reset job
|
709 |
+
$this->options->job = new \stdClass();
|
710 |
+
|
711 |
+
return true;
|
712 |
+
}
|
713 |
+
|
714 |
+
/**
|
715 |
+
* Drop table if necessary
|
716 |
+
* @param string $new
|
717 |
+
*/
|
718 |
+
private function dropTable( $new ) {
|
719 |
+
$old = $this->db->get_var( $this->db->prepare( "SHOW TABLES LIKE %s", $new ) );
|
720 |
+
|
721 |
+
if( !$this->shouldDropTable( $new, $old ) ) {
|
722 |
+
return;
|
723 |
+
}
|
724 |
+
|
725 |
+
$this->log( "DB Processing: {$new} already exists, dropping it first" );
|
726 |
+
$this->db->query( "DROP TABLE {$new}" );
|
727 |
+
}
|
728 |
+
|
729 |
+
/**
|
730 |
+
* Check if table needs to be dropped
|
731 |
+
* @param string $new
|
732 |
+
* @param string $old
|
733 |
+
* @return bool
|
734 |
+
*/
|
735 |
+
private function shouldDropTable( $new, $old ) {
|
736 |
+
return (
|
737 |
+
$old == $new &&
|
738 |
+
(
|
739 |
+
!isset( $this->options->job->current ) ||
|
740 |
+
!isset( $this->options->job->start ) ||
|
741 |
+
0 == $this->options->job->start
|
742 |
+
)
|
743 |
+
);
|
744 |
+
}
|
745 |
+
|
746 |
+
/**
|
747 |
+
* Check if WP is installed in subdir
|
748 |
+
* @return boolean
|
749 |
+
*/
|
750 |
+
private function isSubDir() {
|
751 |
+
// Compare names without scheme to bypass cases where siteurl and home have different schemes http / https
|
752 |
+
// This is happening much more often than you would expect
|
753 |
+
$siteurl = preg_replace( '#^https?://#', '', rtrim( get_option( 'siteurl' ), '/' ) );
|
754 |
+
$home = preg_replace( '#^https?://#', '', rtrim( get_option( 'home' ), '/' ) );
|
755 |
+
|
756 |
+
if( $home !== $siteurl ) {
|
757 |
+
return true;
|
758 |
+
}
|
759 |
+
return false;
|
760 |
+
}
|
761 |
+
|
762 |
+
}
|
@@ -10,6 +10,7 @@ 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
|
@@ -17,257 +18,305 @@ use WPStaging\Backend\Modules\Jobs\Multisite\Files as muFiles;
|
|
17 |
*/
|
18 |
class Updating extends Job {
|
19 |
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
148 |
} else {
|
149 |
-
|
150 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
151 |
}
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
272 |
|
273 |
}
|
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 |
+
use WPStaging\Utils\Helper;
|
14 |
|
15 |
/**
|
16 |
* Class Cloning
|
18 |
*/
|
19 |
class Updating extends Job {
|
20 |
|
21 |
+
/**
|
22 |
+
* External Database Used
|
23 |
+
* @var bool
|
24 |
+
*/
|
25 |
+
public $isExternal;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* Initialize is called in \Job
|
29 |
+
*/
|
30 |
+
public function initialize() {
|
31 |
+
$this->db = WPStaging::getInstance()->get( "wpdb" );
|
32 |
+
}
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Save Chosen Cloning Settings
|
36 |
+
* @return bool
|
37 |
+
*/
|
38 |
+
public function save() {
|
39 |
+
if( !isset( $_POST ) || !isset( $_POST["cloneID"] ) ) {
|
40 |
+
return false;
|
41 |
+
}
|
42 |
+
|
43 |
+
// Delete files to copy listing
|
44 |
+
$this->cache->delete( "files_to_copy" );
|
45 |
+
|
46 |
+
// Generate Options
|
47 |
+
// Clone
|
48 |
+
$this->options->clone = $_POST["cloneID"];
|
49 |
+
$this->options->cloneDirectoryName = preg_replace( "#\W+#", '-', strtolower( $this->options->clone ) );
|
50 |
+
$this->options->cloneNumber = 1;
|
51 |
+
$this->options->includedDirectories = array();
|
52 |
+
$this->options->excludedDirectories = array();
|
53 |
+
$this->options->extraDirectories = array();
|
54 |
+
$this->options->excludedFiles = array(
|
55 |
+
'.htaccess',
|
56 |
+
'.DS_Store',
|
57 |
+
'.git',
|
58 |
+
'.svn',
|
59 |
+
'.tmp',
|
60 |
+
'desktop.ini',
|
61 |
+
'.gitignore',
|
62 |
+
'.log',
|
63 |
+
'db.php',
|
64 |
+
'object-cache.php'
|
65 |
+
);
|
66 |
+
|
67 |
+
$this->options->excludedFilesFullPath = array(
|
68 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'db.php',
|
69 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'object-cache.php',
|
70 |
+
'wp-content' . DIRECTORY_SEPARATOR . 'advanced-cache.php'
|
71 |
+
);
|
72 |
+
|
73 |
+
// Define mainJob to differentiate between cloning, updating and pushing
|
74 |
+
$this->options->mainJob = 'updating';
|
75 |
+
|
76 |
+
// Job
|
77 |
+
$this->options->job = new \stdClass();
|
78 |
+
|
79 |
+
// Check if clone data already exists and use that one
|
80 |
+
if( isset( $this->options->existingClones[$this->options->clone] ) ) {
|
81 |
+
$this->options->cloneNumber = $this->options->existingClones[$this->options->clone]['number'];
|
82 |
+
$this->options->databaseUser = $this->options->existingClones[$this->options->clone]['databaseUser'];
|
83 |
+
$this->options->databasePassword = $this->options->existingClones[$this->options->clone]['databasePassword'];
|
84 |
+
$this->options->databaseDatabase = $this->options->existingClones[$this->options->clone]['databaseDatabase'];
|
85 |
+
$this->options->databaseServer = $this->options->existingClones[$this->options->clone]['databaseServer'];
|
86 |
+
$this->options->databasePrefix = $this->options->existingClones[$this->options->clone]['databasePrefix'];
|
87 |
+
$this->options->destinationHostname = $this->options->existingClones[$this->options->clone]['url'];
|
88 |
+
$this->options->prefix = $this->getStagingPrefix();
|
89 |
+
$helper = new Helper();
|
90 |
+
$this->options->homeHostname = $helper->get_home_url_without_scheme();
|
91 |
+
} else {
|
92 |
+
wp_die( 'Fatal Error: Can not update clone because there is no clone data.' );
|
93 |
+
}
|
94 |
+
|
95 |
+
$this->isExternal = (empty( $this->options->databaseUser ) && empty( $this->options->databasePassword )) ? false : true;
|
96 |
+
|
97 |
+
// Included Tables
|
98 |
+
if( isset( $_POST["includedTables"] ) && is_array( $_POST["includedTables"] ) ) {
|
99 |
+
$this->options->tables = $_POST["includedTables"];
|
100 |
+
} else {
|
101 |
+
$this->options->tables = array();
|
102 |
+
}
|
103 |
+
|
104 |
+
// Excluded Directories
|
105 |
+
if( isset( $_POST["excludedDirectories"] ) && is_array( $_POST["excludedDirectories"] ) ) {
|
106 |
+
$this->options->excludedDirectories = $_POST["excludedDirectories"];
|
107 |
+
}
|
108 |
+
|
109 |
+
// Excluded Directories TOTAL
|
110 |
+
// Do not copy these folders and plugins
|
111 |
+
$excludedDirectories = array(
|
112 |
+
ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'cache',
|
113 |
+
ABSPATH . 'wp-content' . DIRECTORY_SEPARATOR . 'plugins' . DIRECTORY_SEPARATOR . 'wps-hide-login'
|
114 |
+
);
|
115 |
+
|
116 |
+
$this->options->excludedDirectories = array_merge( $excludedDirectories, $this->options->excludedDirectories );
|
117 |
+
|
118 |
+
// Included Directories
|
119 |
+
if( isset( $_POST["includedDirectories"] ) && is_array( $_POST["includedDirectories"] ) ) {
|
120 |
+
$this->options->includedDirectories = $_POST["includedDirectories"];
|
121 |
+
}
|
122 |
+
|
123 |
+
// Extra Directories
|
124 |
+
if( isset( $_POST["extraDirectories"] ) && !empty( $_POST["extraDirectories"] ) ) {
|
125 |
+
$this->options->extraDirectories = $_POST["extraDirectories"];
|
126 |
+
}
|
127 |
+
|
128 |
+
$this->options->cloneDir = '';
|
129 |
+
if( isset( $_POST["cloneDir"] ) && !empty( $_POST["cloneDir"] ) ) {
|
130 |
+
$this->options->cloneDir = trailingslashit( $_POST["cloneDir"] );
|
131 |
+
}
|
132 |
+
|
133 |
+
//$this->options->destinationDir = !empty( $this->options->cloneDir ) ? trailingslashit( $this->options->cloneDir ) : trailingslashit( $this->options->existingClones[$this->options->clone]['path'] );
|
134 |
+
|
135 |
+
$this->options->destinationDir = $this->getDestinationDir();
|
136 |
+
|
137 |
+
$this->options->cloneHostname = '';
|
138 |
+
if( isset( $_POST["cloneHostname"] ) && !empty( $_POST["cloneHostname"] ) ) {
|
139 |
+
$this->options->cloneHostname = $_POST["cloneHostname"];
|
140 |
+
}
|
141 |
+
|
142 |
+
// Directories to Copy
|
143 |
+
$this->options->directoriesToCopy = array_merge(
|
144 |
+
$this->options->includedDirectories, $this->options->extraDirectories
|
145 |
+
);
|
146 |
+
|
147 |
+
array_unshift( $this->options->directoriesToCopy, ABSPATH );
|
148 |
+
|
149 |
+
return $this->saveOptions();
|
150 |
+
}
|
151 |
+
|
152 |
+
/**
|
153 |
+
* Get Destination Directory including staging subdirectory
|
154 |
+
* @return type
|
155 |
+
*/
|
156 |
+
private function getDestinationDir() {
|
157 |
+
if( empty( $this->options->cloneDir ) ) {
|
158 |
+
return trailingslashit( \WPStaging\WPStaging::getWPpath() . $this->options->cloneDirectoryName );
|
159 |
+
}
|
160 |
+
//return trailingslashit( $this->options->cloneDir . $this->options->cloneDirectoryName );
|
161 |
+
return trailingslashit( $this->options->cloneDir );
|
162 |
+
}
|
163 |
+
|
164 |
+
/**
|
165 |
+
* Check and return prefix of the staging site
|
166 |
+
*/
|
167 |
+
public function getStagingPrefix() {
|
168 |
+
// prefix not defined! Happens if staging site has ben generated with older version of wpstg
|
169 |
+
// Try to get staging prefix from wp-config.php of staging site
|
170 |
+
$this->options->prefix = $this->options->existingClones[$this->options->clone]['prefix'];
|
171 |
+
if( empty( $this->options->prefix ) ) {
|
172 |
+
// Throw error if wp-config.php is not readable
|
173 |
+
$path = ABSPATH . $this->options->cloneDirectoryName . "/wp-config.php";
|
174 |
+
if( false === ($content = @file_get_contents( $path )) ) {
|
175 |
+
$this->log( "Can not open {$path}. Can't read contents", Logger::TYPE_ERROR );
|
176 |
+
$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" );
|
177 |
+
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" );
|
178 |
} else {
|
179 |
+
// Get prefix from wp-config.php
|
180 |
+
preg_match( "/table_prefix\s*=\s*'(\w*)';/", $content, $matches );
|
181 |
+
|
182 |
+
if( !empty( $matches[1] ) ) {
|
183 |
+
$this->options->prefix = $matches[1];
|
184 |
+
} else {
|
185 |
+
$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" );
|
186 |
+
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" );
|
187 |
+
}
|
188 |
}
|
189 |
+
}
|
190 |
+
|
191 |
+
// Die() if staging prefix is the same as the live prefix
|
192 |
+
if( false === $this->isExternal && $this->db->prefix == $this->options->prefix ) {
|
193 |
+
$this->log( "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" );
|
194 |
+
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" );
|
195 |
+
}
|
196 |
+
|
197 |
+
// Else
|
198 |
+
return $this->options->prefix;
|
199 |
+
}
|
200 |
+
|
201 |
+
/**
|
202 |
+
* Start the cloning job
|
203 |
+
*/
|
204 |
+
public function start() {
|
205 |
+
if( null === $this->options->currentJob ) {
|
206 |
+
$this->log( "Cloning job for {$this->options->clone} finished" );
|
207 |
+
return true;
|
208 |
+
}
|
209 |
+
|
210 |
+
$methodName = "job" . ucwords( $this->options->currentJob );
|
211 |
+
|
212 |
+
if( !method_exists( $this, $methodName ) ) {
|
213 |
+
$this->log( "Can't execute job; Job's method {$methodName} is not found" );
|
214 |
+
throw new JobNotFoundException( $methodName );
|
215 |
+
}
|
216 |
+
|
217 |
+
// Call the job
|
218 |
+
//$this->log("execute job: Job's method {$methodName}");
|
219 |
+
return $this->{$methodName}();
|
220 |
+
}
|
221 |
+
|
222 |
+
/**
|
223 |
+
* @param object $response
|
224 |
+
* @param string $nextJob
|
225 |
+
* @return object
|
226 |
+
*/
|
227 |
+
private function handleJobResponse( $response, $nextJob ) {
|
228 |
+
// Job is not done
|
229 |
+
if( true !== $response->status ) {
|
230 |
+
return $response;
|
231 |
+
}
|
232 |
+
|
233 |
+
$this->options->currentJob = $nextJob;
|
234 |
+
$this->options->currentStep = 0;
|
235 |
+
$this->options->totalSteps = 0;
|
236 |
+
|
237 |
+
// Save options
|
238 |
+
$this->saveOptions();
|
239 |
+
|
240 |
+
return $response;
|
241 |
+
}
|
242 |
+
|
243 |
+
/**
|
244 |
+
* Clone Database
|
245 |
+
* @return object
|
246 |
+
*/
|
247 |
+
// public function jobDatabase() {
|
248 |
+
// if( is_multisite() ) {
|
249 |
+
// $database = new muDatabase();
|
250 |
+
// } else {
|
251 |
+
// $database = new Database();
|
252 |
+
// }
|
253 |
+
// return $this->handleJobResponse( $database->start(), "directories" );
|
254 |
+
// }
|
255 |
+
|
256 |
+
/**
|
257 |
+
* Clone Database
|
258 |
+
* @return object
|
259 |
+
*/
|
260 |
+
public function jobDatabase() {
|
261 |
+
if( is_multisite() ) {
|
262 |
+
$database = new muDatabase();
|
263 |
+
} else {
|
264 |
+
$database = new Database();
|
265 |
+
}
|
266 |
+
return $this->handleJobResponse( $database->start(), "directories" );
|
267 |
+
}
|
268 |
+
|
269 |
+
/**
|
270 |
+
* Get All Files From Selected Directories Recursively Into a File
|
271 |
+
* @return object
|
272 |
+
*/
|
273 |
+
public function jobDirectories() {
|
274 |
+
if( is_multisite() ) {
|
275 |
+
$directories = new muDirectories();
|
276 |
+
} else {
|
277 |
+
$directories = new Directories();
|
278 |
+
}
|
279 |
+
return $this->handleJobResponse( $directories->start(), "files" );
|
280 |
+
}
|
281 |
+
|
282 |
+
/**
|
283 |
+
* Copy Files
|
284 |
+
* @return object
|
285 |
+
*/
|
286 |
+
public function jobFiles() {
|
287 |
+
if( is_multisite() ) {
|
288 |
+
$files = new muFiles();
|
289 |
+
} else {
|
290 |
+
$files = new Files();
|
291 |
+
}
|
292 |
+
return $this->handleJobResponse( $files->start(), "data" );
|
293 |
+
}
|
294 |
+
|
295 |
+
/**
|
296 |
+
* Replace Data
|
297 |
+
* @return object
|
298 |
+
*/
|
299 |
+
public function jobData() {
|
300 |
+
if( is_multisite() ) {
|
301 |
+
$data = new muData();
|
302 |
+
} else {
|
303 |
+
$data = new Data();
|
304 |
+
}
|
305 |
+
return $this->handleJobResponse( $data->start(), "finish" );
|
306 |
+
}
|
307 |
+
|
308 |
+
/**
|
309 |
+
* Save Clone Data
|
310 |
+
* @return object
|
311 |
+
*/
|
312 |
+
public function jobFinish() {
|
313 |
+
if( is_multisite() ) {
|
314 |
+
$finish = new muFinish();
|
315 |
+
} else {
|
316 |
+
$finish = new Finish();
|
317 |
+
}
|
318 |
+
$finish = new Finish();
|
319 |
+
return $this->handleJobResponse( $finish->start(), '' );
|
320 |
+
}
|
321 |
|
322 |
}
|
@@ -169,8 +169,7 @@ class SystemInfo extends InjectionAware {
|
|
169 |
$output .= $this->info( "File Copy Limit:", isset( $settings->fileLimit ) ? $settings->fileLimit : 'undefined' );
|
170 |
$output .= $this->info( "Batch Size:", isset( $settings->batchSize ) ? $settings->batchSize : 'undefined' );
|
171 |
$output .= $this->info( "CPU Load:", isset( $settings->cpuLoad ) ? $settings->cpuLoad : 'undefined' );
|
172 |
-
$output .= $this->info( "WP in Subdir:",
|
173 |
-
//$output .= $this->info( "Login Custom Link:", isset( $settings->loginSlug ) ? $settings->loginSlug : 'false' );
|
174 |
|
175 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
|
176 |
|
169 |
$output .= $this->info( "File Copy Limit:", isset( $settings->fileLimit ) ? $settings->fileLimit : 'undefined' );
|
170 |
$output .= $this->info( "Batch Size:", isset( $settings->batchSize ) ? $settings->batchSize : 'undefined' );
|
171 |
$output .= $this->info( "CPU Load:", isset( $settings->cpuLoad ) ? $settings->cpuLoad : 'undefined' );
|
172 |
+
$output .= $this->info( "WP in Subdir:", $this->isSubDir() ? 'true' : 'false' );
|
|
|
173 |
|
174 |
$output .= PHP_EOL . PHP_EOL . "-- Available Sites Version < 1.1.6.x" . PHP_EOL . PHP_EOL;
|
175 |
|
@@ -179,16 +179,6 @@ class Settings {
|
|
179 |
->setDefault( (isset( $settings->disableAdminLogin )) ? $settings->disableAdminLogin : null )
|
180 |
);
|
181 |
|
182 |
-
// WordPress in subdirectory
|
183 |
-
$element = new Check(
|
184 |
-
"wpstg_settings[wpSubDirectory]", array('1' => '')
|
185 |
-
);
|
186 |
-
|
187 |
-
$this->form["general"]->add(
|
188 |
-
$element->setLabel( "Wordpress in subdirectory" )
|
189 |
-
->setDefault( (isset( $settings->wpSubDirectory )) ? $settings->wpSubDirectory : null )
|
190 |
-
);
|
191 |
-
|
192 |
// Debug Mode
|
193 |
$element = new Check(
|
194 |
"wpstg_settings[debugMode]", array('1' => '')
|
179 |
->setDefault( (isset( $settings->disableAdminLogin )) ? $settings->disableAdminLogin : null )
|
180 |
);
|
181 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
// Debug Mode
|
183 |
$element = new Check(
|
184 |
"wpstg_settings[debugMode]", array('1' => '')
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/*
|
4 |
+
* We need an empty functions.php to simulate a valid theme
|
5 |
+
*
|
6 |
+
*/
|
7 |
+
|
@@ -5,12 +5,41 @@
|
|
5 |
Plugin URI: https://wp-staging.com
|
6 |
Description: Prevents 3rd party plugins from being loaded during WP Staging specific operations
|
7 |
Author: René Hermenau
|
8 |
-
Version: 1.
|
9 |
Author URI: https://wp-staging.com
|
10 |
Credit: Original version is made by Delicious Brains (WP Migrate DB). Thank you guys!
|
11 |
*/
|
12 |
|
|
|
|
|
|
|
|
|
|
|
13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
14 |
|
15 |
/**
|
16 |
* remove all plugins except wp-staging and wp-staging-pro from blog-active plugins
|
@@ -27,18 +56,54 @@ function wpstg_exclude_plugins( $plugins ) {
|
|
27 |
if( !wpstg_is_compatibility_mode_request() ) {
|
28 |
return $plugins;
|
29 |
}
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
}
|
35 |
-
unset( $plugins[$key] );
|
36 |
}
|
|
|
|
|
37 |
|
38 |
return $plugins;
|
39 |
}
|
|
|
40 |
add_filter( 'option_active_plugins', 'wpstg_exclude_plugins' );
|
41 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
42 |
|
43 |
/**
|
44 |
* remove all plugins except wp-staging and wp-staging-pro from network-active plugins
|
@@ -56,16 +121,17 @@ function wpstg_exclude_site_plugins( $plugins ) {
|
|
56 |
return $plugins;
|
57 |
}
|
58 |
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
}
|
64 |
-
unset( $plugins[$plugin] );
|
65 |
}
|
|
|
|
|
66 |
|
67 |
return $plugins;
|
68 |
}
|
|
|
69 |
add_filter( 'site_option_active_sitewide_plugins', 'wpstg_exclude_site_plugins' );
|
70 |
|
71 |
/**
|
@@ -74,6 +140,12 @@ add_filter( 'site_option_active_sitewide_plugins', 'wpstg_exclude_site_plugins'
|
|
74 |
* @return bool
|
75 |
*/
|
76 |
function wpstg_is_compatibility_mode_request() {
|
|
|
|
|
|
|
|
|
|
|
|
|
77 |
if( !defined( 'DOING_AJAX' ) ||
|
78 |
!DOING_AJAX ||
|
79 |
!isset( $_POST['action'] ) ||
|
@@ -82,6 +154,7 @@ function wpstg_is_compatibility_mode_request() {
|
|
82 |
|
83 |
return false;
|
84 |
}
|
|
|
85 |
return true;
|
86 |
}
|
87 |
|
@@ -117,4 +190,5 @@ function wpstg_tgmpa_compatibility() {
|
|
117 |
}
|
118 |
}
|
119 |
}
|
120 |
-
|
|
5 |
Plugin URI: https://wp-staging.com
|
6 |
Description: Prevents 3rd party plugins from being loaded during WP Staging specific operations
|
7 |
Author: René Hermenau
|
8 |
+
Version: 1.1
|
9 |
Author URI: https://wp-staging.com
|
10 |
Credit: Original version is made by Delicious Brains (WP Migrate DB). Thank you guys!
|
11 |
*/
|
12 |
|
13 |
+
/**
|
14 |
+
* Get plugins dir
|
15 |
+
* @return string
|
16 |
+
*/
|
17 |
+
function wpstg_get_plugins_dir() {
|
18 |
|
19 |
+
if( defined( 'WP_PLUGIN_DIR' ) ) {
|
20 |
+
$pluginsDir = trailingslashit( WP_PLUGIN_DIR );
|
21 |
+
} else if( defined( 'WP_CONTENT_DIR' ) ) {
|
22 |
+
$pluginsDir = trailingslashit( WP_CONTENT_DIR ) . 'plugins/';
|
23 |
+
}
|
24 |
+
return $pluginsDir;
|
25 |
+
}
|
26 |
+
|
27 |
+
/*
|
28 |
+
* Check if optimizer is enabled
|
29 |
+
* @return bool false if it's disabled
|
30 |
+
*
|
31 |
+
*/
|
32 |
+
|
33 |
+
function wpstg_is_enabled_optimizer() {
|
34 |
+
$status = ( object ) get_option( 'wpstg_settings' );
|
35 |
+
|
36 |
+
if( $status && isset( $status->optimizer ) && $status->optimizer == 1 ) {
|
37 |
+
return true;
|
38 |
+
}
|
39 |
+
// Activate the Optimizer all the times.
|
40 |
+
// Until now we never had any issue with the Optimizer so its default state is activated
|
41 |
+
return true;
|
42 |
+
}
|
43 |
|
44 |
/**
|
45 |
* remove all plugins except wp-staging and wp-staging-pro from blog-active plugins
|
56 |
if( !wpstg_is_compatibility_mode_request() ) {
|
57 |
return $plugins;
|
58 |
}
|
59 |
+
|
60 |
+
foreach ( $plugins as $key => $plugin ) {
|
61 |
+
if( false !== strpos( $plugin, 'wp-staging' ) ) {
|
62 |
+
continue;
|
|
|
|
|
63 |
}
|
64 |
+
unset( $plugins[$key] );
|
65 |
+
}
|
66 |
|
67 |
return $plugins;
|
68 |
}
|
69 |
+
|
70 |
add_filter( 'option_active_plugins', 'wpstg_exclude_plugins' );
|
71 |
|
72 |
+
/**
|
73 |
+
*
|
74 |
+
* Disables the theme during WP Staging AJAX requests
|
75 |
+
*
|
76 |
+
*
|
77 |
+
* @param $dir
|
78 |
+
*
|
79 |
+
* @return string
|
80 |
+
*/
|
81 |
+
function wpstg_disable_theme( $dir ) {
|
82 |
+
$enableTheme = apply_filters( 'wpstg_optimizer_enable_theme', false );
|
83 |
+
|
84 |
+
if( wpstg_is_compatibility_mode_request() && false === $enableTheme ) {
|
85 |
+
$wpstgRootPro = wpstg_get_plugins_dir() . 'wp-staging-pro';
|
86 |
+
$wpstgRoot = wpstg_get_plugins_dir() . 'wp-staging';
|
87 |
+
|
88 |
+
$file = DIRECTORY_SEPARATOR . 'apps' . DIRECTORY_SEPARATOR . 'Backend' . DIRECTORY_SEPARATOR . 'Optimizer' . DIRECTORY_SEPARATOR . 'blank-theme' . DIRECTORY_SEPARATOR . 'functions.php';
|
89 |
+
$theme = DIRECTORY_SEPARATOR . 'apps' . DIRECTORY_SEPARATOR . 'Backend' . DIRECTORY_SEPARATOR . 'Optimizer' . DIRECTORY_SEPARATOR . 'blank-theme';
|
90 |
+
|
91 |
+
|
92 |
+
if( file_exists( $wpstgRoot . $file ) ) {
|
93 |
+
return $wpstgRoot . $theme;
|
94 |
+
} elseif( file_exists( $wpstgRootPro . $file ) ) {
|
95 |
+
return $wpstgRootPro . $theme;
|
96 |
+
} else {
|
97 |
+
return '';
|
98 |
+
}
|
99 |
+
return $themeDir;
|
100 |
+
}
|
101 |
+
|
102 |
+
return $dir;
|
103 |
+
}
|
104 |
+
|
105 |
+
add_filter( 'stylesheet_directory', 'wpstg_disable_theme' );
|
106 |
+
add_filter( 'template_directory', 'wpstg_disable_theme' );
|
107 |
|
108 |
/**
|
109 |
* remove all plugins except wp-staging and wp-staging-pro from network-active plugins
|
121 |
return $plugins;
|
122 |
}
|
123 |
|
124 |
+
|
125 |
+
foreach ( array_keys( $plugins ) as $plugin ) {
|
126 |
+
if( false !== strpos( $plugin, 'wp-staging' ) || !isset( $blacklist_plugins[$plugin] ) ) {
|
127 |
+
continue;
|
|
|
|
|
128 |
}
|
129 |
+
unset( $plugins[$plugin] );
|
130 |
+
}
|
131 |
|
132 |
return $plugins;
|
133 |
}
|
134 |
+
|
135 |
add_filter( 'site_option_active_sitewide_plugins', 'wpstg_exclude_site_plugins' );
|
136 |
|
137 |
/**
|
140 |
* @return bool
|
141 |
*/
|
142 |
function wpstg_is_compatibility_mode_request() {
|
143 |
+
|
144 |
+
// Optimizer not enabled
|
145 |
+
if( !wpstg_is_enabled_optimizer() ) {
|
146 |
+
return false;
|
147 |
+
}
|
148 |
+
|
149 |
if( !defined( 'DOING_AJAX' ) ||
|
150 |
!DOING_AJAX ||
|
151 |
!isset( $_POST['action'] ) ||
|
154 |
|
155 |
return false;
|
156 |
}
|
157 |
+
|
158 |
return true;
|
159 |
}
|
160 |
|
190 |
}
|
191 |
}
|
192 |
}
|
193 |
+
|
194 |
+
add_action( 'admin_init', 'wpstg_tgmpa_compatibility', 1 );
|
@@ -11,22 +11,22 @@
|
|
11 |
/* CSS for Tabs */
|
12 |
|
13 |
#tab_container ul {
|
14 |
-
/*height: 200px;*/
|
15 |
-
list-style: none;
|
16 |
-
margin: 0;
|
17 |
-
padding: 0;
|
18 |
-
background: #f1f1f1;
|
19 |
-
float: left;
|
20 |
-
/*list-style-type: square;*/
|
21 |
}
|
22 |
|
23 |
#tab_container ul li:first-child.selected-tab {
|
24 |
-
border-top: none;
|
25 |
}
|
26 |
|
27 |
#tab_container ul li a.selected-tab {
|
28 |
-
font-weight: bold;
|
29 |
-
text-decoration: none;
|
30 |
}
|
31 |
|
32 |
|
@@ -42,7 +42,7 @@ text-decoration: none;
|
|
42 |
|
43 |
|
44 |
#tab_container .row label strong, #tab_container .row strong {
|
45 |
-
font-weight: bold;
|
46 |
}
|
47 |
|
48 |
.wpstg-tabs a {
|
@@ -63,24 +63,24 @@ font-weight: bold;
|
|
63 |
*/
|
64 |
|
65 |
#tab_container .panel-container {
|
66 |
-
background: #FFF;
|
67 |
-
padding:0 20px 20px 20px;
|
68 |
-
overflow:auto;
|
69 |
}
|
70 |
|
71 |
#tab_container .form-table th {
|
72 |
-
vertical-align: top;
|
73 |
-
text-align: left;
|
74 |
-
padding: 20px 10px 20px 0;
|
75 |
-
line-height: 1.3;
|
76 |
-
font-weight: bold;
|
77 |
-
font-size: 14px;
|
78 |
-
color:#484848;
|
79 |
-
width: 30%;
|
80 |
}
|
81 |
|
82 |
#tab_container .form-table tr {
|
83 |
-
|
84 |
}
|
85 |
|
86 |
#tab_container span.description{
|
@@ -104,7 +104,7 @@ width: 30%;
|
|
104 |
width:100%;
|
105 |
}
|
106 |
#tab_container span.description{
|
107 |
-
|
108 |
}
|
109 |
#tab_container .form-table tr > th, #tab_container .form-table tr > td {
|
110 |
padding:10px;
|
@@ -112,23 +112,23 @@ width: 30%;
|
|
112 |
}
|
113 |
|
114 |
#tab_container ul li {
|
115 |
-
margin-bottom:0;
|
116 |
}
|
117 |
|
118 |
#tab_container ul li a {
|
119 |
-
display: block;
|
120 |
-
padding:10px 4px 10px 14px;
|
121 |
-
border-width: 1px 0;
|
122 |
-
border-style: solid;
|
123 |
-
border-top-color:white;
|
124 |
-
border-bottom-color:#e7e7e7;
|
125 |
-
text-decoration: none;
|
126 |
-
color: #0097DF;
|
127 |
-
font-weight: bold;
|
128 |
}
|
129 |
#tab_container ul li a:hover {
|
130 |
-
background-color: #e5e5e5;
|
131 |
-
color:#777777;
|
132 |
}
|
133 |
|
134 |
|
@@ -166,37 +166,37 @@ color:#777777;
|
|
166 |
}
|
167 |
|
168 |
#mashtabcontainer ul .active {
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
}
|
173 |
|
174 |
#mashtabcontainer ul .active:hover {
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
}
|
179 |
|
180 |
#mashtabcontainer ul li a {
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
}
|
185 |
|
186 |
#mashtabcontainer .mashtab-container {
|
187 |
-
|
188 |
}
|
189 |
|
190 |
/* Cloning workflow */
|
191 |
#wpstg-clonepage-wrapper {
|
192 |
-
|
193 |
-
|
194 |
}
|
195 |
|
196 |
@media screen and (min-width:1090px){
|
197 |
#wpstg-clonepage-wrapper {
|
198 |
float: left;
|
199 |
-
|
200 |
/*width: 690px;*/
|
201 |
}
|
202 |
.wpstg-sidebar{
|
@@ -207,42 +207,42 @@ color:#777777;
|
|
207 |
}
|
208 |
|
209 |
.wpstg-sidebar{
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
|
217 |
#wpstg-steps {
|
218 |
margin-top:30px;
|
219 |
}
|
220 |
|
221 |
#wpstg-steps li {
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
}
|
227 |
|
228 |
|
229 |
.wpstg-step-num {
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
}
|
238 |
|
239 |
.wpstg-current-step {
|
240 |
-
|
241 |
}
|
242 |
|
243 |
.wpstg-current-step .wpstg-step-num {
|
244 |
-
|
245 |
-
|
246 |
}
|
247 |
|
248 |
.wpstg-clone {
|
@@ -257,160 +257,164 @@ color:#777777;
|
|
257 |
}
|
258 |
|
259 |
.wpstg-clone.active {
|
260 |
-
|
261 |
}
|
262 |
|
263 |
.wpstg-clone-title {
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
}
|
271 |
|
272 |
.wpstg-clone-action {
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
}
|
282 |
|
283 |
.wpstg-remove-clone:hover {
|
284 |
-
|
285 |
}
|
286 |
|
287 |
.wpstg-clone-action:last-child {
|
288 |
-
|
289 |
}
|
290 |
|
291 |
.wpstg-clone:hover .wpstg-clone-action {
|
292 |
-
|
293 |
}
|
294 |
|
295 |
#wpstg-show-error-details:focus,
|
296 |
#wpstg-workflow .wpstg-clone-action {
|
297 |
-
|
298 |
-
|
299 |
}
|
300 |
|
301 |
.wpstg-link-btn {
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
}
|
310 |
|
311 |
.wpstg-link-btn:hover,
|
312 |
.wpstg-link-btn:focus {
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
}
|
317 |
|
318 |
#wpstg-workflow .wpstg-link-btn:active {
|
319 |
-
|
320 |
}
|
321 |
|
322 |
.wpstg-link-btn[disabled] {
|
323 |
-
|
324 |
-
|
325 |
}
|
326 |
|
327 |
#wpstg-cancel-cloning, #wpstg-cancel-cloning-update {
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
}
|
332 |
|
333 |
#wpstg-cancel-cloning.success, #wpstg-cancel-cloning.success {
|
334 |
-
|
335 |
-
|
336 |
}
|
337 |
|
338 |
#wpstg-error-wrapper,
|
339 |
#wpstg-error-details {
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
}
|
345 |
|
346 |
#wpstg-show-error-details {
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
}
|
353 |
|
354 |
#wpstg-show-error-details:hover {
|
355 |
-
|
356 |
}
|
357 |
|
358 |
#wpstg-error-details {
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
}
|
363 |
|
364 |
#wpstg-home-link,
|
365 |
#wpstg-try-again {
|
366 |
-
|
367 |
}
|
368 |
|
369 |
|
370 |
#wpstg-loader {
|
371 |
-
|
372 |
-
|
373 |
}
|
374 |
|
375 |
#wpstg-loader.wpstg-finished {
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
|
|
|
|
|
|
|
|
382 |
}
|
383 |
.wpstg-loader {
|
384 |
-
|
385 |
-
|
386 |
}
|
387 |
|
388 |
.wpstg-loader.wpstg-finished {
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
}
|
396 |
|
397 |
#wpstg-workflow {
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
padding-right: 20px;
|
408 |
}
|
409 |
|
410 |
#wpstg-sidebar {
|
411 |
float: left;
|
412 |
max-width: 400px;
|
413 |
display: block;
|
|
|
414 |
}
|
415 |
|
416 |
@media screen and (max-width:1150px){
|
@@ -421,194 +425,194 @@ color:#777777;
|
|
421 |
|
422 |
#wpstg-workflow.loading::after,
|
423 |
#wpstg-removing-clone.loading::after {
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
431 |
-
|
432 |
-
|
433 |
-
|
434 |
-
|
435 |
-
|
436 |
}
|
437 |
|
438 |
#wpstg-removing-clone.loading::after {
|
439 |
-
|
440 |
}
|
441 |
|
442 |
#wpstg-existing-clones,
|
443 |
#wpstg-removing-clone {
|
444 |
-
|
445 |
}
|
446 |
|
447 |
.wpstg-progress-bar {
|
448 |
-
|
449 |
-
|
450 |
-
|
451 |
-
|
452 |
}
|
453 |
|
454 |
.wpstg-progress {
|
455 |
float:left;
|
456 |
-
|
457 |
-
|
458 |
-
|
459 |
-
|
460 |
-
|
461 |
-
|
462 |
-
|
463 |
}
|
464 |
.wpstg-progress-files {
|
465 |
-
|
466 |
-
|
467 |
-
|
468 |
-
|
469 |
-
|
470 |
-
|
471 |
-
|
472 |
}
|
473 |
|
474 |
#wpstg-new-clone-id.wpstg-error-input,
|
475 |
#wpstg-clone-path.wpstg-error-input {
|
476 |
-
|
477 |
-
|
478 |
}
|
479 |
|
480 |
#wpstg-clone-path {
|
481 |
-
|
482 |
-
|
483 |
}
|
484 |
|
485 |
.wpstg-error-msg {
|
486 |
-
|
487 |
}
|
488 |
|
489 |
#wpstg-clone-id-error {
|
490 |
-
|
491 |
-
|
492 |
-
|
493 |
}
|
494 |
|
495 |
#wpstg-start-cloning + .wpstg-error-msg {
|
496 |
-
|
497 |
-
|
498 |
}
|
499 |
|
500 |
.wpstg-size-info {
|
501 |
-
|
502 |
-
|
503 |
-
|
504 |
-
|
505 |
}
|
506 |
|
507 |
.wpstg-db-table .wpstg-size-info {
|
508 |
-
|
509 |
}
|
510 |
|
511 |
#wpstg-workflow #wpstg-start-cloning {
|
512 |
-
|
513 |
-
|
514 |
-
|
515 |
-
|
516 |
}
|
517 |
|
518 |
/* Tabs */
|
519 |
.wpstg-tabs-wrapper {
|
520 |
-
|
521 |
-
|
522 |
}
|
523 |
|
524 |
#wpstg-path-wrapper {
|
525 |
-
|
526 |
-
|
527 |
-
|
528 |
}
|
529 |
|
530 |
.wpstg-tabs-wrapper {
|
531 |
-
|
532 |
-
|
533 |
-
|
534 |
}
|
535 |
|
536 |
.wpstg-tab-section {
|
537 |
-
|
538 |
-
|
539 |
-
|
540 |
-
|
541 |
-
|
542 |
}
|
543 |
|
544 |
.wpstg-tab-section::after {
|
545 |
-
|
546 |
-
|
547 |
-
|
548 |
}
|
549 |
|
550 |
.wpstg-tab-header {
|
551 |
-
|
552 |
-
|
553 |
-
|
554 |
-
|
555 |
-
|
556 |
-
|
557 |
-
|
558 |
-
|
559 |
-
|
560 |
}
|
561 |
|
562 |
.wpstg-tab-triangle {
|
563 |
-
|
564 |
-
|
565 |
-
|
566 |
}
|
567 |
|
568 |
.wpstg-tab-header:focus {
|
569 |
-
|
570 |
-
|
571 |
-
|
572 |
}
|
573 |
|
574 |
#wpstg-large-files {
|
575 |
-
|
576 |
-
|
577 |
-
|
578 |
-
|
579 |
-
|
580 |
-
|
581 |
-
|
582 |
}
|
583 |
|
584 |
#wpstg-large-files h3 {
|
585 |
-
|
586 |
-
|
587 |
-
|
588 |
-
|
589 |
-
|
590 |
-
|
591 |
}
|
592 |
|
593 |
/* tmp */
|
594 |
.wpstg-subdir {
|
595 |
-
|
596 |
-
|
597 |
}
|
598 |
.wpstg-subdir.wpstg-push {
|
599 |
-
|
600 |
-
|
601 |
}
|
602 |
|
603 |
.wpstg-dir a.disabled {
|
604 |
-
|
605 |
-
|
606 |
-
|
607 |
}
|
608 |
|
609 |
.wpstg-check-subdirs {
|
610 |
-
|
611 |
-
|
612 |
}
|
613 |
|
614 |
.wpstg-notice-alert{
|
@@ -653,9 +657,9 @@ color:#777777;
|
|
653 |
}
|
654 |
|
655 |
#wpstg-remove-cloning {
|
656 |
-
|
657 |
-
|
658 |
-
|
659 |
}
|
660 |
|
661 |
#wpstg-success-notice{
|
@@ -676,11 +680,11 @@ color:#777777;
|
|
676 |
}
|
677 |
|
678 |
.form-table .col-title label {
|
679 |
-
|
680 |
}
|
681 |
|
682 |
.form-table td:first-child {
|
683 |
-
|
684 |
}
|
685 |
|
686 |
|
@@ -957,6 +961,7 @@ color:#777777;
|
|
957 |
|
958 |
#wpstg-external-db th {
|
959 |
text-align: left;
|
|
|
960 |
}
|
961 |
|
962 |
#wpstg-db-connect{
|
@@ -984,9 +989,3 @@ color:#777777;
|
|
984 |
background-color: #f2dede;
|
985 |
border-color: #ebccd1;
|
986 |
}
|
987 |
-
|
988 |
-
#wpstg-external-db tr th{
|
989 |
-
font-weight:500;
|
990 |
-
color:grey;
|
991 |
-
opacity: 0.8;
|
992 |
-
}
|
11 |
/* CSS for Tabs */
|
12 |
|
13 |
#tab_container ul {
|
14 |
+
/*height: 200px;*/
|
15 |
+
list-style: none;
|
16 |
+
margin: 0;
|
17 |
+
padding: 0;
|
18 |
+
background: #f1f1f1;
|
19 |
+
float: left;
|
20 |
+
/*list-style-type: square;*/
|
21 |
}
|
22 |
|
23 |
#tab_container ul li:first-child.selected-tab {
|
24 |
+
border-top: none;
|
25 |
}
|
26 |
|
27 |
#tab_container ul li a.selected-tab {
|
28 |
+
font-weight: bold;
|
29 |
+
text-decoration: none;
|
30 |
}
|
31 |
|
32 |
|
42 |
|
43 |
|
44 |
#tab_container .row label strong, #tab_container .row strong {
|
45 |
+
font-weight: bold;
|
46 |
}
|
47 |
|
48 |
.wpstg-tabs a {
|
63 |
*/
|
64 |
|
65 |
#tab_container .panel-container {
|
66 |
+
background: #FFF;
|
67 |
+
padding:0 20px 20px 20px;
|
68 |
+
overflow:auto;
|
69 |
}
|
70 |
|
71 |
#tab_container .form-table th {
|
72 |
+
vertical-align: top;
|
73 |
+
text-align: left;
|
74 |
+
padding: 20px 10px 20px 0;
|
75 |
+
line-height: 1.3;
|
76 |
+
font-weight: bold;
|
77 |
+
font-size: 14px;
|
78 |
+
color:#484848;
|
79 |
+
width: 30%;
|
80 |
}
|
81 |
|
82 |
#tab_container .form-table tr {
|
83 |
+
border-bottom: 1px solid #E7E7E7;
|
84 |
}
|
85 |
|
86 |
#tab_container span.description{
|
104 |
width:100%;
|
105 |
}
|
106 |
#tab_container span.description{
|
107 |
+
font-size: 14px;
|
108 |
}
|
109 |
#tab_container .form-table tr > th, #tab_container .form-table tr > td {
|
110 |
padding:10px;
|
112 |
}
|
113 |
|
114 |
#tab_container ul li {
|
115 |
+
margin-bottom:0;
|
116 |
}
|
117 |
|
118 |
#tab_container ul li a {
|
119 |
+
display: block;
|
120 |
+
padding:10px 4px 10px 14px;
|
121 |
+
border-width: 1px 0;
|
122 |
+
border-style: solid;
|
123 |
+
border-top-color:white;
|
124 |
+
border-bottom-color:#e7e7e7;
|
125 |
+
text-decoration: none;
|
126 |
+
color: #0097DF;
|
127 |
+
font-weight: bold;
|
128 |
}
|
129 |
#tab_container ul li a:hover {
|
130 |
+
background-color: #e5e5e5;
|
131 |
+
color:#777777;
|
132 |
}
|
133 |
|
134 |
|
166 |
}
|
167 |
|
168 |
#mashtabcontainer ul .active {
|
169 |
+
background-color: #00adef;
|
170 |
+
color: white;
|
171 |
+
border-bottom-color: #0098D2;
|
172 |
}
|
173 |
|
174 |
#mashtabcontainer ul .active:hover {
|
175 |
+
background-color: #00A4E2;
|
176 |
+
color: white;
|
177 |
+
border-bottom-color: #0098D2;
|
178 |
}
|
179 |
|
180 |
#mashtabcontainer ul li a {
|
181 |
+
padding: 10px 14px 10px 14px;
|
182 |
+
background-color: #f3f3f3
|
183 |
+
|
184 |
}
|
185 |
|
186 |
#mashtabcontainer .mashtab-container {
|
187 |
+
border: 0 solid #ececec;
|
188 |
}
|
189 |
|
190 |
/* Cloning workflow */
|
191 |
#wpstg-clonepage-wrapper {
|
192 |
+
margin-bottom: 20px;
|
193 |
+
/*width: 690px; */
|
194 |
}
|
195 |
|
196 |
@media screen and (min-width:1090px){
|
197 |
#wpstg-clonepage-wrapper {
|
198 |
float: left;
|
199 |
+
margin-bottom: 20px;
|
200 |
/*width: 690px;*/
|
201 |
}
|
202 |
.wpstg-sidebar{
|
207 |
}
|
208 |
|
209 |
.wpstg-sidebar{
|
210 |
+
display: none;
|
211 |
+
padding: 10px;
|
212 |
+
border: 1px solid #DFDFDF;
|
213 |
+
max-width: 250px;
|
214 |
+
height: 250px;
|
215 |
+
}
|
216 |
|
217 |
#wpstg-steps {
|
218 |
margin-top:30px;
|
219 |
}
|
220 |
|
221 |
#wpstg-steps li {
|
222 |
+
color: #444;
|
223 |
+
line-height: 20px;
|
224 |
+
padding-right:10px;
|
225 |
+
float:left;
|
226 |
}
|
227 |
|
228 |
|
229 |
.wpstg-step-num {
|
230 |
+
border: 1px solid #444;
|
231 |
+
border-radius: 3px;
|
232 |
+
display: inline-block;
|
233 |
+
width: 20px;
|
234 |
+
height: 20px;
|
235 |
+
text-align: center;
|
236 |
+
margin-right: 5px;
|
237 |
}
|
238 |
|
239 |
.wpstg-current-step {
|
240 |
+
font-weight: bold;
|
241 |
}
|
242 |
|
243 |
.wpstg-current-step .wpstg-step-num {
|
244 |
+
background: #444;
|
245 |
+
color: #eee;
|
246 |
}
|
247 |
|
248 |
.wpstg-clone {
|
257 |
}
|
258 |
|
259 |
.wpstg-clone.active {
|
260 |
+
border-color: #1d94cf;;
|
261 |
}
|
262 |
|
263 |
.wpstg-clone-title {
|
264 |
+
display: inline-block;
|
265 |
+
font-size: 15px;
|
266 |
+
max-width: 130px;
|
267 |
+
text-decoration: none;
|
268 |
+
font-weight: bold;
|
269 |
+
color:#0285AE;
|
270 |
}
|
271 |
|
272 |
.wpstg-clone-action {
|
273 |
+
background: #ffffff;
|
274 |
+
border-left: 1px solid #ccc;
|
275 |
+
color: #bbb;
|
276 |
+
padding: 0 5px;
|
277 |
+
float: right;
|
278 |
+
text-decoration: none;
|
279 |
+
position: relative;
|
280 |
+
transition: color .2s ease-in-out;
|
281 |
}
|
282 |
|
283 |
.wpstg-remove-clone:hover {
|
284 |
+
color: #ef6d6d;
|
285 |
}
|
286 |
|
287 |
.wpstg-clone-action:last-child {
|
288 |
+
border: none;
|
289 |
}
|
290 |
|
291 |
.wpstg-clone:hover .wpstg-clone-action {
|
292 |
+
display: inline-block;
|
293 |
}
|
294 |
|
295 |
#wpstg-show-error-details:focus,
|
296 |
#wpstg-workflow .wpstg-clone-action {
|
297 |
+
outline: none;
|
298 |
+
box-shadow: none;
|
299 |
}
|
300 |
|
301 |
.wpstg-link-btn {
|
302 |
+
background: #45a1c9;
|
303 |
+
color: #fff;
|
304 |
+
display: inline-block;
|
305 |
+
padding: 5px 10px;
|
306 |
+
text-decoration: none;
|
307 |
+
vertical-align: baseline;
|
308 |
+
transition: all .2s ease-in-out;
|
309 |
}
|
310 |
|
311 |
.wpstg-link-btn:hover,
|
312 |
.wpstg-link-btn:focus {
|
313 |
+
color: #fff;
|
314 |
+
outline: none;
|
315 |
+
box-shadow: none;
|
316 |
}
|
317 |
|
318 |
#wpstg-workflow .wpstg-link-btn:active {
|
319 |
+
vertical-align: baseline;
|
320 |
}
|
321 |
|
322 |
.wpstg-link-btn[disabled] {
|
323 |
+
background: #777 !important;
|
324 |
+
pointer-events: none;
|
325 |
}
|
326 |
|
327 |
#wpstg-cancel-cloning, #wpstg-cancel-cloning-update {
|
328 |
+
background: #ff3428;
|
329 |
+
border-color: #e72f24;
|
330 |
+
margin-top: 5px;
|
331 |
}
|
332 |
|
333 |
#wpstg-cancel-cloning.success, #wpstg-cancel-cloning.success {
|
334 |
+
background: #64dd58;
|
335 |
+
border-color: #54bd4a;
|
336 |
}
|
337 |
|
338 |
#wpstg-error-wrapper,
|
339 |
#wpstg-error-details {
|
340 |
+
display:none;
|
341 |
+
padding-top: 10px;
|
342 |
+
font-size: 13px;
|
343 |
+
clear:both;
|
344 |
}
|
345 |
|
346 |
#wpstg-show-error-details {
|
347 |
+
display: inline-block;
|
348 |
+
margin-left: 5px;
|
349 |
+
color: #555;
|
350 |
+
text-decoration: none;
|
351 |
+
transition: color .2s ease-in-out;
|
352 |
}
|
353 |
|
354 |
#wpstg-show-error-details:hover {
|
355 |
+
color: #1d94cf;
|
356 |
}
|
357 |
|
358 |
#wpstg-error-details {
|
359 |
+
border-left: 5px solid #ef6d6d;
|
360 |
+
padding: 10px;
|
361 |
+
width: 500px;
|
362 |
}
|
363 |
|
364 |
#wpstg-home-link,
|
365 |
#wpstg-try-again {
|
366 |
+
display: none;
|
367 |
}
|
368 |
|
369 |
|
370 |
#wpstg-loader {
|
371 |
+
content: url('../img/loading.gif');
|
372 |
+
margin-top:-5px;
|
373 |
}
|
374 |
|
375 |
#wpstg-loader.wpstg-finished {
|
376 |
+
display:block;
|
377 |
+
content:"Finished";
|
378 |
+
background-color:#00c89a;
|
379 |
+
color:white;
|
380 |
+
padding-left:10px;
|
381 |
+
padding-right:10px;
|
382 |
+
padding-top:2px;
|
383 |
+
padding-bottom:2px;
|
384 |
+
margin-top:0px;
|
385 |
+
border-radius: 3px;
|
386 |
}
|
387 |
.wpstg-loader {
|
388 |
+
content: url('../img/loading.gif');
|
389 |
+
margin-top:-5px;
|
390 |
}
|
391 |
|
392 |
.wpstg-loader.wpstg-finished {
|
393 |
+
content:"Finished";
|
394 |
+
background-color:#00c89a;
|
395 |
+
color:white;
|
396 |
+
padding:2px;
|
397 |
+
margin-top:0px;
|
398 |
+
max-width:60px;
|
399 |
}
|
400 |
|
401 |
#wpstg-workflow {
|
402 |
+
max-width: 650px;
|
403 |
+
position: relative;
|
404 |
+
clear:both;
|
405 |
+
padding-top:20px;
|
406 |
+
float:left;
|
407 |
+
min-width: 500px;
|
408 |
+
border-right: 1px solid #DFDFDF;
|
409 |
+
min-height: 380px;
|
410 |
+
padding-right: 20px;
|
|
|
411 |
}
|
412 |
|
413 |
#wpstg-sidebar {
|
414 |
float: left;
|
415 |
max-width: 400px;
|
416 |
display: block;
|
417 |
+
margin-left:10px;
|
418 |
}
|
419 |
|
420 |
@media screen and (max-width:1150px){
|
425 |
|
426 |
#wpstg-workflow.loading::after,
|
427 |
#wpstg-removing-clone.loading::after {
|
428 |
+
background: rgba(255, 255, 255, .7);
|
429 |
+
content: 'Loading... may take a while for huge websites';
|
430 |
+
display: block;
|
431 |
+
width: 100%;
|
432 |
+
height: 100%;
|
433 |
+
font-size: 20px;
|
434 |
+
padding-top: 100px;
|
435 |
+
text-align: center;
|
436 |
+
position: absolute;
|
437 |
+
top: 0;
|
438 |
+
left: 0;
|
439 |
+
z-index: 99;
|
440 |
}
|
441 |
|
442 |
#wpstg-removing-clone.loading::after {
|
443 |
+
content: 'REMOVING' !important;
|
444 |
}
|
445 |
|
446 |
#wpstg-existing-clones,
|
447 |
#wpstg-removing-clone {
|
448 |
+
position: relative;
|
449 |
}
|
450 |
|
451 |
.wpstg-progress-bar {
|
452 |
+
/*max-width: 900px;*/
|
453 |
+
height: 27px;
|
454 |
+
padding: 0;
|
455 |
+
background-color: #d6d8d7;
|
456 |
}
|
457 |
|
458 |
.wpstg-progress {
|
459 |
float:left;
|
460 |
+
background: #3fa5ee;
|
461 |
+
width: 0;
|
462 |
+
height: 100%;
|
463 |
+
transition: width .6s ease;
|
464 |
+
color:white;
|
465 |
+
line-height:25px;
|
466 |
+
text-align:center;
|
467 |
}
|
468 |
.wpstg-progress-files {
|
469 |
+
background: #16b4f0;
|
470 |
+
width: 0;
|
471 |
+
height: 100%;
|
472 |
+
transition: width .6s ease;
|
473 |
+
color:white;
|
474 |
+
line-height:25px;
|
475 |
+
text-align:center;
|
476 |
}
|
477 |
|
478 |
#wpstg-new-clone-id.wpstg-error-input,
|
479 |
#wpstg-clone-path.wpstg-error-input {
|
480 |
+
border: 1px solid #ff4235;
|
481 |
+
box-shadow: 0 0 2px rgba(255, 66, 53, .8);
|
482 |
}
|
483 |
|
484 |
#wpstg-clone-path {
|
485 |
+
margin-left: 10px;
|
486 |
+
width: 350px;
|
487 |
}
|
488 |
|
489 |
.wpstg-error-msg {
|
490 |
+
color: #ff4235;
|
491 |
}
|
492 |
|
493 |
#wpstg-clone-id-error {
|
494 |
+
display: block;
|
495 |
+
text-align: right;
|
496 |
+
margin-right: 90px;
|
497 |
}
|
498 |
|
499 |
#wpstg-start-cloning + .wpstg-error-msg {
|
500 |
+
display: block;
|
501 |
+
margin-top: 5px;
|
502 |
}
|
503 |
|
504 |
.wpstg-size-info {
|
505 |
+
color: #999;
|
506 |
+
font-weight: normal;
|
507 |
+
position: relative;
|
508 |
+
left: 2px;
|
509 |
}
|
510 |
|
511 |
.wpstg-db-table .wpstg-size-info {
|
512 |
+
top: 2px;
|
513 |
}
|
514 |
|
515 |
#wpstg-workflow #wpstg-start-cloning {
|
516 |
+
display: inline-block;
|
517 |
+
margin-left: 5px;
|
518 |
+
font-size: 14px;
|
519 |
+
vertical-align: baseline;
|
520 |
}
|
521 |
|
522 |
/* Tabs */
|
523 |
.wpstg-tabs-wrapper {
|
524 |
+
max-width: 640px;
|
525 |
+
margin: 10px 0;
|
526 |
}
|
527 |
|
528 |
#wpstg-path-wrapper {
|
529 |
+
border-bottom: 2px dashed #ccc;
|
530 |
+
padding-bottom: 10px;
|
531 |
+
margin-bottom: 10px;
|
532 |
}
|
533 |
|
534 |
.wpstg-tabs-wrapper {
|
535 |
+
border: 1px solid #ddd;
|
536 |
+
border-right: none;
|
537 |
+
border-left: none;
|
538 |
}
|
539 |
|
540 |
.wpstg-tab-section {
|
541 |
+
border: 1px solid #ddd;
|
542 |
+
border-right: none;
|
543 |
+
border-left: none;
|
544 |
+
display: none;
|
545 |
+
padding: 20px;
|
546 |
}
|
547 |
|
548 |
.wpstg-tab-section::after {
|
549 |
+
display: block;
|
550 |
+
content: '';
|
551 |
+
clear: both;
|
552 |
}
|
553 |
|
554 |
.wpstg-tab-header {
|
555 |
+
border: 1px solid #ddd;
|
556 |
+
border-right: none;
|
557 |
+
border-left: none;
|
558 |
+
color: #444;
|
559 |
+
font-size: 16px;
|
560 |
+
font-weight: bolder;
|
561 |
+
display: block;
|
562 |
+
padding: 10px;;
|
563 |
+
text-decoration: none;
|
564 |
}
|
565 |
|
566 |
.wpstg-tab-triangle {
|
567 |
+
font-family: arial;
|
568 |
+
display: inline-block;
|
569 |
+
margin-right: 10px;
|
570 |
}
|
571 |
|
572 |
.wpstg-tab-header:focus {
|
573 |
+
color: #444;
|
574 |
+
outline: none;
|
575 |
+
box-shadow: none;
|
576 |
}
|
577 |
|
578 |
#wpstg-large-files {
|
579 |
+
display:none;
|
580 |
+
border: 1px dashed #ccc;
|
581 |
+
/*float: right;*/
|
582 |
+
padding: 10px 10px 10px;
|
583 |
+
margin-top:20px;
|
584 |
+
position: relative;
|
585 |
+
font-size:12px;
|
586 |
}
|
587 |
|
588 |
#wpstg-large-files h3 {
|
589 |
+
background: #fff;
|
590 |
+
margin: 0;
|
591 |
+
padding: 0 5px;
|
592 |
+
position: absolute;
|
593 |
+
top: -10px;
|
594 |
+
left: 5px;
|
595 |
}
|
596 |
|
597 |
/* tmp */
|
598 |
.wpstg-subdir {
|
599 |
+
display: none;
|
600 |
+
margin-left: 20px;
|
601 |
}
|
602 |
.wpstg-subdir.wpstg-push {
|
603 |
+
display: block;
|
604 |
+
margin-left: 20px;
|
605 |
}
|
606 |
|
607 |
.wpstg-dir a.disabled {
|
608 |
+
color: #888;
|
609 |
+
cursor: default;
|
610 |
+
text-decoration: none;
|
611 |
}
|
612 |
|
613 |
.wpstg-check-subdirs {
|
614 |
+
display: inline-block;
|
615 |
+
margin-left: 10px;
|
616 |
}
|
617 |
|
618 |
.wpstg-notice-alert{
|
657 |
}
|
658 |
|
659 |
#wpstg-remove-cloning {
|
660 |
+
background: #ff3428;
|
661 |
+
border-color: #e72f24;
|
662 |
+
margin-top: 5px;
|
663 |
}
|
664 |
|
665 |
#wpstg-success-notice{
|
680 |
}
|
681 |
|
682 |
.form-table .col-title label {
|
683 |
+
font-weight: 600;
|
684 |
}
|
685 |
|
686 |
.form-table td:first-child {
|
687 |
+
width:30%;
|
688 |
}
|
689 |
|
690 |
|
961 |
|
962 |
#wpstg-external-db th {
|
963 |
text-align: left;
|
964 |
+
width:120px;
|
965 |
}
|
966 |
|
967 |
#wpstg-db-connect{
|
989 |
background-color: #f2dede;
|
990 |
border-color: #ebccd1;
|
991 |
}
|
|
|
|
|
|
|
|
|
|
|
|
@@ -332,10 +332,10 @@ var WPStaging = (function ($)
|
|
332 |
.on("click", ".wpstg-execute-clone", function (e) {
|
333 |
e.preventDefault();
|
334 |
|
335 |
-
if (!confirm("Are you sure you want to update the staging site? All your staging site modifications will be overwritten with the data from the live site. So make sure that your live site is up to date."))
|
336 |
-
{
|
337 |
-
return false;
|
338 |
-
}
|
339 |
|
340 |
var clone = $(this).data("clone");
|
341 |
|
@@ -376,7 +376,7 @@ var WPStaging = (function ($)
|
|
376 |
* @param {String} dataType
|
377 |
* @param {Boolean} showErrors
|
378 |
*/
|
379 |
-
var ajax = function (data, callback, dataType, showErrors)
|
380 |
{
|
381 |
if ("undefined" === typeof (dataType))
|
382 |
{
|
@@ -387,27 +387,39 @@ var WPStaging = (function ($)
|
|
387 |
{
|
388 |
showErrors = true;
|
389 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
390 |
|
391 |
$.ajax({
|
392 |
-
url: ajaxurl,
|
393 |
type: "POST",
|
394 |
dataType: dataType,
|
395 |
cache: false,
|
396 |
data: data,
|
397 |
error: function (xhr, textStatus, errorThrown) {
|
398 |
console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
|
399 |
-
console.log(textStatus);
|
400 |
|
401 |
-
//
|
402 |
-
|
403 |
-
|
404 |
-
|
|
|
|
|
|
|
405 |
|
|
|
406 |
var errorCode = "undefined" === typeof (xhr.status) ? "Unknown" : xhr.status;
|
407 |
-
|
408 |
showError(
|
409 |
"Fatal Error: " + errorCode + " 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) {
|
413 |
if ("function" === typeof (callback))
|
@@ -417,36 +429,50 @@ var WPStaging = (function ($)
|
|
417 |
},
|
418 |
statusCode: {
|
419 |
404: function (data) {
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
},
|
425 |
500: function () {
|
426 |
-
|
427 |
-
|
428 |
-
|
|
|
|
|
|
|
|
|
429 |
},
|
430 |
504: function () {
|
|
|
431 |
showError("Error 504 - 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 |
-
|
433 |
-
obj.status = false;
|
434 |
-
obj.error = 'custom error';
|
435 |
-
return JSON.stringify(obj);
|
436 |
|
437 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
438 |
429: function () {
|
|
|
439 |
showError("Error 429 - 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\ ");
|
440 |
-
var obj = new Object();
|
441 |
-
obj.status = false;
|
442 |
-
obj.error = 'custom error';
|
443 |
-
return JSON.stringify(obj);
|
444 |
-
|
445 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
446 |
}
|
447 |
});
|
448 |
};
|
449 |
|
|
|
450 |
/**
|
451 |
* Next / Previous Step Clicks to Navigate Through Staging Job
|
452 |
*/
|
@@ -464,7 +490,7 @@ var WPStaging = (function ($)
|
|
464 |
|
465 |
if ($this.data("action") === "wpstg_update") {
|
466 |
// Update Clone - confirmed
|
467 |
-
if (!confirm("Are you sure you want to update the staging site with data from the live site? \n\
|
468 |
{
|
469 |
return false;
|
470 |
}
|
@@ -672,7 +698,9 @@ var WPStaging = (function ($)
|
|
672 |
that.data.databasePassword = $("#wpstg_db_password").val();
|
673 |
that.data.databaseDatabase = $("#wpstg_db_database").val();
|
674 |
that.data.databasePrefix = $("#wpstg_db_prefix").val();
|
675 |
-
|
|
|
|
|
676 |
|
677 |
};
|
678 |
|
@@ -998,6 +1026,8 @@ var WPStaging = (function ($)
|
|
998 |
{
|
999 |
return;
|
1000 |
}
|
|
|
|
|
1001 |
|
1002 |
// Start the process
|
1003 |
start();
|
@@ -1019,7 +1049,7 @@ var WPStaging = (function ($)
|
|
1019 |
setTimeout(function () {
|
1020 |
//cloneDatabase();
|
1021 |
processing();
|
1022 |
-
}, wpstg.
|
1023 |
|
1024 |
that.timer('start');
|
1025 |
|
@@ -1051,7 +1081,7 @@ var WPStaging = (function ($)
|
|
1051 |
|
1052 |
WPStaging.ajax(
|
1053 |
{
|
1054 |
-
action: "
|
1055 |
nonce: wpstg.nonce,
|
1056 |
excludedTables: getExcludedTables(),
|
1057 |
includedDirectories: getIncludedDirectories(),
|
@@ -1075,7 +1105,7 @@ var WPStaging = (function ($)
|
|
1075 |
if ("undefined" !== typeof (response.error) && response.error) {
|
1076 |
console.log(response.message);
|
1077 |
showError(
|
1078 |
-
"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."
|
1079 |
);
|
1080 |
|
1081 |
return;
|
@@ -1095,7 +1125,7 @@ var WPStaging = (function ($)
|
|
1095 |
//console.log('continue processing');
|
1096 |
cache.get("#wpstg-loader").show();
|
1097 |
processing();
|
1098 |
-
}, wpstg.
|
1099 |
|
1100 |
} else if (true === response.status && 'finished' !== response.status) {
|
1101 |
//console.log('Processing...');
|
332 |
.on("click", ".wpstg-execute-clone", function (e) {
|
333 |
e.preventDefault();
|
334 |
|
335 |
+
// if (!confirm("Are you sure you want to update the staging site? All your staging site modifications will be overwritten with the data from the live site. So make sure that your live site is up to date."))
|
336 |
+
// {
|
337 |
+
// return false;
|
338 |
+
// }
|
339 |
|
340 |
var clone = $(this).data("clone");
|
341 |
|
376 |
* @param {String} dataType
|
377 |
* @param {Boolean} showErrors
|
378 |
*/
|
379 |
+
var ajax = function (data, callback, dataType, showErrors, tryCount)
|
380 |
{
|
381 |
if ("undefined" === typeof (dataType))
|
382 |
{
|
387 |
{
|
388 |
showErrors = true;
|
389 |
}
|
390 |
+
|
391 |
+
var tryCount = "undefined" === typeof (tryCount) ? 0 : tryCount;
|
392 |
+
|
393 |
+
var retryLimit = 10;
|
394 |
+
|
395 |
+
var retryTimeout = 10000 * tryCount;
|
396 |
|
397 |
$.ajax({
|
398 |
+
url: ajaxurl + '?action=wpstg_processing&_=' + (Date.now() / 1000),
|
399 |
type: "POST",
|
400 |
dataType: dataType,
|
401 |
cache: false,
|
402 |
data: data,
|
403 |
error: function (xhr, textStatus, errorThrown) {
|
404 |
console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
|
|
|
405 |
|
406 |
+
//try again after 10 seconds
|
407 |
+
tryCount++;
|
408 |
+
if (tryCount <= retryLimit) {
|
409 |
+
setTimeout(function () {
|
410 |
+
ajax(data, callback, dataType, showErrors, tryCount);
|
411 |
+
return;
|
412 |
+
}, retryTimeout);
|
413 |
|
414 |
+
} else {
|
415 |
var errorCode = "undefined" === typeof (xhr.status) ? "Unknown" : xhr.status;
|
|
|
416 |
showError(
|
417 |
"Fatal Error: " + errorCode + " 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."
|
418 |
);
|
419 |
+
}
|
420 |
+
|
421 |
+
|
422 |
+
|
423 |
},
|
424 |
success: function (data) {
|
425 |
if ("function" === typeof (callback))
|
429 |
},
|
430 |
statusCode: {
|
431 |
404: function (data) {
|
432 |
+
if (tryCount >= retryLimit) {
|
433 |
+
showError("Error 404 - 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.");
|
434 |
+
}
|
|
|
435 |
},
|
436 |
500: function () {
|
437 |
+
if (tryCount >= retryLimit) {
|
438 |
+
showError("Fatal Error 500 - 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.");
|
439 |
+
}
|
440 |
+
// var obj = new Object();
|
441 |
+
// obj.status = false;
|
442 |
+
// obj.error = 'custom error';
|
443 |
+
// return JSON.stringify(obj);
|
444 |
},
|
445 |
504: function () {
|
446 |
+
if (tryCount > retryLimit) {
|
447 |
showError("Error 504 - 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\ ");
|
448 |
+
}
|
|
|
|
|
|
|
449 |
|
450 |
},
|
451 |
+
502: function () {
|
452 |
+
if (tryCount >= retryLimit) {
|
453 |
+
showError("Error 502 - 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\ ");
|
454 |
+
}
|
455 |
+
},
|
456 |
+
503: function () {
|
457 |
+
if (tryCount >= retryLimit) {
|
458 |
+
showError("Error 503 - 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\ ");
|
459 |
+
}
|
460 |
+
},
|
461 |
429: function () {
|
462 |
+
if (tryCount >= retryLimit) {
|
463 |
showError("Error 429 - 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\ ");
|
|
|
|
|
|
|
|
|
|
|
464 |
}
|
465 |
+
},
|
466 |
+
403: function () {
|
467 |
+
if (tryCount >= retryLimit) {
|
468 |
+
showError("Refresh page or login again! The process should be finished successfully. \n\ ");
|
469 |
+
}
|
470 |
+
}
|
471 |
}
|
472 |
});
|
473 |
};
|
474 |
|
475 |
+
|
476 |
/**
|
477 |
* Next / Previous Step Clicks to Navigate Through Staging Job
|
478 |
*/
|
490 |
|
491 |
if ($this.data("action") === "wpstg_update") {
|
492 |
// Update Clone - confirmed
|
493 |
+
if (!confirm("Are you sure you want to update the staging site with data from the live site? \n\nEnsure to exclude all 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."))
|
494 |
{
|
495 |
return false;
|
496 |
}
|
698 |
that.data.databasePassword = $("#wpstg_db_password").val();
|
699 |
that.data.databaseDatabase = $("#wpstg_db_database").val();
|
700 |
that.data.databasePrefix = $("#wpstg_db_prefix").val();
|
701 |
+
that.data.cloneDir = $("#wpstg_clone_dir").val();
|
702 |
+
that.data.cloneHostname = $("#wpstg_clone_hostname").val();
|
703 |
+
//console.log(that.data);
|
704 |
|
705 |
};
|
706 |
|
1026 |
{
|
1027 |
return;
|
1028 |
}
|
1029 |
+
|
1030 |
+
that.isCancelled = false;
|
1031 |
|
1032 |
// Start the process
|
1033 |
start();
|
1049 |
setTimeout(function () {
|
1050 |
//cloneDatabase();
|
1051 |
processing();
|
1052 |
+
}, wpstg.delayReq);
|
1053 |
|
1054 |
that.timer('start');
|
1055 |
|
1081 |
|
1082 |
WPStaging.ajax(
|
1083 |
{
|
1084 |
+
action: "wpstg_processing",
|
1085 |
nonce: wpstg.nonce,
|
1086 |
excludedTables: getExcludedTables(),
|
1087 |
includedDirectories: getIncludedDirectories(),
|
1105 |
if ("undefined" !== typeof (response.error) && response.error) {
|
1106 |
console.log(response.message);
|
1107 |
showError(
|
1108 |
+
"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."
|
1109 |
);
|
1110 |
|
1111 |
return;
|
1125 |
//console.log('continue processing');
|
1126 |
cache.get("#wpstg-loader").show();
|
1127 |
processing();
|
1128 |
+
}, wpstg.delayReq);
|
1129 |
|
1130 |
} else if (true === response.status && 'finished' !== response.status) {
|
1131 |
//console.log('Processing...');
|
@@ -10,7 +10,7 @@
|
|
10 |
<div class='wpstg-share-button-container'>
|
11 |
<div class='wpstg-share-button wpstg-share-button-twitter' data-share-url="https://wordpress.org/plugins/wp-staging">
|
12 |
<div clas='box'>
|
13 |
-
<a href="https://twitter.com/intent/tweet?button_hashtag=wpstaging&text=Check%20out%20this%20plugin%20for%20creating%20a%20one%
|
14 |
<span class='wpstg-share'><?php echo __('Tweet #wpstaging','wp-staging'); ?></span>
|
15 |
</a>
|
16 |
</div>
|
@@ -24,7 +24,7 @@
|
|
24 |
</div>
|
25 |
<div class="wpstg-share-button wpstg-share-button-facebook" data-share-url="https://wordpress.org/plugins/wp-staging">
|
26 |
<div class="box">
|
27 |
-
<a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%
|
28 |
<span class='wpstg-share'><?php echo __('Share on Facebook','wp-staging'); ?></span>
|
29 |
</a>
|
30 |
</div>
|
10 |
<div class='wpstg-share-button-container'>
|
11 |
<div class='wpstg-share-button wpstg-share-button-twitter' data-share-url="https://wordpress.org/plugins/wp-staging">
|
12 |
<div clas='box'>
|
13 |
+
<a href="https://twitter.com/intent/tweet?button_hashtag=wpstaging&text=Check%20out%20this%20plugin%20for%20creating%20a%20one-click%20WordPress%20testing%20site&via=wpstg" target='_blank'>
|
14 |
<span class='wpstg-share'><?php echo __('Tweet #wpstaging','wp-staging'); ?></span>
|
15 |
</a>
|
16 |
</div>
|
24 |
</div>
|
25 |
<div class="wpstg-share-button wpstg-share-button-facebook" data-share-url="https://wordpress.org/plugins/wp-staging">
|
26 |
<div class="box">
|
27 |
+
<a href="https://www.facebook.com/sharer/sharer.php?u=https%3A%2F%2Fwp-staging.com%2Fwow-cloning-wordpress-websites-has-never-been-easier%2F" target="_blank">
|
28 |
<span class='wpstg-share'><?php echo __('Share on Facebook','wp-staging'); ?></span>
|
29 |
</a>
|
30 |
</div>
|
@@ -0,0 +1,36 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<fieldset disabled style="opacity:0.8;border-top: 1px solid white;margin-top: 20px;">
|
2 |
+
|
3 |
+
|
4 |
+
<p>
|
5 |
+
<strong style="font-size: 14px;"> <?php _e( 'Copy Staging Site to Custom Directory', 'wp-staging' ); ?></strong>
|
6 |
+
<br>
|
7 |
+
<?php _e( 'Path must be writeable by PHP and an absolute path like <code>/www/public_html/dev</code>.', 'wp-staging' ); ?>
|
8 |
+
</p>
|
9 |
+
<table cellspacing="0" id="wpstg-clone-directory">
|
10 |
+
<tbody>
|
11 |
+
<tr><th style="text-align:left;min-width: 120px;">Target Directory: </th>
|
12 |
+
<td> <input readonly style="width:300px;" type="text" name="wpstg_clone_dir" id="wpstg_clone_dir" value="" title="wpstg_clone_dir" placeholder="<?php echo \WPStaging\WPStaging::getWPpath(); ?>" autocapitalize="off"></td>
|
13 |
+
</tr>
|
14 |
+
<tr>
|
15 |
+
<td></td>
|
16 |
+
<td><code>Default: <?php echo \WPStaging\WPStaging::getWPpath(); ?></code></td>
|
17 |
+
</tr>
|
18 |
+
<tr>
|
19 |
+
<td> </td>
|
20 |
+
<td></td>
|
21 |
+
</tr>
|
22 |
+
<tr><th style="text-align:left;min-width:120px;">Target Hostname: </th><td> <input readonly style="width:300px;" type="text" name="wpstg_clone_hostname" id="wpstg_clone_hostname" value="" title="wpstg_clone_hostname" placeholder="<?php echo get_site_url(); ?>" autocapitalize="off">
|
23 |
+
</td>
|
24 |
+
</tr>
|
25 |
+
<tr>
|
26 |
+
<td></td>
|
27 |
+
<td><code>Default: <?php echo get_site_url(); ?></code></td>
|
28 |
+
</tr>
|
29 |
+
</tbody>
|
30 |
+
</table>
|
31 |
+
</fieldset>
|
32 |
+
<p style="font-weight:bold;background-color:#e6e6e6;padding:15px;border-top: 1px solid white;margin-top: 20px;"><?php _e('That\'s a Pro Feature', 'wp-staging'); ?>
|
33 |
+
<br>
|
34 |
+
<a href="https://wp-staging.com/?utm_source=wp-admin&utm_medium=wp-admin&utm_campaign=db-external&utm_term=db-external" target="_blank" class="quads-button green wpstg-button" style="border-radius:3px;font-size: 14px;border: 1px solid white;"><?php _e("Get WP Staging Pro", "wp-staging"); ?></a>
|
35 |
+
</p>
|
36 |
+
|
@@ -1,4 +1,4 @@
|
|
1 |
-
<div class="wpstg-notice-alert">
|
2 |
<h4 style="margin:0">
|
3 |
<?php
|
4 |
_e("Attention: Check carefully if these database tables and files are safe to delete and do not belong to your live site!", "wp-staging")
|
@@ -17,7 +17,7 @@
|
|
17 |
<?php _e('Database Name:', 'wp-staging'); ?>
|
18 |
<span style="background-color:#5b9dd9;color:#fff;padding: 2px;border-radius: 3px;">
|
19 |
<?php
|
20 |
-
$database = empty($clone->databaseDatabase) ? "{$dbname}
|
21 |
echo $database;
|
22 |
?>
|
23 |
</span>
|
1 |
+
<div class="wpstg-notice-alert wpstg-failed">
|
2 |
<h4 style="margin:0">
|
3 |
<?php
|
4 |
_e("Attention: Check carefully if these database tables and files are safe to delete and do not belong to your live site!", "wp-staging")
|
17 |
<?php _e('Database Name:', 'wp-staging'); ?>
|
18 |
<span style="background-color:#5b9dd9;color:#fff;padding: 2px;border-radius: 3px;">
|
19 |
<?php
|
20 |
+
$database = empty($clone->databaseDatabase) ? "{$dbname} / Main Database)" : $clone->databaseDatabase;
|
21 |
echo $database;
|
22 |
?>
|
23 |
</span>
|
@@ -1,6 +1,8 @@
|
|
1 |
<fieldset disabled style="opacity:0.8;">
|
2 |
-
<p
|
3 |
-
|
|
|
|
|
4 |
<table cellspacing="0" id="wpstg-external-db">
|
5 |
<tbody>
|
6 |
<tr><th>Server</th><td><input type="text" name="wpstg_db_server" id="wpstg_db_server" value="" title="wpstg_db_server" placeholder="localhost" autocapitalize="off" readonly>
|
@@ -13,12 +15,8 @@
|
|
13 |
</td></tr>
|
14 |
<tr><th>Database Prefix</th><td><input type="text" name="wpstg_db_prefix" id="wpstg_db_prefix" value="" placeholder="<?php echo $db->prefix; ?>" autocapitalize="off" readonly>
|
15 |
</td></tr>
|
16 |
-
<tr><th><a href="#" id="wpstg-db-connect">Test Database Connection</a></
|
17 |
-
</td></tr>
|
18 |
</tbody>
|
19 |
</table>
|
20 |
</fieldset>
|
21 |
-
|
22 |
-
<br>
|
23 |
-
<a href="https://wp-staging.com/?utm_source=wp-admin&utm_medium=wp-admin&utm_campaign=db-external&utm_term=db-external" target="_blank" class="quads-button green wpstg-button" style="border-radius:2px;font-size: 14px;">Get WP Staging Pro</a>
|
24 |
-
</p>
|
1 |
<fieldset disabled style="opacity:0.8;">
|
2 |
+
<p><strong style="font-size: 14px;">
|
3 |
+
<?php _e('Copy Staging Site to Separate Database', 'wp-staging'); ?></strong>
|
4 |
+
<br><?php _e('Database must be created manually in advance!', 'wp-staging'); ?>
|
5 |
+
</p>
|
6 |
<table cellspacing="0" id="wpstg-external-db">
|
7 |
<tbody>
|
8 |
<tr><th>Server</th><td><input type="text" name="wpstg_db_server" id="wpstg_db_server" value="" title="wpstg_db_server" placeholder="localhost" autocapitalize="off" readonly>
|
15 |
</td></tr>
|
16 |
<tr><th>Database Prefix</th><td><input type="text" name="wpstg_db_prefix" id="wpstg_db_prefix" value="" placeholder="<?php echo $db->prefix; ?>" autocapitalize="off" readonly>
|
17 |
</td></tr>
|
18 |
+
<tr><th></th><td><a href="#" id="wpstg-db-connect">Test Database Connection</a></td></tr>
|
|
|
19 |
</tbody>
|
20 |
</table>
|
21 |
</fieldset>
|
22 |
+
|
|
|
|
|
|
@@ -1,82 +1,80 @@
|
|
1 |
<label id="wpstg-clone-label" for="wpstg-new-clone">
|
2 |
-
<?php echo __('Staging Site Name:', 'wp-staging')?>
|
3 |
-
<input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if
|
4 |
</label>
|
5 |
|
6 |
<span class="wpstg-error-msg" id="wpstg-clone-id-error" style="display:none;">
|
7 |
-
|
8 |
-
|
9 |
-
"<br>
|
10 |
-
"wp-staging"
|
11 |
-
|
|
|
12 |
</span>
|
13 |
|
14 |
<div class="wpstg-tabs-wrapper">
|
15 |
<a href="#" class="wpstg-tab-header active" data-id="#wpstg-scanning-db">
|
16 |
<span class="wpstg-tab-triangle">►</span>
|
17 |
-
|
18 |
</a>
|
19 |
|
20 |
<div class="wpstg-tab-section" id="wpstg-scanning-db">
|
21 |
-
|
22 |
<h4 style="margin:0">
|
23 |
-
<?php
|
24 |
-
|
25 |
echo __(
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
</h4>
|
30 |
<div style="margin-top:10px;margin-bottom:10px;">
|
31 |
<a href="#" class="wpstg-button-unselect button"> None </a>
|
32 |
-
<a href="#" class="wpstg-button-select button"> <?php _e(WPStaging\WPStaging::getTablePrefix(), 'wp-staging'); ?> </a>
|
33 |
</div>
|
34 |
<?php
|
35 |
-
|
36 |
-
|
37 |
-
$attributes
|
38 |
-
$attributes .= in_array($table->name, $options->clonedTables) ? " disabled" : '';
|
39 |
?>
|
40 |
<div class="wpstg-db-table">
|
41 |
<label>
|
42 |
-
<input class="wpstg-db-table-checkboxes" type="checkbox" name="<?php echo $table->name?>" <?php echo $attributes?>>
|
43 |
-
<?php echo $table->name?>
|
44 |
</label>
|
45 |
<span class="wpstg-size-info">
|
46 |
-
|
47 |
-
|
48 |
</div>
|
49 |
<?php endforeach ?>
|
50 |
<div style="margin-top:10px;">
|
51 |
<a href="#" class="wpstg-button-unselect button"> None </a>
|
52 |
-
<a href="#" class="wpstg-button-select button"> <?php _e(WPStaging\WPStaging::getTablePrefix(), 'wp-staging'); ?> </a>
|
53 |
</div>
|
54 |
</div>
|
55 |
|
56 |
<a href="#" class="wpstg-tab-header" data-id="#wpstg-scanning-files">
|
57 |
<span class="wpstg-tab-triangle">►</span>
|
58 |
-
<?php echo __("Files", "wp-staging")?>
|
59 |
</a>
|
60 |
|
61 |
<div class="wpstg-tab-section" id="wpstg-scanning-files">
|
62 |
<h4 style="margin:0">
|
63 |
-
<?php echo __("Select folders to copy. Click on folder name to list subfolders!", "wp-staging")?>
|
64 |
</h4>
|
65 |
|
66 |
-
<?php echo $scan->directoryListing()?>
|
67 |
|
68 |
<h4 style="margin:10px 0 10px 0">
|
69 |
-
<?php echo __("Extra directories to copy", "wp-staging")?>
|
70 |
</h4>
|
71 |
|
72 |
-
<textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:
|
73 |
<p>
|
74 |
<span>
|
75 |
<?php
|
76 |
echo __(
|
77 |
-
|
78 |
-
|
79 |
-
"wp-staging"
|
80 |
)
|
81 |
?>
|
82 |
</span>
|
@@ -85,49 +83,46 @@
|
|
85 |
<p>
|
86 |
<span>
|
87 |
<?php
|
88 |
-
if
|
89 |
-
|
90 |
}
|
91 |
?>
|
92 |
</span>
|
93 |
</p>
|
94 |
</div>
|
95 |
|
96 |
-
<a href="#" class="wpstg-tab-header" data-id="#wpstg-advanced-settings" style="display:
|
97 |
<span class="wpstg-tab-triangle">►</span>
|
98 |
-
<?php echo __("Advanced Settings", "wp-staging"); ?>
|
99 |
</a>
|
100 |
|
101 |
<div class="wpstg-tab-section" id="wpstg-advanced-settings" style="display:none;">
|
102 |
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
|
|
107 |
</div>
|
108 |
|
109 |
</div>
|
110 |
|
111 |
<button type="button" class="wpstg-prev-step-link wpstg-link-btn button-primary wpstg-button">
|
112 |
-
<?php _e("Back", "wp-staging")?>
|
113 |
</button>
|
114 |
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
echo '<button type="button" id="wpstg-start-cloning" class="wpstg-next-step-link wpstg-link-btn button-primary wpstg-button" data-action="'.$action.'">'.$label.'</button>';
|
129 |
-
|
130 |
-
}
|
131 |
-
?>
|
132 |
|
133 |
-
<a href="#" id="wpstg-check-space"><?php _e('Check Disk Space', 'wp-staging'); ?></a>
|
1 |
<label id="wpstg-clone-label" for="wpstg-new-clone">
|
2 |
+
<?php echo __( 'Staging Site Name:', 'wp-staging' ) ?>
|
3 |
+
<input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if( null !== $options->current ) echo " disabled='disabled'" ?>>
|
4 |
</label>
|
5 |
|
6 |
<span class="wpstg-error-msg" id="wpstg-clone-id-error" style="display:none;">
|
7 |
+
<?php
|
8 |
+
echo __(
|
9 |
+
"<br>Probably not enough free disk space to create a staging site. " .
|
10 |
+
"<br> You can continue but its likely that the copying process will fail.", "wp-staging"
|
11 |
+
)
|
12 |
+
?>
|
13 |
</span>
|
14 |
|
15 |
<div class="wpstg-tabs-wrapper">
|
16 |
<a href="#" class="wpstg-tab-header active" data-id="#wpstg-scanning-db">
|
17 |
<span class="wpstg-tab-triangle">►</span>
|
18 |
+
<?php echo __( "DB Tables", "wp-staging" ) ?>
|
19 |
</a>
|
20 |
|
21 |
<div class="wpstg-tab-section" id="wpstg-scanning-db">
|
22 |
+
<?php do_action( "wpstg_scanning_db" ) ?>
|
23 |
<h4 style="margin:0">
|
24 |
+
<?php
|
|
|
25 |
echo __(
|
26 |
+
"Uncheck the tables you do not want to copy. Usually you should select tables with prefix '{$scan->prefix}', only.", "wp-staging"
|
27 |
+
)
|
28 |
+
?>
|
29 |
</h4>
|
30 |
<div style="margin-top:10px;margin-bottom:10px;">
|
31 |
<a href="#" class="wpstg-button-unselect button"> None </a>
|
32 |
+
<a href="#" class="wpstg-button-select button"> <?php _e( WPStaging\WPStaging::getTablePrefix(), 'wp-staging' ); ?> </a>
|
33 |
</div>
|
34 |
<?php
|
35 |
+
foreach ( $options->tables as $table ):
|
36 |
+
$attributes = in_array( $table->name, $options->excludedTables ) ? '' : "checked";
|
37 |
+
$attributes .= in_array( $table->name, $options->clonedTables ) ? " disabled" : '';
|
|
|
38 |
?>
|
39 |
<div class="wpstg-db-table">
|
40 |
<label>
|
41 |
+
<input class="wpstg-db-table-checkboxes" type="checkbox" name="<?php echo $table->name ?>" <?php echo $attributes ?>>
|
42 |
+
<?php echo $table->name ?>
|
43 |
</label>
|
44 |
<span class="wpstg-size-info">
|
45 |
+
<?php echo $scan->formatSize( $table->size ) ?>
|
46 |
+
</span>
|
47 |
</div>
|
48 |
<?php endforeach ?>
|
49 |
<div style="margin-top:10px;">
|
50 |
<a href="#" class="wpstg-button-unselect button"> None </a>
|
51 |
+
<a href="#" class="wpstg-button-select button"> <?php _e( WPStaging\WPStaging::getTablePrefix(), 'wp-staging' ); ?> </a>
|
52 |
</div>
|
53 |
</div>
|
54 |
|
55 |
<a href="#" class="wpstg-tab-header" data-id="#wpstg-scanning-files">
|
56 |
<span class="wpstg-tab-triangle">►</span>
|
57 |
+
<?php echo __( "Files", "wp-staging" ) ?>
|
58 |
</a>
|
59 |
|
60 |
<div class="wpstg-tab-section" id="wpstg-scanning-files">
|
61 |
<h4 style="margin:0">
|
62 |
+
<?php echo __( "Select folders to copy. Click on folder name to list subfolders!", "wp-staging" ) ?>
|
63 |
</h4>
|
64 |
|
65 |
+
<?php echo $scan->directoryListing() ?>
|
66 |
|
67 |
<h4 style="margin:10px 0 10px 0">
|
68 |
+
<?php echo __( "Extra directories to copy", "wp-staging" ) ?>
|
69 |
</h4>
|
70 |
|
71 |
+
<textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:100px;"></textarea>
|
72 |
<p>
|
73 |
<span>
|
74 |
<?php
|
75 |
echo __(
|
76 |
+
"Enter one folder path per line.<br>" .
|
77 |
+
"Folders must start with absolute path: " . $options->root, "wp-staging"
|
|
|
78 |
)
|
79 |
?>
|
80 |
</span>
|
83 |
<p>
|
84 |
<span>
|
85 |
<?php
|
86 |
+
if( isset( $options->clone ) ) {
|
87 |
+
echo __( "All files will be copied to: ", "wp-staging" ) . $options->root . $options->clone;
|
88 |
}
|
89 |
?>
|
90 |
</span>
|
91 |
</p>
|
92 |
</div>
|
93 |
|
94 |
+
<a href="#" class="wpstg-tab-header" data-id="#wpstg-advanced-settings" style="display:block;">
|
95 |
<span class="wpstg-tab-triangle">►</span>
|
96 |
+
<?php echo __( "Advanced Settings / Pro", "wp-staging" ); ?>
|
97 |
</a>
|
98 |
|
99 |
<div class="wpstg-tab-section" id="wpstg-advanced-settings" style="display:none;">
|
100 |
|
101 |
+
<?php
|
102 |
+
require_once (__DIR__ . DIRECTORY_SEPARATOR . 'external-database.php');
|
103 |
+
require_once (__DIR__ . DIRECTORY_SEPARATOR . 'custom-directory.php');
|
104 |
+
?>
|
105 |
+
|
106 |
</div>
|
107 |
|
108 |
</div>
|
109 |
|
110 |
<button type="button" class="wpstg-prev-step-link wpstg-link-btn button-primary wpstg-button">
|
111 |
+
<?php _e( "Back", "wp-staging" ) ?>
|
112 |
</button>
|
113 |
|
114 |
+
<?php
|
115 |
+
if( null !== $options->current ) {
|
116 |
+
$label = __( "Update Clone", "wp-staging" );
|
117 |
+
$action = 'wpstg_update';
|
118 |
+
|
119 |
+
echo '<button type="button" id="wpstg-start-updating" class="wpstg-next-step-link wpstg-link-btn button-primary wpstg-button" data-action="' . $action . '">' . $label . '</button>';
|
120 |
+
} else {
|
121 |
+
$label = __( "Start Cloning", "wp-staging" );
|
122 |
+
$action = 'wpstg_cloning';
|
123 |
+
|
124 |
+
echo '<button type="button" id="wpstg-start-cloning" class="wpstg-next-step-link wpstg-link-btn button-primary wpstg-button" data-action="' . $action . '">' . $label . '</button>';
|
125 |
+
}
|
126 |
+
?>
|
|
|
|
|
|
|
|
|
127 |
|
128 |
+
<a href="#" id="wpstg-check-space"><?php _e( 'Check Free Disk Space', 'wp-staging' ); ?></a>
|
@@ -4,7 +4,7 @@
|
|
4 |
</span>
|
5 |
|
6 |
<span class="wpstg-version">
|
7 |
-
<?php if(
|
8 |
</span>
|
9 |
|
10 |
<div class="wpstg-header">
|
@@ -35,25 +35,25 @@
|
|
35 |
|
36 |
<ul class="nav-tab-wrapper">
|
37 |
<?php
|
38 |
-
$tabs
|
39 |
$activeTab = (isset( $_GET["tab"] ) && array_key_exists( $_GET["tab"], $tabs )) ? $_GET["tab"] : "general";
|
40 |
|
41 |
# Loop through tabs
|
42 |
foreach ( $tabs as $id => $name ):
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
endforeach;
|
58 |
?>
|
59 |
</ul>
|
@@ -66,258 +66,242 @@
|
|
66 |
settings_fields( "wpstg_settings" );
|
67 |
|
68 |
foreach ( $tabs as $id => $name ):
|
69 |
-
|
70 |
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
The higher the value the faster the database copy process.
|
98 |
To find out the highest possible values try a high value like 1.000 or more. If you get timeout issues, lower it
|
99 |
until you get no more errors during copying process.", "wp-staging" ); ?>
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
The higher the value the faster the database search & replace process.
|
118 |
This is a high memory consumptive process. If you get timeouts lower this value!", "wp-staging" ); ?>
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
The higher the value the faster the file copy process.
|
138 |
To find out the highest possible values try a high value like 500 or more. If you get timeout issues, lower it
|
139 |
until you get no more errors during copying process.", "wp-staging" ); ?>
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
Note: Increase this option only if you have a good reason. Files larger than a few megabytes are in 99% of all cases log and backup files which are not needed on a staging site.", "wp-staging" ); ?>
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
The higher the value the faster large files are copied.
|
177 |
To find out the highest possible values try a high one and lower it until
|
178 |
you get no errors during file copy process. Usually this value correlates directly
|
179 |
with the memory consumption of php so make sure that
|
180 |
it does not exceed any php.ini max_memory limits.", "wp-staging" ); ?>
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
increases and it's also possible that staging process gets interrupted because of too many ajax requests
|
198 |
(e.g. <strong>authorization error</strong>).
|
199 |
Using a lower value results in lower cpu load on your server but also slower staging site creation.", "wp-staging" ); ?>
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
<?php echo $form->label( "wpstg_settings[debugMode]" ) ?>
|
245 |
-
<span class="description">
|
246 |
-
<?php _e( "This will enable an extended debug mode which creates additional entries
|
247 |
in <strong>wp-content/uploads/wp-staging/logs/logfile.log</strong>.
|
248 |
Please enable this when we ask you to do so.", "wp-staging" ); ?>
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
This will not remove staging sites files or database tables.", "wp-staging" ); ?>
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
<br>
|
292 |
Warning this may cause timeout problems in big directory / file structures.", "wp-staging" ); ?>
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
<span class="description">
|
305 |
-
<?php //_e( 'Enter the string which links to your login page if you are using a custom login page instead the default WordPress login. <br/><br/><strong>This does not affect already existing staging sites.</strong><br/> You need to create a new staging site if you like to change the login url of a staging site.', 'wp-staging' ); ?>
|
306 |
-
</span>
|
307 |
-
</div>
|
308 |
-
</td>
|
309 |
-
<td>
|
310 |
-
<?php //echo get_home_url() . '/?' . $form->render( "wpstg_settings[loginSlug]" ); ?>
|
311 |
-
</td>
|
312 |
-
</tr>-->
|
313 |
-
</tbody>
|
314 |
-
</table>
|
315 |
-
</div>
|
316 |
-
<?php
|
317 |
endforeach;
|
318 |
// Show submit button any tab but add-ons
|
319 |
if( $activeTab !== "add-ons" ) {
|
320 |
-
|
321 |
}
|
322 |
unset( $tabs );
|
323 |
?>
|
4 |
</span>
|
5 |
|
6 |
<span class="wpstg-version">
|
7 |
+
<?php if( WPStaging\WPStaging::getSlug() === "wp-staging-pro" ) echo "Pro" ?> Version <?php echo \WPStaging\WPStaging::VERSION ?>
|
8 |
</span>
|
9 |
|
10 |
<div class="wpstg-header">
|
35 |
|
36 |
<ul class="nav-tab-wrapper">
|
37 |
<?php
|
38 |
+
$tabs = $this->di->get( "tabs" )->get();
|
39 |
$activeTab = (isset( $_GET["tab"] ) && array_key_exists( $_GET["tab"], $tabs )) ? $_GET["tab"] : "general";
|
40 |
|
41 |
# Loop through tabs
|
42 |
foreach ( $tabs as $id => $name ):
|
43 |
+
$url = esc_url( add_query_arg( array(
|
44 |
+
"settings-updated" => false,
|
45 |
+
"tab" => $id
|
46 |
+
) ) );
|
47 |
|
48 |
+
$activeClass = ($activeTab === $id) ? " nav-tab-active" : '';
|
49 |
+
?>
|
50 |
+
<li>
|
51 |
+
<a href="<?php echo $url ?>" title="<?php echo esc_attr( $name ) ?>" class="nav-tab<?php echo $activeClass ?>">
|
52 |
+
<?php echo esc_html( $name ) ?>
|
53 |
+
</a>
|
54 |
+
</li>
|
55 |
+
<?php
|
56 |
+
unset( $url, $activeClass );
|
57 |
endforeach;
|
58 |
?>
|
59 |
</ul>
|
66 |
settings_fields( "wpstg_settings" );
|
67 |
|
68 |
foreach ( $tabs as $id => $name ):
|
69 |
+
$form = $this->di->get( "forms" )->get( $id );
|
70 |
|
71 |
+
if( null === $form ) {
|
72 |
+
continue;
|
73 |
+
}
|
74 |
+
?>
|
75 |
+
<div id="<?php echo $id ?>__wpstg_header">
|
76 |
+
<table class="form-table">
|
77 |
+
<thead>
|
78 |
+
<tr class="row">
|
79 |
+
<th class="row th" colspan="2">
|
80 |
+
<div class="col-title">
|
81 |
+
<strong><?php echo $name ?></strong>
|
82 |
+
<span class="description"></span>
|
83 |
+
</div>
|
84 |
+
</th>
|
85 |
+
</tr>
|
86 |
+
</thead>
|
87 |
|
88 |
+
<tbody>
|
89 |
+
<tr class="row">
|
90 |
+
<td class="row th">
|
91 |
+
<div class="col-title">
|
92 |
+
<?php
|
93 |
+
echo $form->label( "wpstg_settings[queryLimit]" )
|
94 |
+
?>
|
95 |
+
<span class="description">
|
96 |
+
<?php _e( "Number of DB rows, that are copied within one ajax query.
|
97 |
The higher the value the faster the database copy process.
|
98 |
To find out the highest possible values try a high value like 1.000 or more. If you get timeout issues, lower it
|
99 |
until you get no more errors during copying process.", "wp-staging" ); ?>
|
100 |
+
<br>
|
101 |
+
<strong> Default: 10000 </strong>
|
102 |
+
</span>
|
103 |
+
</div>
|
104 |
+
</td>
|
105 |
+
<td>
|
106 |
+
<?php echo $form->render( "wpstg_settings[queryLimit]" ) ?>
|
107 |
+
</td>
|
108 |
+
</tr>
|
109 |
+
<tr class="row">
|
110 |
+
<td class="row th">
|
111 |
+
<div class="col-title">
|
112 |
+
<?php
|
113 |
+
echo $form->label( "wpstg_settings[querySRLimit]" )
|
114 |
+
?>
|
115 |
+
<span class="description">
|
116 |
+
<?php _e( "Number of DB rows, that are processed within one ajax query.
|
117 |
The higher the value the faster the database search & replace process.
|
118 |
This is a high memory consumptive process. If you get timeouts lower this value!", "wp-staging" ); ?>
|
119 |
+
<br>
|
120 |
+
<strong> Default: 5000 </strong>
|
121 |
+
</span>
|
122 |
+
</div>
|
123 |
+
</td>
|
124 |
+
<td>
|
125 |
+
<?php echo $form->render( "wpstg_settings[querySRLimit]" ) ?>
|
126 |
+
</td>
|
127 |
+
</tr>
|
128 |
|
129 |
+
<tr class="row">
|
130 |
+
<td class="row th">
|
131 |
+
<div class="col-title">
|
132 |
+
<?php
|
133 |
+
echo $form->label( "wpstg_settings[fileLimit]" )
|
134 |
+
?>
|
135 |
+
<span class="description">
|
136 |
+
<?php _e( "Number of files to copy that will be copied within one ajax request.
|
137 |
The higher the value the faster the file copy process.
|
138 |
To find out the highest possible values try a high value like 500 or more. If you get timeout issues, lower it
|
139 |
until you get no more errors during copying process.", "wp-staging" ); ?>
|
140 |
+
<br>
|
141 |
+
<br>
|
142 |
+
<?php _e( "<strong>Important:</strong> If CPU Load Priority is <strong>Low</strong> set a file copy limit value of 50 or higher! Otherwise file copying process takes a lot of time.", "wp-staging" ); ?>
|
143 |
+
<br>
|
144 |
+
<br>
|
145 |
+
<strong> Default: 1 </strong>
|
146 |
+
</span>
|
147 |
+
</div>
|
148 |
+
</td>
|
149 |
+
<td>
|
150 |
+
<?php echo $form->render( "wpstg_settings[fileLimit]" ) ?>
|
151 |
+
</td>
|
152 |
+
</tr>
|
153 |
|
154 |
+
<tr class="row">
|
155 |
+
<td class="row th">
|
156 |
+
<div class="col-title">
|
157 |
+
<?php echo $form->label( "wpstg_settings[maxFileSize]" ) ?>
|
158 |
+
<span class="description">
|
159 |
+
<?php _e( "Maximum size of the files which are allowed to copy. All files larger than this value will be skipped.
|
160 |
Note: Increase this option only if you have a good reason. Files larger than a few megabytes are in 99% of all cases log and backup files which are not needed on a staging site.", "wp-staging" ); ?>
|
161 |
+
<br>
|
162 |
+
<strong>Default:</strong> 8 MB
|
163 |
+
</span>
|
164 |
+
</div>
|
165 |
+
</td>
|
166 |
+
<td>
|
167 |
+
<?php echo $form->render( "wpstg_settings[maxFileSize]" ) ?>
|
168 |
+
</td>
|
169 |
+
</tr>
|
170 |
+
<tr class="row">
|
171 |
+
<td class="row th">
|
172 |
+
<div class="col-title">
|
173 |
+
<?php echo $form->label( "wpstg_settings[batchSize]" ) ?>
|
174 |
+
<span class="description">
|
175 |
+
<?php _e( "Buffer size for the file copy process in megabyte.
|
176 |
The higher the value the faster large files are copied.
|
177 |
To find out the highest possible values try a high one and lower it until
|
178 |
you get no errors during file copy process. Usually this value correlates directly
|
179 |
with the memory consumption of php so make sure that
|
180 |
it does not exceed any php.ini max_memory limits.", "wp-staging" ); ?>
|
181 |
+
<br>
|
182 |
+
<strong>Default:</strong> 2 MB
|
183 |
+
</span>
|
184 |
+
</div>
|
185 |
+
</td>
|
186 |
+
<td>
|
187 |
+
<?php echo $form->render( "wpstg_settings[batchSize]" ) ?>
|
188 |
+
</td>
|
189 |
+
</tr>
|
190 |
|
191 |
+
<tr class="row">
|
192 |
+
<td class="row th">
|
193 |
+
<div class="col-title">
|
194 |
+
<?php echo $form->label( "wpstg_settings[cpuLoad]" ) ?>
|
195 |
+
<span class="description">
|
196 |
+
<?php _e( "Using high will result in fast as possible processing but the cpu load
|
197 |
increases and it's also possible that staging process gets interrupted because of too many ajax requests
|
198 |
(e.g. <strong>authorization error</strong>).
|
199 |
Using a lower value results in lower cpu load on your server but also slower staging site creation.", "wp-staging" ); ?>
|
200 |
+
<br>
|
201 |
+
<strong>Default: </strong> Low
|
202 |
+
</span>
|
203 |
+
</div>
|
204 |
+
</td>
|
205 |
+
<td>
|
206 |
+
<?php echo $form->render( "wpstg_settings[cpuLoad]" ) ?>
|
207 |
+
</td>
|
208 |
+
</tr>
|
209 |
+
<tr class="row">
|
210 |
+
<td class="row th">
|
211 |
+
<div class="col-title">
|
212 |
+
<?php echo $form->label( "wpstg_settings[delayRequests]" ) ?>
|
213 |
+
<span class="description">
|
214 |
+
<?php _e( "If your server uses rate limits it blocks requests and WP Staging can be interrupted. You can resolve that by adding one or more seconds of delay between the processing requests. ", "wp-staging" ); ?>
|
215 |
+
<br>
|
216 |
+
<strong>Default: </strong> 0s
|
217 |
+
</span>
|
218 |
+
</div>
|
219 |
+
</td>
|
220 |
+
<td>
|
221 |
+
<?php echo $form->render( "wpstg_settings[delayRequests]" ) ?>
|
222 |
+
</td>
|
223 |
+
</tr>
|
224 |
+
<tr class="row">
|
225 |
+
<td class="row th">
|
226 |
+
<div class="col-title">
|
227 |
+
<?php echo $form->label( "wpstg_settings[disableAdminLogin]" ) ?>
|
228 |
+
<span class="description">
|
229 |
+
If you want to remove the requirement to login to the staging site you can deactivate it here.
|
230 |
+
<strong>Note:</strong> The staging site discourages search engines from indexing the site by setting the 'noindex' tag into header of the staging site.
|
231 |
+
</span>
|
232 |
+
</div>
|
233 |
+
</td>
|
234 |
+
<td>
|
235 |
+
<?php echo $form->render( "wpstg_settings[disableAdminLogin]" ) ?>
|
236 |
+
</td>
|
237 |
+
</tr>
|
238 |
+
<tr class="row">
|
239 |
+
<td class="row th">
|
240 |
+
<div class="col-title">
|
241 |
+
<?php echo $form->label( "wpstg_settings[debugMode]" ) ?>
|
242 |
+
<span class="description">
|
243 |
+
<?php _e( "This will enable an extended debug mode which creates additional entries
|
|
|
|
|
|
|
244 |
in <strong>wp-content/uploads/wp-staging/logs/logfile.log</strong>.
|
245 |
Please enable this when we ask you to do so.", "wp-staging" ); ?>
|
246 |
+
</span>
|
247 |
+
</div>
|
248 |
+
</td>
|
249 |
+
<td>
|
250 |
+
<?php echo $form->render( "wpstg_settings[debugMode]" ) ?>
|
251 |
+
</td>
|
252 |
+
</tr>
|
253 |
+
<tr class="row">
|
254 |
+
<td class="row th">
|
255 |
+
<div class="col-title">
|
256 |
+
<?php echo $form->label( "wpstg_settings[optimizer]" ) ?>
|
257 |
+
<span class="description">
|
258 |
+
<?php _e( "The Optimizer is a mu plugin which disables all other plugins during WP Staging processing. Usually this makes the cloning process more reliable. If you experience issues, disable the Optimizer.", "wp-staging" ); ?>
|
259 |
+
</span>
|
260 |
+
</div>
|
261 |
+
</td>
|
262 |
+
<td>
|
263 |
+
<?php echo $form->render( "wpstg_settings[optimizer]" ) ?>
|
264 |
+
</td>
|
265 |
+
</tr>
|
266 |
|
267 |
+
<tr class="row">
|
268 |
+
<td class="row th">
|
269 |
+
<div class="col-title">
|
270 |
+
<?php echo $form->label( "wpstg_settings[unInstallOnDelete]" ) ?>
|
271 |
+
<span class="description">
|
272 |
+
<?php _e( "Check this box if you like WP Staging to completely remove all of its data when the plugin is deleted.
|
273 |
This will not remove staging sites files or database tables.", "wp-staging" ); ?>
|
274 |
+
</span>
|
275 |
+
</div>
|
276 |
+
</td>
|
277 |
+
<td>
|
278 |
+
<?php echo $form->render( "wpstg_settings[unInstallOnDelete]" ) ?>
|
279 |
+
</td>
|
280 |
+
</tr>
|
281 |
|
282 |
+
<tr class="row">
|
283 |
+
<td class="row th">
|
284 |
+
<div class="col-title">
|
285 |
+
<?php echo $form->label( "wpstg_settings[checkDirectorySize]" ) ?>
|
286 |
+
<span class="description">
|
287 |
+
<?php _e( "Check this box if you like WP Staging to check sizes of each directory on scanning process.
|
288 |
<br>
|
289 |
Warning this may cause timeout problems in big directory / file structures.", "wp-staging" ); ?>
|
290 |
+
</span>
|
291 |
+
</div>
|
292 |
+
</td>
|
293 |
+
<td>
|
294 |
+
<?php echo $form->render( "wpstg_settings[checkDirectorySize]" ) ?>
|
295 |
+
</td>
|
296 |
+
</tr>
|
297 |
+
</tbody>
|
298 |
+
</table>
|
299 |
+
</div>
|
300 |
+
<?php
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
301 |
endforeach;
|
302 |
// Show submit button any tab but add-ons
|
303 |
if( $activeTab !== "add-ons" ) {
|
304 |
+
submit_button();
|
305 |
}
|
306 |
unset( $tabs );
|
307 |
?>
|
@@ -21,11 +21,11 @@ class Settings {
|
|
21 |
/**
|
22 |
* @var int
|
23 |
*/
|
24 |
-
|
25 |
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
protected $batchSize;
|
30 |
|
31 |
/**
|
@@ -33,6 +33,11 @@ class Settings {
|
|
33 |
*/
|
34 |
protected $cpuLoad;
|
35 |
|
|
|
|
|
|
|
|
|
|
|
36 |
/**
|
37 |
* @var bool
|
38 |
*/
|
@@ -51,11 +56,11 @@ class Settings {
|
|
51 |
/**
|
52 |
* @var bool
|
53 |
*/
|
54 |
-
|
55 |
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
protected $checkDirectorySize;
|
60 |
|
61 |
/**
|
@@ -71,25 +76,31 @@ class Settings {
|
|
71 |
|
72 |
|
73 |
/**
|
|
|
|
|
|
|
|
|
|
|
|
|
74 |
* Settings constructor.
|
75 |
*/
|
76 |
public function __construct() {
|
77 |
-
|
78 |
|
79 |
if (!empty($this->_raw)){
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
|
84 |
-
|
85 |
* @param array $settings
|
86 |
* @return $this
|
87 |
*/
|
88 |
-
|
89 |
$this->_raw = $settings;
|
90 |
|
91 |
-
|
92 |
-
|
93 |
$this->{$key} = $value;
|
94 |
}
|
95 |
}
|
@@ -100,178 +111,176 @@ class Settings {
|
|
100 |
/**
|
101 |
* @return bool
|
102 |
*/
|
103 |
-
|
104 |
-
|
105 |
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
|
117 |
/**
|
118 |
* @return array
|
119 |
*/
|
120 |
-
|
121 |
return $this->_raw;
|
122 |
}
|
123 |
|
124 |
/**
|
125 |
* @return int
|
126 |
*/
|
127 |
-
|
128 |
-
|
129 |
}
|
130 |
|
131 |
/**
|
132 |
* @param int $queryLimit
|
133 |
*/
|
134 |
-
|
135 |
$this->queryLimit = $queryLimit;
|
136 |
}
|
137 |
|
138 |
/**
|
139 |
* @return int
|
140 |
*/
|
141 |
-
|
142 |
-
|
143 |
}
|
144 |
|
145 |
/**
|
146 |
-
* @param int $
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
|
159 |
-
|
160 |
* @param int $batchSize
|
161 |
*/
|
162 |
-
|
163 |
$this->batchSize = $batchSize;
|
164 |
}
|
165 |
|
166 |
/**
|
167 |
* @return string
|
168 |
*/
|
169 |
-
|
170 |
return $this->cpuLoad;
|
171 |
}
|
172 |
|
|
|
|
|
|
|
|
|
|
|
173 |
/**
|
174 |
* @param string $cpuLoad
|
175 |
*/
|
176 |
-
|
177 |
$this->cpuLoad = $cpuLoad;
|
178 |
}
|
179 |
|
180 |
/**
|
181 |
* @return bool
|
182 |
*/
|
183 |
-
|
184 |
return ('1' === $this->unInstallOnDelete);
|
185 |
}
|
186 |
|
187 |
/**
|
188 |
* @param bool $unInstallOnDelete
|
189 |
*/
|
190 |
-
|
191 |
$this->unInstallOnDelete = $unInstallOnDelete;
|
192 |
}
|
193 |
|
194 |
/**
|
195 |
* @return bool
|
196 |
*/
|
197 |
-
|
198 |
return ('1' === $this->optimizer);
|
199 |
}
|
200 |
|
201 |
/**
|
202 |
* @param bool $optimizer
|
203 |
*/
|
204 |
-
|
205 |
$this->optimizer = $optimizer;
|
206 |
}
|
207 |
|
208 |
/**
|
209 |
* @return bool
|
210 |
*/
|
211 |
-
|
212 |
return ('1' === $this->disableAdminLogin);
|
213 |
}
|
214 |
|
215 |
/**
|
216 |
* @param bool $disableAdminLogin
|
217 |
*/
|
218 |
-
|
219 |
$this->disableAdminLogin = $disableAdminLogin;
|
220 |
}
|
221 |
|
222 |
-
|
223 |
-
* @return bool
|
224 |
-
*/
|
225 |
-
public function isWpSubDirectory() {
|
226 |
-
return ('1' === $this->wpSubDirectory);
|
227 |
-
}
|
228 |
-
|
229 |
-
/**
|
230 |
-
* @param bool $wpSubDirectory
|
231 |
-
*/
|
232 |
-
public function setWpSubDirectory( $wpSubDirectory ) {
|
233 |
-
$this->wpSubDirectory = $wpSubDirectory;
|
234 |
-
}
|
235 |
|
236 |
/**
|
237 |
* @return bool
|
238 |
*/
|
239 |
-
|
240 |
return ('1' === $this->checkDirectorySize);
|
241 |
}
|
242 |
|
243 |
/**
|
244 |
* @param bool $checkDirectorySize
|
245 |
*/
|
246 |
-
|
247 |
$this->checkDirectorySize = $checkDirectorySize;
|
248 |
}
|
249 |
|
250 |
/**
|
251 |
* @return bool
|
252 |
*/
|
253 |
-
|
254 |
return ('1' === $this->debugMode);
|
255 |
}
|
256 |
|
257 |
/**
|
258 |
* @param bool $debugMode
|
259 |
*/
|
260 |
-
|
261 |
$this->debugMode = $debugMode;
|
262 |
}
|
263 |
|
264 |
/**
|
265 |
* @return array
|
266 |
*/
|
267 |
-
|
268 |
return $this->blackListedPlugins;
|
269 |
}
|
270 |
|
271 |
/**
|
272 |
* @param array $blackListedPlugins
|
273 |
*/
|
274 |
-
|
275 |
$this->blackListedPlugins = $blackListedPlugins;
|
276 |
}
|
277 |
-
|
|
|
|
|
|
|
|
|
|
21 |
/**
|
22 |
* @var int
|
23 |
*/
|
24 |
+
protected $fileLimit;
|
25 |
|
26 |
+
/**
|
27 |
+
* @var int
|
28 |
+
*/
|
29 |
protected $batchSize;
|
30 |
|
31 |
/**
|
33 |
*/
|
34 |
protected $cpuLoad;
|
35 |
|
36 |
+
/**
|
37 |
+
* @var int
|
38 |
+
*/
|
39 |
+
protected $delayRequests;
|
40 |
+
|
41 |
/**
|
42 |
* @var bool
|
43 |
*/
|
56 |
/**
|
57 |
* @var bool
|
58 |
*/
|
59 |
+
protected $skipTransients;
|
60 |
|
61 |
+
/**
|
62 |
+
* @var bool
|
63 |
+
*/
|
64 |
protected $checkDirectorySize;
|
65 |
|
66 |
/**
|
76 |
|
77 |
|
78 |
/**
|
79 |
+
* User roles to access the staging site
|
80 |
+
* @var type array
|
81 |
+
*/
|
82 |
+
protected $userRoles = array();
|
83 |
+
|
84 |
+
/**
|
85 |
* Settings constructor.
|
86 |
*/
|
87 |
public function __construct() {
|
88 |
+
$this->_raw = get_option( "wpstg_settings", array() );
|
89 |
|
90 |
if (!empty($this->_raw)){
|
91 |
+
$this->hydrate( $this->_raw );
|
92 |
+
}
|
93 |
+
}
|
94 |
|
95 |
+
/**
|
96 |
* @param array $settings
|
97 |
* @return $this
|
98 |
*/
|
99 |
+
public function hydrate( $settings = array() ) {
|
100 |
$this->_raw = $settings;
|
101 |
|
102 |
+
foreach ( $settings as $key => $value ) {
|
103 |
+
if( property_exists( $this, $key ) ) {
|
104 |
$this->{$key} = $value;
|
105 |
}
|
106 |
}
|
111 |
/**
|
112 |
* @return bool
|
113 |
*/
|
114 |
+
public function save() {
|
115 |
+
$data = array();
|
116 |
|
117 |
+
foreach ( get_object_vars( $this ) as $key => $value ) {
|
118 |
+
if( 0 == strpos( $key, '_' ) ) {
|
119 |
+
continue;
|
120 |
+
}
|
121 |
|
122 |
+
$data[$key] = $value;
|
123 |
+
}
|
124 |
+
|
125 |
+
return update_option( "wpstg_settings", $data );
|
126 |
+
}
|
127 |
|
128 |
/**
|
129 |
* @return array
|
130 |
*/
|
131 |
+
public function getRaw() {
|
132 |
return $this->_raw;
|
133 |
}
|
134 |
|
135 |
/**
|
136 |
* @return int
|
137 |
*/
|
138 |
+
public function getQueryLimit() {
|
139 |
+
return ( int ) $this->queryLimit;
|
140 |
}
|
141 |
|
142 |
/**
|
143 |
* @param int $queryLimit
|
144 |
*/
|
145 |
+
public function setQueryLimit( $queryLimit ) {
|
146 |
$this->queryLimit = $queryLimit;
|
147 |
}
|
148 |
|
149 |
/**
|
150 |
* @return int
|
151 |
*/
|
152 |
+
public function getFileLimit() {
|
153 |
+
return ( int ) $this->fileLimit;
|
154 |
}
|
155 |
|
156 |
/**
|
157 |
+
* @param int $fileLimit
|
158 |
+
*/
|
159 |
+
public function setFileLimit( $fileLimit ) {
|
160 |
+
$this->fileLimit = $fileLimit;
|
161 |
+
}
|
162 |
|
163 |
+
/**
|
164 |
+
* @return int
|
165 |
+
*/
|
166 |
+
public function getBatchSize() {
|
167 |
+
return ( int ) $this->batchSize;
|
168 |
+
}
|
169 |
|
170 |
+
/**
|
171 |
* @param int $batchSize
|
172 |
*/
|
173 |
+
public function setBatchSize( $batchSize ) {
|
174 |
$this->batchSize = $batchSize;
|
175 |
}
|
176 |
|
177 |
/**
|
178 |
* @return string
|
179 |
*/
|
180 |
+
public function getCpuLoad() {
|
181 |
return $this->cpuLoad;
|
182 |
}
|
183 |
|
184 |
+
|
185 |
+
public function getDelayRequests(){
|
186 |
+
return $this->delayRequests;
|
187 |
+
}
|
188 |
+
|
189 |
/**
|
190 |
* @param string $cpuLoad
|
191 |
*/
|
192 |
+
public function setCpuLoad( $cpuLoad ) {
|
193 |
$this->cpuLoad = $cpuLoad;
|
194 |
}
|
195 |
|
196 |
/**
|
197 |
* @return bool
|
198 |
*/
|
199 |
+
public function isUnInstallOnDelete() {
|
200 |
return ('1' === $this->unInstallOnDelete);
|
201 |
}
|
202 |
|
203 |
/**
|
204 |
* @param bool $unInstallOnDelete
|
205 |
*/
|
206 |
+
public function setUnInstallOnDelete( $unInstallOnDelete ) {
|
207 |
$this->unInstallOnDelete = $unInstallOnDelete;
|
208 |
}
|
209 |
|
210 |
/**
|
211 |
* @return bool
|
212 |
*/
|
213 |
+
public function isOptimizer() {
|
214 |
return ('1' === $this->optimizer);
|
215 |
}
|
216 |
|
217 |
/**
|
218 |
* @param bool $optimizer
|
219 |
*/
|
220 |
+
public function setOptimizer( $optimizer ) {
|
221 |
$this->optimizer = $optimizer;
|
222 |
}
|
223 |
|
224 |
/**
|
225 |
* @return bool
|
226 |
*/
|
227 |
+
public function isDisableAdminLogin() {
|
228 |
return ('1' === $this->disableAdminLogin);
|
229 |
}
|
230 |
|
231 |
/**
|
232 |
* @param bool $disableAdminLogin
|
233 |
*/
|
234 |
+
public function setDisableAdminLogin( $disableAdminLogin ) {
|
235 |
$this->disableAdminLogin = $disableAdminLogin;
|
236 |
}
|
237 |
|
238 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
239 |
|
240 |
/**
|
241 |
* @return bool
|
242 |
*/
|
243 |
+
public function isCheckDirectorySize() {
|
244 |
return ('1' === $this->checkDirectorySize);
|
245 |
}
|
246 |
|
247 |
/**
|
248 |
* @param bool $checkDirectorySize
|
249 |
*/
|
250 |
+
public function setCheckDirectorySize( $checkDirectorySize ) {
|
251 |
$this->checkDirectorySize = $checkDirectorySize;
|
252 |
}
|
253 |
|
254 |
/**
|
255 |
* @return bool
|
256 |
*/
|
257 |
+
public function isDebugMode() {
|
258 |
return ('1' === $this->debugMode);
|
259 |
}
|
260 |
|
261 |
/**
|
262 |
* @param bool $debugMode
|
263 |
*/
|
264 |
+
public function setDebugMode( $debugMode ) {
|
265 |
$this->debugMode = $debugMode;
|
266 |
}
|
267 |
|
268 |
/**
|
269 |
* @return array
|
270 |
*/
|
271 |
+
public function getBlackListedPlugins() {
|
272 |
return $this->blackListedPlugins;
|
273 |
}
|
274 |
|
275 |
/**
|
276 |
* @param array $blackListedPlugins
|
277 |
*/
|
278 |
+
public function setBlackListedPlugins( $blackListedPlugins ) {
|
279 |
$this->blackListedPlugins = $blackListedPlugins;
|
280 |
}
|
281 |
+
|
282 |
+
public function setUserRoles ($userRoles){
|
283 |
+
$this->userRoles = $userRoles;
|
284 |
+
}
|
285 |
+
|
286 |
+
}
|
@@ -4,40 +4,49 @@ namespace WPStaging\Utils;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
-
class Strings{
|
11 |
-
|
12 |
-
/**
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
public function str_replace_first( $search, $replace, $subject ) {
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
}
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
}
|
42 |
|
43 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
+
class Strings {
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Replace first occurance of certain string
|
14 |
+
* @param string $search
|
15 |
+
* @param string $replace
|
16 |
+
* @param string $subject
|
17 |
+
* @return string
|
18 |
+
*/
|
19 |
+
public function str_replace_first( $search, $replace, $subject ) {
|
20 |
+
|
21 |
+
if( empty( $search ) )
|
22 |
+
return $subject;
|
23 |
+
|
24 |
+
$pos = strpos( $subject, $search );
|
25 |
+
if( $pos !== false ) {
|
26 |
+
return substr_replace( $subject, $replace, $pos, strlen( $search ) );
|
27 |
+
}
|
28 |
+
return $subject;
|
29 |
+
}
|
30 |
+
|
31 |
+
/**
|
32 |
+
* Get last string after last certain element in string
|
33 |
+
* Example: getLastElemAfterString('/', '/path/stagingsite/subfolder') returns 'subfolder'
|
34 |
+
* @param string $needle
|
35 |
+
* @param string $haystack
|
36 |
+
* @return string
|
37 |
+
*/
|
38 |
+
public function getLastElemAfterString( $needle, $haystack ) {
|
39 |
+
$pos = strrpos( $haystack, $needle );
|
40 |
+
return $pos === false ? $haystack : substr( $haystack, $pos + 1 );
|
41 |
+
}
|
42 |
+
|
43 |
+
/**
|
44 |
+
* Return url without scheme
|
45 |
+
* @param string $str
|
46 |
+
* @return string
|
47 |
+
*/
|
48 |
+
public function getUrlWithoutScheme( $str ) {
|
49 |
+
return preg_replace( '#^https?://#', '', rtrim( $str, '/' ) );
|
50 |
}
|
51 |
|
52 |
}
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* Get directory permissions
|
5 |
+
*
|
6 |
+
* @return int
|
7 |
+
*/
|
8 |
+
function wpstg_get_permissions_for_directory() {
|
9 |
+
if( defined( 'FS_CHMOD_DIR' ) ) {
|
10 |
+
return FS_CHMOD_DIR;
|
11 |
+
}
|
12 |
+
|
13 |
+
return 0755;
|
14 |
+
}
|
15 |
+
|
16 |
+
/**
|
17 |
+
* Get file permissions
|
18 |
+
*
|
19 |
+
* @return int
|
20 |
+
*/
|
21 |
+
function wpstg_get_permissions_for_file() {
|
22 |
+
if( defined( 'FS_CHMOD_FILE' ) ) {
|
23 |
+
return FS_CHMOD_FILE;
|
24 |
+
}
|
25 |
+
|
26 |
+
return 0644;
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* PHP setup environment
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*/
|
34 |
+
function wpstg_setup_environment() {
|
35 |
+
// Set whether a client disconnect should abort script execution
|
36 |
+
@ignore_user_abort( true );
|
37 |
+
|
38 |
+
// Set maximum execution time
|
39 |
+
@set_time_limit( 0 );
|
40 |
+
|
41 |
+
// Set maximum time in seconds a script is allowed to parse input data
|
42 |
+
@ini_set( 'max_input_time', '-1' );
|
43 |
+
|
44 |
+
// Set maximum backtracking steps
|
45 |
+
@ini_set( 'pcre.backtrack_limit', PHP_INT_MAX );
|
46 |
+
|
47 |
+
// Set binary safe encoding
|
48 |
+
// if ( @function_exists( 'mb_internal_encoding' ) && ( @ini_get( 'mbstring.func_overload' ) & 2 ) ) {
|
49 |
+
// @mb_internal_encoding( 'ISO-8859-1' );
|
50 |
+
// }
|
51 |
+
}
|
52 |
+
|
53 |
+
/**
|
54 |
+
* Escape Windows directory separator
|
55 |
+
*
|
56 |
+
* @param string $path Path
|
57 |
+
*
|
58 |
+
* @return string
|
59 |
+
*/
|
60 |
+
function wpstg_escape_windows_directory_separator( $path ) {
|
61 |
+
return preg_replace( '/[\\\\]+/', '\\\\\\\\', $path );
|
62 |
+
}
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Replace Windows directory separator
|
66 |
+
* Replace backward slash with forward slash directory separator
|
67 |
+
* Windows Compatibility Fix
|
68 |
+
*
|
69 |
+
* @param string $path Path
|
70 |
+
*
|
71 |
+
* @return string
|
72 |
+
*/
|
73 |
+
function wpstg_replace_windows_directory_separator( $path ) {
|
74 |
+
return preg_replace( '/[\\\\]+/', '/', $path );
|
75 |
+
}
|
@@ -4,7 +4,7 @@ namespace WPStaging;
|
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
-
|
8 |
}
|
9 |
|
10 |
// Ensure to include autoloader class
|
@@ -26,407 +26,438 @@ use WPStaging\Cron\Cron;
|
|
26 |
*/
|
27 |
final class WPStaging {
|
28 |
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
192 |
-
|
193 |
-
|
194 |
-
|
195 |
-
|
196 |
-
|
197 |
-
|
198 |
-
|
199 |
-
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
|
206 |
-
|
207 |
-
|
208 |
-
|
209 |
-
|
210 |
-
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
-
|
271 |
-
|
272 |
-
|
273 |
-
|
274 |
-
|
275 |
-
|
276 |
-
|
277 |
-
|
278 |
-
|
279 |
-
|
280 |
-
|
281 |
-
|
282 |
-
|
283 |
-
|
284 |
-
|
285 |
-
|
286 |
-
|
287 |
-
|
288 |
-
|
289 |
-
|
290 |
-
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
-
|
297 |
-
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
|
304 |
-
|
305 |
-
|
306 |
-
|
307 |
-
|
308 |
-
|
309 |
-
|
310 |
-
|
311 |
-
|
312 |
-
|
313 |
-
|
314 |
-
|
315 |
-
|
316 |
-
|
317 |
-
|
318 |
-
|
319 |
-
|
320 |
-
|
321 |
-
|
322 |
-
|
323 |
-
|
324 |
-
|
325 |
-
|
326 |
-
|
327 |
-
|
328 |
-
|
329 |
-
|
330 |
-
|
331 |
-
|
332 |
-
|
333 |
-
|
334 |
-
|
335 |
-
|
336 |
-
|
337 |
-
|
338 |
-
|
339 |
-
|
340 |
-
|
341 |
-
|
342 |
-
|
343 |
-
|
344 |
-
|
345 |
-
|
346 |
-
|
347 |
-
|
348 |
-
|
349 |
-
|
350 |
-
|
351 |
-
|
352 |
-
|
353 |
-
|
354 |
-
|
355 |
-
|
356 |
-
|
357 |
-
|
358 |
-
|
359 |
-
|
360 |
-
|
361 |
-
|
362 |
-
|
363 |
-
|
364 |
-
|
365 |
-
|
366 |
-
|
367 |
-
|
368 |
-
|
369 |
-
|
370 |
-
|
371 |
-
|
372 |
-
|
373 |
-
|
374 |
-
|
375 |
-
|
376 |
-
|
377 |
-
|
378 |
-
|
379 |
-
|
380 |
-
|
381 |
-
|
382 |
-
|
383 |
-
|
384 |
-
|
385 |
-
|
386 |
-
|
387 |
-
|
388 |
-
|
389 |
-
|
390 |
-
|
391 |
-
|
392 |
-
|
393 |
-
|
394 |
-
|
395 |
-
|
396 |
-
|
397 |
-
|
398 |
-
|
399 |
-
|
400 |
-
|
401 |
-
|
402 |
-
|
403 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
408 |
-
|
409 |
-
|
410 |
-
|
411 |
-
|
412 |
-
|
413 |
-
|
414 |
-
|
415 |
-
|
416 |
-
|
417 |
-
|
418 |
-
|
419 |
-
|
420 |
-
|
421 |
-
|
422 |
-
|
423 |
-
|
424 |
-
|
425 |
-
|
426 |
-
|
427 |
-
|
428 |
-
|
429 |
-
|
430 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
431 |
|
432 |
}
|
4 |
|
5 |
// No Direct Access
|
6 |
if( !defined( "WPINC" ) ) {
|
7 |
+
die;
|
8 |
}
|
9 |
|
10 |
// Ensure to include autoloader class
|
26 |
*/
|
27 |
final class WPStaging {
|
28 |
|
29 |
+
/**
|
30 |
+
* Plugin version
|
31 |
+
*/
|
32 |
+
const VERSION = "2.4.0";
|
33 |
+
|
34 |
+
/**
|
35 |
+
* Plugin name
|
36 |
+
*/
|
37 |
+
const NAME = "WP Staging";
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Plugin slug
|
41 |
+
*/
|
42 |
+
const SLUG = "wp-staging";
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Compatible WP Version
|
46 |
+
*/
|
47 |
+
const WP_COMPATIBLE = "5.0.0";
|
48 |
+
|
49 |
+
public $wpPath;
|
50 |
+
|
51 |
+
/**
|
52 |
+
* Slug: Either wp-staging or wp-staging-pro
|
53 |
+
* @var string
|
54 |
+
*/
|
55 |
+
public $slug;
|
56 |
+
|
57 |
+
/**
|
58 |
+
* Absolute plugin path
|
59 |
+
* @var string
|
60 |
+
*/
|
61 |
+
public $pluginPath;
|
62 |
+
|
63 |
+
/**
|
64 |
+
* Services
|
65 |
+
* @var array
|
66 |
+
*/
|
67 |
+
private $services;
|
68 |
+
|
69 |
+
/**
|
70 |
+
* Singleton instance
|
71 |
+
* @var WPStaging
|
72 |
+
*/
|
73 |
+
private static $instance;
|
74 |
+
|
75 |
+
/**
|
76 |
+
* WPStaging constructor.
|
77 |
+
*/
|
78 |
+
private function __construct() {
|
79 |
+
|
80 |
+
$this->registerMain();
|
81 |
+
$this->registerNamespaces();
|
82 |
+
$this->loadLanguages();
|
83 |
+
$this->loadDependencies();
|
84 |
+
$this->defineHooks();
|
85 |
+
// Licensing stuff be loaded in wpstg core to make cron hook available from frontpage
|
86 |
+
$this->initLicensing();
|
87 |
+
|
88 |
+
wpstg_setup_environment();
|
89 |
+
}
|
90 |
+
|
91 |
+
/**
|
92 |
+
* Get root WP root path -
|
93 |
+
* Changed ABSPATH trailingslash for windows compatibility
|
94 |
+
|
95 |
+
* @return type
|
96 |
+
*/
|
97 |
+
public static function getWPpath() {
|
98 |
+
return str_replace( '/', DIRECTORY_SEPARATOR, ABSPATH );
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* Method to be executed upon activation of the plugin
|
103 |
+
*/
|
104 |
+
public function registerMain() {
|
105 |
+
// Slug of the plugin
|
106 |
+
$this->slug = plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
|
107 |
+
|
108 |
+
// absolute path to the main plugin dir
|
109 |
+
$this->pluginPath = plugin_dir_path( dirname( dirname( __FILE__ ) ) );
|
110 |
+
|
111 |
+
// URL to apps folder
|
112 |
+
$this->url = plugin_dir_url( dirname( __FILE__ ) );
|
113 |
+
|
114 |
+
// URL to backend public folder folder
|
115 |
+
$this->backend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Backend/public/";
|
116 |
+
|
117 |
+
// URL to frontend public folder folder
|
118 |
+
$this->frontend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Frontend/public/";
|
119 |
+
}
|
120 |
+
|
121 |
+
/**
|
122 |
+
* Define Hooks
|
123 |
+
*/
|
124 |
+
public function defineHooks() {
|
125 |
+
$loader = $this->get( "loader" );
|
126 |
+
$loader->addAction( "admin_enqueue_scripts", $this, "enqueueElements", 100 );
|
127 |
+
$loader->addAction( "admin_enqueue_scripts", $this, "removeWPCoreJs", 5 );
|
128 |
+
$loader->addAction( "wp_enqueue_scripts", $this, "enqueueElements", 100 );
|
129 |
+
$this->addIntervals();
|
130 |
+
}
|
131 |
+
|
132 |
+
/**
|
133 |
+
* Remove heartbeat api and user login check
|
134 |
+
* @param type $hook
|
135 |
+
* @return type
|
136 |
+
*/
|
137 |
+
public function removeWPCoreJs( $hook ) {
|
138 |
+
$availablePages = array(
|
139 |
+
"toplevel_page_wpstg_clone",
|
140 |
+
"wp-staging-pro_page_wpstg-settings",
|
141 |
+
"wp-staging-pro_page_wpstg-tools",
|
142 |
+
"wp-staging-pro_page_wpstg-license"
|
143 |
+
);
|
144 |
+
|
145 |
+
// Load these css and js files only on wp staging admin pages
|
146 |
+
if( !in_array( $hook, $availablePages ) || !is_admin() ) {
|
147 |
+
return;
|
148 |
+
}
|
149 |
+
|
150 |
+
// Disable user login status check
|
151 |
+
remove_action( 'admin_enqueue_scripts', 'wp_auth_check_load' );
|
152 |
+
// Disable heartbeat check for cloning and pushing
|
153 |
+
wp_deregister_script( 'heartbeat' );
|
154 |
+
}
|
155 |
+
|
156 |
+
/**
|
157 |
+
* Add new cron time event "weekly"
|
158 |
+
*/
|
159 |
+
public function addIntervals() {
|
160 |
+
$interval = new Cron();
|
161 |
+
}
|
162 |
+
|
163 |
+
/**
|
164 |
+
* Scripts and Styles
|
165 |
+
* @param string $hook
|
166 |
+
*/
|
167 |
+
public function enqueueElements( $hook ) {
|
168 |
+
|
169 |
+
// Load this css file on frontend and backend on all pages if current site is a staging site
|
170 |
+
if( $this->isStagingSite() ) {
|
171 |
+
wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", array(), $this->getVersion() );
|
172 |
+
}
|
173 |
+
|
174 |
+
$availablePages = array(
|
175 |
+
"toplevel_page_wpstg_clone",
|
176 |
+
"wp-staging_page_wpstg-settings",
|
177 |
+
"wp-staging_page_wpstg-tools",
|
178 |
+
"wp-staging_page_wpstg-license",
|
179 |
+
"wp-staging_page_wpstg-welcome",
|
180 |
+
);
|
181 |
+
|
182 |
+
// Load these css and js files only on wp staging admin pages
|
183 |
+
if( !in_array( $hook, $availablePages ) || !is_admin() ) {
|
184 |
+
return;
|
185 |
+
}
|
186 |
+
|
187 |
+
|
188 |
+
// Load admin js files
|
189 |
+
wp_enqueue_script(
|
190 |
+
"wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"), $this->getVersion(), false
|
191 |
+
);
|
192 |
+
|
193 |
+
// Load admin css files
|
194 |
+
wp_enqueue_style(
|
195 |
+
"wpstg-admin", $this->backend_url . "css/wpstg-admin.css", array(), $this->getVersion()
|
196 |
+
);
|
197 |
+
|
198 |
+
wp_localize_script( "wpstg-admin-script", "wpstg", array(
|
199 |
+
"nonce" => wp_create_nonce( "wpstg_ajax_nonce" ),
|
200 |
+
"noncetick" => apply_filters( 'nonce_life', DAY_IN_SECONDS ),
|
201 |
+
"delayReq" => $this->getDelay(),
|
202 |
+
"settings" => ( object ) array(), // TODO add settings?
|
203 |
+
"tblprefix" => self::getTablePrefix(),
|
204 |
+
"isMultisite" => is_multisite() ? true : false
|
205 |
+
) );
|
206 |
+
}
|
207 |
+
|
208 |
+
/**
|
209 |
+
* Get table prefix of the current site
|
210 |
+
* @return string
|
211 |
+
*/
|
212 |
+
public static function getTablePrefix() {
|
213 |
+
$wpDB = WPStaging::getInstance()->get( "wpdb" );
|
214 |
+
return $wpDB->prefix;
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Caching and logging folder
|
219 |
+
*
|
220 |
+
* @return string
|
221 |
+
*/
|
222 |
+
public static function getContentDir() {
|
223 |
+
$wp_upload_dir = wp_upload_dir();
|
224 |
+
$path = $wp_upload_dir['basedir'] . '/wp-staging';
|
225 |
+
wp_mkdir_p( $path );
|
226 |
+
return apply_filters( 'wpstg_get_upload_dir', $path . DIRECTORY_SEPARATOR );
|
227 |
+
}
|
228 |
+
|
229 |
+
/**
|
230 |
+
* Register used namespaces
|
231 |
+
*/
|
232 |
+
private function registerNamespaces() {
|
233 |
+
$autoloader = new Autoloader();
|
234 |
+
$this->set( "autoloader", $autoloader );
|
235 |
+
|
236 |
+
// Autoloader
|
237 |
+
$autoloader->registerNamespaces( array(
|
238 |
+
"WPStaging" => array(
|
239 |
+
$this->pluginPath . 'apps' . DIRECTORY_SEPARATOR,
|
240 |
+
$this->pluginPath . 'apps' . DIRECTORY_SEPARATOR . 'Core' . DIRECTORY_SEPARATOR,
|
241 |
+
$this->pluginPath . 'apps' . DIRECTORY_SEPARATOR . 'Core' . DIRECTORY_SEPARATOR . 'Iterators' . DIRECTORY_SEPARATOR,
|
242 |
+
),
|
243 |
+
"splitbrain" => array(
|
244 |
+
$this->pluginPath . 'vendor' . DIRECTORY_SEPARATOR . 'splitbrain' . DIRECTORY_SEPARATOR
|
245 |
+
)
|
246 |
+
) );
|
247 |
+
|
248 |
+
// Register namespaces
|
249 |
+
$autoloader->register();
|
250 |
+
}
|
251 |
+
|
252 |
+
/**
|
253 |
+
* Get Instance
|
254 |
+
* @return WPStaging
|
255 |
+
*/
|
256 |
+
public static function getInstance() {
|
257 |
+
if( null === static::$instance ) {
|
258 |
+
static::$instance = new static();
|
259 |
+
}
|
260 |
+
|
261 |
+
return static::$instance;
|
262 |
+
}
|
263 |
+
|
264 |
+
/**
|
265 |
+
* Prevent cloning
|
266 |
+
* @return void
|
267 |
+
*/
|
268 |
+
private function __clone() {
|
269 |
+
|
270 |
+
}
|
271 |
+
|
272 |
+
/**
|
273 |
+
* Prevent unserialization
|
274 |
+
* @return void
|
275 |
+
*/
|
276 |
+
private function __wakeup() {
|
277 |
+
|
278 |
+
}
|
279 |
+
|
280 |
+
/**
|
281 |
+
* Load Dependencies
|
282 |
+
*/
|
283 |
+
private function loadDependencies() {
|
284 |
+
// Set loader
|
285 |
+
$this->set( "loader", new Loader() );
|
286 |
+
|
287 |
+
// Set cache
|
288 |
+
$this->set( "cache", new Cache() );
|
289 |
+
|
290 |
+
// Set logger
|
291 |
+
$this->set( "logger", new Logger() );
|
292 |
+
|
293 |
+
// Set settings
|
294 |
+
$this->set( "settings", new Settings() );
|
295 |
+
|
296 |
+
// Load globally available functions
|
297 |
+
require_once $this->pluginPath . 'apps/Core/Utils/functions.php';
|
298 |
+
|
299 |
+
// Set Administrator
|
300 |
+
if( is_admin() ) {
|
301 |
+
new Administrator( $this );
|
302 |
+
} else {
|
303 |
+
new Frontend( $this );
|
304 |
+
}
|
305 |
+
}
|
306 |
+
|
307 |
+
/**
|
308 |
+
* Execute Plugin
|
309 |
+
*/
|
310 |
+
public function run() {
|
311 |
+
$this->get( "loader" )->run();
|
312 |
+
}
|
313 |
+
|
314 |
+
/**
|
315 |
+
* Set a variable to DI with given name
|
316 |
+
* @param string $name
|
317 |
+
* @param mixed $variable
|
318 |
+
* @return $this
|
319 |
+
*/
|
320 |
+
public function set( $name, $variable ) {
|
321 |
+
// It is a function
|
322 |
+
if( is_callable( $variable ) )
|
323 |
+
$variable = $variable();
|
324 |
+
|
325 |
+
// Add it to services
|
326 |
+
$this->services[$name] = $variable;
|
327 |
+
|
328 |
+
return $this;
|
329 |
+
}
|
330 |
+
|
331 |
+
/**
|
332 |
+
* Get given name index from DI
|
333 |
+
* @param string $name
|
334 |
+
* @return mixed|null
|
335 |
+
*/
|
336 |
+
public function get( $name ) {
|
337 |
+
return (isset( $this->services[$name] )) ? $this->services[$name] : null;
|
338 |
+
}
|
339 |
+
|
340 |
+
/**
|
341 |
+
* @return string
|
342 |
+
*/
|
343 |
+
public function getVersion() {
|
344 |
+
return self::VERSION;
|
345 |
+
}
|
346 |
+
|
347 |
+
/**
|
348 |
+
* @return string
|
349 |
+
*/
|
350 |
+
public function getName() {
|
351 |
+
return self::NAME;
|
352 |
+
}
|
353 |
+
|
354 |
+
/**
|
355 |
+
* @return string
|
356 |
+
*/
|
357 |
+
public static function getSlug() {
|
358 |
+
return plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
|
359 |
+
}
|
360 |
+
|
361 |
+
/**
|
362 |
+
* Get path to main plugin file
|
363 |
+
* @return string
|
364 |
+
*/
|
365 |
+
public function getPath() {
|
366 |
+
return dirname( dirname( __FILE__ ) );
|
367 |
+
}
|
368 |
+
|
369 |
+
/**
|
370 |
+
* Get main plugin url
|
371 |
+
* @return type
|
372 |
+
*/
|
373 |
+
public function getUrl() {
|
374 |
+
return plugin_dir_url( dirname( __FILE__ ) );
|
375 |
+
}
|
376 |
+
|
377 |
+
/**
|
378 |
+
* @return array|mixed|object
|
379 |
+
*/
|
380 |
+
public function getDelay() {
|
381 |
+
$options = $this->get( "settings" );
|
382 |
+
$setting = $options->getDelayRequests();
|
383 |
+
|
384 |
+
switch ( $setting ) {
|
385 |
+
case "0":
|
386 |
+
$delay = 0;
|
387 |
+
break;
|
388 |
+
|
389 |
+
case "1":
|
390 |
+
$delay = 1000;
|
391 |
+
break;
|
392 |
+
|
393 |
+
case "2":
|
394 |
+
$delay = 2000;
|
395 |
+
break;
|
396 |
+
|
397 |
+
case "3":
|
398 |
+
$delay = 3000;
|
399 |
+
break;
|
400 |
+
|
401 |
+
case "4":
|
402 |
+
$delay = 4000;
|
403 |
+
break;
|
404 |
+
|
405 |
+
default:
|
406 |
+
$delay = 0;
|
407 |
+
}
|
408 |
+
|
409 |
+
return $delay;
|
410 |
+
}
|
411 |
+
|
412 |
+
/**
|
413 |
+
* Load language file
|
414 |
+
*/
|
415 |
+
public function loadLanguages() {
|
416 |
+
$languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
|
417 |
+
|
418 |
+
// Set filter for plugins languages directory
|
419 |
+
$languagesDirectory = apply_filters( "wpstg_languages_directory", $languagesDirectory );
|
420 |
+
|
421 |
+
// Traditional WP plugin locale filter
|
422 |
+
$locale = apply_filters( "plugin_locale", get_locale(), "wp-staging" );
|
423 |
+
$moFile = sprintf( '%1$s-%2$s.mo', "wp-staging", $locale );
|
424 |
+
|
425 |
+
// Setup paths to current locale file
|
426 |
+
$moFileLocal = $languagesDirectory . $moFile;
|
427 |
+
$moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wp-staging" . DIRECTORY_SEPARATOR . $moFile;
|
428 |
+
|
429 |
+
// Global file (/wp-content/languages/wpstg)
|
430 |
+
if( file_exists( $moFileGlobal ) ) {
|
431 |
+
load_textdomain( "wp-staging", $moFileGlobal );
|
432 |
+
}
|
433 |
+
// Local file (/wp-content/plugins/wp-staging/languages/)
|
434 |
+
elseif( file_exists( $moFileLocal ) ) {
|
435 |
+
load_textdomain( "wp-staging", $moFileLocal );
|
436 |
+
}
|
437 |
+
// Default file
|
438 |
+
else {
|
439 |
+
load_plugin_textdomain( "wp-staging", false, $languagesDirectory );
|
440 |
+
}
|
441 |
+
}
|
442 |
+
|
443 |
+
/**
|
444 |
+
* Check if it is a staging site
|
445 |
+
* @return bool
|
446 |
+
*/
|
447 |
+
private function isStagingSite() {
|
448 |
+
return ("true" === get_option( "wpstg_is_staging_site" ));
|
449 |
+
}
|
450 |
+
|
451 |
+
/**
|
452 |
+
* Initialize licensing functions
|
453 |
+
* @return boolean
|
454 |
+
*/
|
455 |
+
public function initLicensing() {
|
456 |
+
// Add licensing stuff if class exists
|
457 |
+
if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
|
458 |
+
$licensing = new Backend\Pro\Licensing\Licensing();
|
459 |
+
}
|
460 |
+
return false;
|
461 |
+
}
|
462 |
|
463 |
}
|
@@ -64,13 +64,7 @@ class Frontend extends InjectionAware {
|
|
64 |
/**
|
65 |
* Check permissions for the page to decide whether or not to disable the page
|
66 |
*/
|
67 |
-
|
68 |
-
// $this->resetPermaLinks();
|
69 |
-
//
|
70 |
-
// if( $this->disableLogin() ) {
|
71 |
-
// wp_die( sprintf( __( 'Access denied. <a href="%1$s">Login</a> first to access this site', 'wp-staging' ), $this->getLoginUrl() ) );
|
72 |
-
// }
|
73 |
-
// }
|
74 |
public function checkPermissions() {
|
75 |
$this->resetPermaLinks();
|
76 |
|
@@ -106,20 +100,6 @@ class Frontend extends InjectionAware {
|
|
106 |
}
|
107 |
}
|
108 |
|
109 |
-
/**
|
110 |
-
* Get login link
|
111 |
-
* @return string
|
112 |
-
*/
|
113 |
-
// private function getLoginUrl() {
|
114 |
-
//
|
115 |
-
// if( empty( $this->loginSlug ) ) {
|
116 |
-
// //return get_home_url() . '/wp-admin';
|
117 |
-
// return get_site_url() . '/wp-admin';
|
118 |
-
//
|
119 |
-
// }
|
120 |
-
//
|
121 |
-
// return get_home_url() . '/?' . $this->loginSlug;
|
122 |
-
// }
|
123 |
/**
|
124 |
* Get path to wp-login.php
|
125 |
* @return string
|
64 |
/**
|
65 |
* Check permissions for the page to decide whether or not to disable the page
|
66 |
*/
|
67 |
+
|
|
|
|
|
|
|
|
|
|
|
|
|
68 |
public function checkPermissions() {
|
69 |
$this->resetPermaLinks();
|
70 |
|
100 |
}
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
/**
|
104 |
* Get path to wp-login.php
|
105 |
* @return string
|
@@ -3,192 +3,194 @@
|
|
3 |
namespace WPStaging\Frontend;
|
4 |
|
5 |
class loginForm {
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
60 |
-
|
61 |
-
|
62 |
-
|
63 |
-
|
64 |
-
|
65 |
-
|
66 |
-
|
67 |
-
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
104 |
-
|
105 |
-
|
106 |
-
|
107 |
-
|
108 |
-
|
109 |
-
|
110 |
-
|
111 |
-
|
112 |
-
|
113 |
-
|
114 |
-
|
115 |
-
|
116 |
-
|
117 |
-
|
118 |
-
|
119 |
-
|
120 |
-
|
121 |
-
|
122 |
-
|
123 |
-
|
124 |
-
|
125 |
-
|
126 |
-
|
127 |
-
|
128 |
-
|
129 |
-
|
130 |
-
|
131 |
-
|
132 |
-
|
133 |
-
|
134 |
-
|
135 |
-
|
136 |
-
|
137 |
-
|
138 |
-
|
139 |
-
|
140 |
-
|
141 |
-
|
142 |
-
|
143 |
-
|
144 |
-
|
145 |
-
|
146 |
-
|
147 |
-
|
148 |
-
|
149 |
-
|
150 |
-
|
151 |
-
|
152 |
-
|
153 |
-
|
154 |
-
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
|
161 |
-
|
162 |
-
|
163 |
-
|
164 |
-
|
165 |
-
|
166 |
-
|
167 |
-
|
168 |
-
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
|
173 |
-
|
174 |
-
|
175 |
-
|
176 |
-
|
177 |
-
|
178 |
-
|
179 |
-
|
180 |
-
|
181 |
-
|
182 |
-
|
183 |
-
|
184 |
-
|
185 |
-
|
186 |
-
|
187 |
-
|
188 |
-
|
189 |
-
|
190 |
-
|
191 |
-
|
|
|
|
|
192 |
// private function getLoginForm() {
|
193 |
// $this->getHeader();
|
194 |
// echo '<body id="error-page">';
|
@@ -208,65 +210,65 @@ class loginForm {
|
|
208 |
// $this->getFooter();
|
209 |
// }
|
210 |
|
211 |
-
|
212 |
-
|
213 |
-
|
214 |
-
|
215 |
-
|
216 |
-
|
217 |
-
|
218 |
-
|
219 |
-
|
220 |
-
|
221 |
-
|
222 |
-
|
223 |
-
|
224 |
-
|
225 |
-
|
226 |
-
|
227 |
-
|
228 |
-
|
229 |
-
|
230 |
-
|
231 |
-
|
232 |
-
|
233 |
-
|
234 |
-
|
235 |
-
|
236 |
-
|
237 |
-
|
238 |
-
|
239 |
-
|
240 |
-
|
241 |
-
|
242 |
-
|
243 |
-
|
244 |
-
|
245 |
-
|
246 |
-
|
247 |
-
|
248 |
-
|
249 |
-
|
250 |
-
|
251 |
-
|
252 |
-
|
253 |
-
|
254 |
-
|
255 |
-
|
256 |
-
|
257 |
-
|
258 |
-
|
259 |
-
|
260 |
-
|
261 |
-
|
262 |
-
|
263 |
-
|
264 |
-
|
265 |
-
|
266 |
-
|
267 |
-
|
268 |
-
|
269 |
-
|
270 |
<form name="' . $args['form_id'] . '" id="' . $args['form_id'] . '" action="" method="post">
|
271 |
<p class="login-username">
|
272 |
<label for="' . esc_attr( $args['id_username'] ) . '">' . esc_html( $args['label_username'] ) . '</label>
|
@@ -288,11 +290,11 @@ class loginForm {
|
|
288 |
|
289 |
</form>';
|
290 |
|
291 |
-
|
292 |
-
|
293 |
-
|
294 |
-
|
295 |
-
|
296 |
|
297 |
}
|
298 |
|
3 |
namespace WPStaging\Frontend;
|
4 |
|
5 |
class loginForm {
|
6 |
+
|
7 |
+
/**
|
8 |
+
*
|
9 |
+
* @var type array
|
10 |
+
*/
|
11 |
+
private $args = array();
|
12 |
+
private $error;
|
13 |
+
|
14 |
+
function __construct() {
|
15 |
+
$this->login();
|
16 |
+
}
|
17 |
+
|
18 |
+
private function login() {
|
19 |
+
|
20 |
+
|
21 |
+
if( is_user_logged_in() ) {
|
22 |
+
return false;
|
23 |
+
}
|
24 |
+
|
25 |
+
if( !isset( $_POST['wpstg-username'] ) || !isset( $_POST['wpstg-pass'] ) ) {
|
26 |
+
return false;
|
27 |
+
}
|
28 |
+
|
29 |
+
|
30 |
+
if( isset( $_POST['wpstg-submit'] ) && (empty( $_POST['wpstg-username'] ) || empty( $_POST['wpstg-pass'] ) ) ) {
|
31 |
+
$this->error = 'No username or password given!';
|
32 |
+
return false;
|
33 |
+
}
|
34 |
+
|
35 |
+
$user_data = get_user_by( 'login', $_POST['wpstg-username'] );
|
36 |
+
|
37 |
+
if( !$user_data ) {
|
38 |
+
$user_data = get_user_by( 'email', $_POST['wpstg-username'] );
|
39 |
+
}
|
40 |
+
|
41 |
+
if( !$user_data ) {
|
42 |
+
return false;
|
43 |
+
}
|
44 |
+
|
45 |
+
if( wp_check_password( $_POST['wpstg-pass'], $user_data->user_pass, $user_data->ID ) ) {
|
46 |
+
|
47 |
+
$rememberme = isset( $_POST['rememberme'] ) ? true : false;
|
48 |
+
|
49 |
+
wp_set_auth_cookie( $user_data->ID, $rememberme );
|
50 |
+
wp_set_current_user( $user_data->ID, $_POST['wpstg-username'] );
|
51 |
+
do_action( 'wp_login', $_POST['wpstg-username'], get_userdata( $user_data->ID ) );
|
52 |
+
header( 'Location:' . get_site_url() . '/wp-admin/' );
|
53 |
+
} else {
|
54 |
+
$this->error = 'Username or password wrong!';
|
55 |
+
}
|
56 |
+
}
|
57 |
+
|
58 |
+
public function renderForm( $args = array() ) {
|
59 |
+
$this->args = $args;
|
60 |
+
$this->getHeader();
|
61 |
+
$this->getLoginForm();
|
62 |
+
$this->getFooter();
|
63 |
+
}
|
64 |
+
|
65 |
+
private function getHeader() {
|
66 |
+
?>
|
67 |
+
|
68 |
+
<!DOCTYPE html>
|
69 |
+
<html xmlns="http://www.w3.org/1999/xhtml" lang="en-US">
|
70 |
+
<head>
|
71 |
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
72 |
+
<meta name="viewport" content="width=device-width">
|
73 |
+
<meta name='robots' content='noindex,follow' />
|
74 |
+
<title>WordPress › You need to login to access that page</title>
|
75 |
+
<style type="text/css">
|
76 |
+
html {
|
77 |
+
background: #f1f1f1;
|
78 |
+
}
|
79 |
+
body {
|
80 |
+
background: #fff;
|
81 |
+
color: #444;
|
82 |
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
83 |
+
margin: 2em auto;
|
84 |
+
padding: 1em 2em;
|
85 |
+
max-width: 700px;
|
86 |
+
-webkit-box-shadow: 0 1px 3px rgba(0,0,0,0.13);
|
87 |
+
box-shadow: 0 1px 3px rgba(0,0,0,0.13);
|
88 |
+
}
|
89 |
+
h1 {
|
90 |
+
border-bottom: 1px solid #dadada;
|
91 |
+
clear: both;
|
92 |
+
color: #666;
|
93 |
+
font-size: 24px;
|
94 |
+
margin: 30px 0 0 0;
|
95 |
+
padding: 0;
|
96 |
+
padding-bottom: 7px;
|
97 |
+
}
|
98 |
+
#error-page {
|
99 |
+
margin-top: 50px;
|
100 |
+
}
|
101 |
+
#error-page p {
|
102 |
+
font-size: 14px;
|
103 |
+
line-height: 1.5;
|
104 |
+
margin: 25px 0 20px;
|
105 |
+
}
|
106 |
+
#error-page code {
|
107 |
+
font-family: Consolas, Monaco, monospace;
|
108 |
+
}
|
109 |
+
ul li {
|
110 |
+
margin-bottom: 10px;
|
111 |
+
font-size: 14px ;
|
112 |
+
}
|
113 |
+
a {
|
114 |
+
color: #0073aa;
|
115 |
+
}
|
116 |
+
a:hover,
|
117 |
+
a:active {
|
118 |
+
color: #00a0d2;
|
119 |
+
}
|
120 |
+
a:focus {
|
121 |
+
color: #124964;
|
122 |
+
-webkit-box-shadow:
|
123 |
+
0 0 0 1px #5b9dd9,
|
124 |
+
0 0 2px 1px rgba(30, 140, 190, .8);
|
125 |
+
box-shadow:
|
126 |
+
0 0 0 1px #5b9dd9,
|
127 |
+
0 0 2px 1px rgba(30, 140, 190, .8);
|
128 |
+
outline: none;
|
129 |
+
}
|
130 |
+
.button {
|
131 |
+
background: #f7f7f7;
|
132 |
+
border: 1px solid #ccc;
|
133 |
+
color: #555;
|
134 |
+
display: inline-block;
|
135 |
+
text-decoration: none;
|
136 |
+
font-size: 13px;
|
137 |
+
line-height: 26px;
|
138 |
+
height: 28px;
|
139 |
+
margin: 0;
|
140 |
+
padding: 0 10px 1px;
|
141 |
+
cursor: pointer;
|
142 |
+
-webkit-border-radius: 3px;
|
143 |
+
-webkit-appearance: none;
|
144 |
+
border-radius: 3px;
|
145 |
+
white-space: nowrap;
|
146 |
+
-webkit-box-sizing: border-box;
|
147 |
+
-moz-box-sizing: border-box;
|
148 |
+
box-sizing: border-box;
|
149 |
+
|
150 |
+
-webkit-box-shadow: 0 1px 0 #ccc;
|
151 |
+
box-shadow: 0 1px 0 #ccc;
|
152 |
+
vertical-align: top;
|
153 |
+
}
|
154 |
+
|
155 |
+
.button.button-large {
|
156 |
+
height: 30px;
|
157 |
+
line-height: 28px;
|
158 |
+
padding: 0 12px 2px;
|
159 |
+
}
|
160 |
+
|
161 |
+
.button:hover,
|
162 |
+
.button:focus {
|
163 |
+
background: #fafafa;
|
164 |
+
border-color: #999;
|
165 |
+
color: #23282d;
|
166 |
+
}
|
167 |
+
|
168 |
+
.button:focus {
|
169 |
+
border-color: #5b9dd9;
|
170 |
+
-webkit-box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
|
171 |
+
box-shadow: 0 0 3px rgba( 0, 115, 170, .8 );
|
172 |
+
outline: none;
|
173 |
+
}
|
174 |
+
|
175 |
+
.button:active {
|
176 |
+
background: #eee;
|
177 |
+
border-color: #999;
|
178 |
+
-webkit-box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
|
179 |
+
box-shadow: inset 0 2px 5px -3px rgba( 0, 0, 0, 0.5 );
|
180 |
+
-webkit-transform: translateY(1px);
|
181 |
+
-ms-transform: translateY(1px);
|
182 |
+
transform: translateY(1px);
|
183 |
+
}
|
184 |
+
|
185 |
+
</style>
|
186 |
+
</head>
|
187 |
+
<?php
|
188 |
+
}
|
189 |
+
|
190 |
+
/**
|
191 |
+
* Render login form by using native wp function wp_login_form
|
192 |
+
* return string
|
193 |
+
*/
|
194 |
// private function getLoginForm() {
|
195 |
// $this->getHeader();
|
196 |
// echo '<body id="error-page">';
|
210 |
// $this->getFooter();
|
211 |
// }
|
212 |
|
213 |
+
private function getFooter() {
|
214 |
+
echo '</html>';
|
215 |
+
}
|
216 |
+
|
217 |
+
/**
|
218 |
+
* Provides a simple login form for use anywhere within WordPress.
|
219 |
+
*
|
220 |
+
* The login format HTML is echoed by default. Pass a false value for `$echo` to return it instead.
|
221 |
+
*
|
222 |
+
* @since 3.0.0
|
223 |
+
*
|
224 |
+
* @param array $args {
|
225 |
+
* Optional. Array of options to control the form output. Default empty array.
|
226 |
+
*
|
227 |
+
* @type bool $echo Whether to display the login form or return the form HTML code.
|
228 |
+
* Default true (echo).
|
229 |
+
* @type string $redirect URL to redirect to. Must be absolute, as in "https://example.com/mypage/".
|
230 |
+
* Default is to redirect back to the request URI.
|
231 |
+
* @type string $form_id ID attribute value for the form. Default 'loginform'.
|
232 |
+
* @type string $label_username Label for the username or email address field. Default 'Username or Email Address'.
|
233 |
+
* @type string $label_password Label for the password field. Default 'Password'.
|
234 |
+
* @type string $label_remember Label for the remember field. Default 'Remember Me'.
|
235 |
+
* @type string $label_log_in Label for the submit button. Default 'Log In'.
|
236 |
+
* @type string $id_username ID attribute value for the username field. Default 'user_login'.
|
237 |
+
* @type string $id_password ID attribute value for the password field. Default 'user_pass'.
|
238 |
+
* @type string $id_remember ID attribute value for the remember field. Default 'rememberme'.
|
239 |
+
* @type string $id_submit ID attribute value for the submit button. Default 'wp-submit'.
|
240 |
+
* @type bool $remember Whether to display the "rememberme" checkbox in the form.
|
241 |
+
* @type string $value_username Default value for the username field. Default empty.
|
242 |
+
* @type bool $value_remember Whether the "Remember Me" checkbox should be checked by default.
|
243 |
+
* Default false (unchecked).
|
244 |
+
*
|
245 |
+
* }
|
246 |
+
* @return string|void String when retrieving.
|
247 |
+
*/
|
248 |
+
private function getLoginForm() {
|
249 |
+
|
250 |
+
$arguments = array(
|
251 |
+
'echo' => true,
|
252 |
+
// Default 'redirect' value takes the user back to the request URI.
|
253 |
+
'redirect' => ( is_ssl() ? 'https://' : 'http://' ) . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'],
|
254 |
+
'form_id' => 'loginform',
|
255 |
+
'label_username' => __( 'Username or Email Address' ),
|
256 |
+
'label_password' => __( 'Password' ),
|
257 |
+
'label_remember' => __( 'Remember Me' ),
|
258 |
+
'label_log_in' => __( 'Log In' ),
|
259 |
+
'id_username' => 'user_login',
|
260 |
+
'id_password' => 'user_pass',
|
261 |
+
'id_remember' => 'rememberme',
|
262 |
+
'id_submit' => 'wp-submit',
|
263 |
+
'remember' => true,
|
264 |
+
'value_username' => '',
|
265 |
+
// Set 'value_remember' to true to default the "Remember me" checkbox to checked.
|
266 |
+
'value_remember' => false
|
267 |
+
);
|
268 |
+
|
269 |
+
$args = empty( $this->args ) ? $arguments : $this->args;
|
270 |
+
|
271 |
+
$form = '
|
272 |
<form name="' . $args['form_id'] . '" id="' . $args['form_id'] . '" action="" method="post">
|
273 |
<p class="login-username">
|
274 |
<label for="' . esc_attr( $args['id_username'] ) . '">' . esc_html( $args['label_username'] ) . '</label>
|
290 |
|
291 |
</form>';
|
292 |
|
293 |
+
if( $args['echo'] )
|
294 |
+
echo $form;
|
295 |
+
else
|
296 |
+
return $form;
|
297 |
+
}
|
298 |
|
299 |
}
|
300 |
|
@@ -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.
|
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,26 @@ https://wp-staging.com
|
|
146 |
|
147 |
== Changelog ==
|
148 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
149 |
= 2.3.9 =
|
150 |
* New: Support for wp-config.php located in one level up of the root folder for multisites
|
151 |
* New: Allow exclusion of custom options from wp_options from beeing pushed
|
@@ -200,6 +220,6 @@ Complete changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-sta
|
|
200 |
|
201 |
== Upgrade Notice ==
|
202 |
|
203 |
-
= 2.
|
204 |
-
* New: Compatible to WordPress
|
205 |
|
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.4.0
|
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.4.0 =
|
150 |
+
* New: Compatible to WP 5.0.0 Gutenberg
|
151 |
+
* New: Increase file scanning process performance
|
152 |
+
* New: Preview for external database cloning
|
153 |
+
* New: Add delay between requests setting to prevent timeouts on rate limited servers
|
154 |
+
* New: Try again automatically cloning process if ajax request has been killed due to server ressource limit error
|
155 |
+
|
156 |
+
* Fix: Error when removing heartbeat api
|
157 |
+
* Fix: remove ? parameter from staging site
|
158 |
+
* Fix: Do not load theme while WP Staging is running. Prevents processing interruption if there are fatal errors in the theme
|
159 |
+
* Fix: When cloning has been canceled page needs to be reloaded before beeing able to clone again
|
160 |
+
* Fix: Under rare circumstances plugins are disabled when wp staging runs.
|
161 |
+
* Fix: Prevent error 503 (firewall/performance timeout) by adding post parameter to the ajax url
|
162 |
+
* Fix: Adding automatic resume function to the ajax processing to prevent cloning and pushing interruptions due to hitting server ressource or network glitches.
|
163 |
+
* Fix: Selected folders are not excluded under Windows IIS server
|
164 |
+
* Fix: Windows IIS server compatibilility issues resolved
|
165 |
+
|
166 |
+
|
167 |
+
|
168 |
+
|
169 |
= 2.3.9 =
|
170 |
* New: Support for wp-config.php located in one level up of the root folder for multisites
|
171 |
* New: Allow exclusion of custom options from wp_options from beeing pushed
|
220 |
|
221 |
== Upgrade Notice ==
|
222 |
|
223 |
+
= 2.4.0 =
|
224 |
+
* New: Compatible to WordPress 5.0.0. Important fixes!
|
225 |
|
@@ -7,7 +7,7 @@
|
|
7 |
* Author: WP-Staging
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi, ilgityildirim
|
10 |
-
* Version: 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.
|
55 |
}
|
56 |
|
57 |
/**
|
7 |
* Author: WP-Staging
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi, ilgityildirim
|
10 |
+
* Version: 2.4.0
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
|
51 |
|
52 |
// Version
|
53 |
if( !defined( 'WPSTG_VERSION' ) ) {
|
54 |
+
define( 'WPSTG_VERSION', '2.4.0' );
|
55 |
}
|
56 |
|
57 |
/**
|