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

Version Description

  • Fix: Cancel Cloning button not working
  • Fix: Limit max execution time to a maximum of 30sec to prevent high memory consumption and script timeouts
Download this release

Release Info

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

Code changes from version 2.0.1 to 2.0.6

Files changed (50) hide show
  1. CHANGELOG.md +0 -0
  2. CONTRIBUTING.md +0 -38
  3. LICENSE.txt → LICENSE +70 -10
  4. README.md +0 -32
  5. apps/Backend/Activation/Activation.php +61 -0
  6. apps/Backend/Activation/Welcome.php +44 -0
  7. apps/Backend/Administrator.php +624 -604
  8. apps/Backend/Modules/Jobs/Cloning.php +9 -3
  9. apps/Backend/Modules/Jobs/Data.php +1 -1
  10. apps/Backend/Modules/Jobs/Database.php +4 -0
  11. apps/Backend/Modules/Jobs/Delete.php +67 -38
  12. apps/Backend/Modules/Jobs/Delete_deprecated.php +397 -0
  13. apps/Backend/Modules/Jobs/Delete_new.php +382 -0
  14. apps/Backend/Modules/Jobs/Delete_old.php +4 -4
  15. apps/Backend/Modules/Jobs/Directories.php +155 -82
  16. apps/Backend/Modules/Jobs/Finish.php +3 -22
  17. apps/Backend/Modules/Jobs/Job.php +54 -13
  18. apps/Backend/Modules/Jobs/JobExecutable.php +1 -1
  19. apps/Backend/Modules/Jobs/Scan.php +49 -18
  20. apps/Backend/Modules/Optimizer.php +0 -141
  21. apps/Backend/Modules/Views/Forms/Settings.php +1 -2
  22. apps/Backend/Notices/Notices.php +62 -53
  23. apps/Backend/Optimizer/Optimizer.php +45 -0
  24. apps/Backend/Optimizer/wp-staging-optimizer.php +120 -0
  25. apps/Backend/Pluginmeta/Pluginmeta.php +69 -0
  26. apps/Backend/Upgrade/Upgrade.php +125 -37
  27. apps/Backend/public/css/wpstg-admin.css +100 -7
  28. apps/Backend/public/img/wpstaging-banner200x400-tryout.gif +0 -0
  29. apps/Backend/public/img/wpstaging-banner200x400.gif +0 -0
  30. apps/Backend/public/js/wpstg-admin.js +514 -450
  31. apps/Backend/views/_includes/header.php +1 -1
  32. apps/Backend/views/_includes/messages/beta.php +2 -2
  33. apps/Backend/views/_includes/messages/rating.php +2 -0
  34. apps/Backend/views/_includes/messages/wp-version-compatible-message.php +1 -1
  35. apps/Backend/views/clone/ajax/delete-confirmation.php +1 -1
  36. apps/Backend/views/clone/ajax/scan.php +10 -7
  37. apps/Backend/views/clone/ajax/start.php +1 -1
  38. apps/Backend/views/clone/index.php +1 -1
  39. apps/Backend/views/clone/single-site/index.php +2 -1
  40. apps/Backend/views/settings/index.php +2 -2
  41. apps/Backend/views/tools/index.php +1 -1
  42. apps/Backend/views/welcome/welcome.php +15 -0
  43. apps/Core/Cron/Cron.php +46 -0
  44. apps/Core/Utils/Cache.php +1 -1
  45. apps/Core/Utils/Logger.php +3 -1
  46. apps/Core/WPStaging.php +402 -386
  47. apps/Frontend/Frontend.php +0 -1
  48. readme.txt +235 -251
  49. uninstall.php +89 -39
  50. wp-staging.php +80 -56
CHANGELOG.md DELETED
File without changes
CONTRIBUTING.md DELETED
@@ -1,38 +0,0 @@
1
- #Contribute To WP Staging
2
-
3
- Community made patches, localisations, bug reports and contributions are always welcome.
4
-
5
- When contributing please ensure you follow the guidelines below so that we can keep on top of things.
6
-
7
- __Please Note:__ GitHub is for bug reports and contributions only.
8
-
9
- ## Getting Started
10
-
11
- * Submit a ticket for your issue, assuming one does not already exist.
12
- * Raise it on our [Issue Tracker](https://github.com/rene-hermenau/wp-staging/issues)
13
- * Clearly describe the issue including steps to reproduce the bug.
14
- * Make sure you fill in the earliest version that you know has the issue as well as the version of WordPress you're using.
15
-
16
- ## Making Changes
17
-
18
- * Fork the repository on GitHub
19
- * Make the changes to your forked repository
20
- * Ensure you stick to the [WordPress Coding Standards](https://codex.wordpress.org/WordPress_Coding_Standards)
21
- * When committing, reference your issue (if present) and include a note about the fix
22
- * (coming soon) If possible, and if applicable, please also add/update unit tests for your changes
23
- * Push the changes to your fork and submit a pull request to the 'master' branch of the WP Staging repository
24
-
25
- ## Code Documentation
26
-
27
- * We ensure that every WP Staging function is documented well and follows the standards set by phpDoc
28
- * An example function can be found [here](https://gist.github.com/rene-hermenau/8d3d7ee0633ee2f64b4b)
29
- * Please make sure that every function is documented so that when we update our API Documentation it will complete
30
- * If you're adding/editing a function in a class, make sure to add `@access {private|public|protected}`
31
- * Finally, please use tabs and not spaces. The tab indent size should be 4 for all WP Staging code.
32
-
33
- At this point you're waiting on us to merge your pull request. We'll review all pull requests, and make suggestions and changes if necessary.
34
-
35
- # Additional Resources
36
- * [General GitHub Documentation](http://help.github.com/)
37
- * [GitHub Pull Request documentation](http://help.github.com/send-pull-requests/)
38
- * [PHPUnit Tests Guide](http://phpunit.de/manual/current/en/writing-tests-for-phpunit.html)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
LICENSE.txt → LICENSE RENAMED
@@ -1,13 +1,12 @@
1
- GNU GENERAL PUBLIC LICENSE
2
- Version 2, June 1991
3
-
4
- Copyright (C) 1989, 1991 Free Software Foundation, Inc.
5
- 51 Franklin St, Fifth Floor, Boston, MA 02110, USA
6
 
 
 
7
  Everyone is permitted to copy and distribute verbatim copies
8
  of this license document, but changing it is not allowed.
9
 
10
- Preamble
11
 
12
  The licenses for most software are designed to take away your
13
  freedom to share and change it. By contrast, the GNU General Public
@@ -16,7 +15,7 @@ software--to make sure the software is free for all its users. This
16
  General Public License applies to most of the Free Software
17
  Foundation's software and to any other program whose authors commit to
18
  using it. (Some other Free Software Foundation software is covered by
19
- the GNU Library General Public License instead.) You can apply it to
20
  your programs, too.
21
 
22
  When we speak of free software, we are referring to freedom, not
@@ -57,7 +56,7 @@ patent must be licensed for everyone's free use or not licensed at all.
57
  The precise terms and conditions for copying, distribution and
58
  modification follow.
59
 
60
- GNU GENERAL PUBLIC LICENSE
61
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
62
 
63
  0. This License applies to any program or other work which contains
@@ -121,6 +120,7 @@ distribute the same sections as part of a whole which is a work based
121
  on the Program, the distribution of the whole must be on the terms of
122
  this License, whose permissions for other licensees extend to the
123
  entire whole, and thus to each and every part regardless of who wrote it.
 
124
  Thus, it is not the intent of this section to claim rights or contest
125
  your rights to work written entirely by you; rather, the intent is to
126
  exercise the right to control the distribution of derivative or
@@ -255,7 +255,7 @@ make exceptions for this. Our decision will be guided by the two goals
255
  of preserving the free status of all derivatives of our free software and
256
  of promoting the sharing and reuse of software generally.
257
 
258
- NO WARRANTY
259
 
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
  FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
@@ -277,4 +277,64 @@ YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277
  PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
  POSSIBILITY OF SUCH DAMAGES.
279
 
280
- END OF TERMS AND CONDITIONS
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ GNU GENERAL PUBLIC LICENSE
2
+ Version 2, June 1991
 
 
 
3
 
4
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
5
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6
  Everyone is permitted to copy and distribute verbatim copies
7
  of this license document, but changing it is not allowed.
8
 
9
+ Preamble
10
 
11
  The licenses for most software are designed to take away your
12
  freedom to share and change it. By contrast, the GNU General Public
15
  General Public License applies to most of the Free Software
16
  Foundation's software and to any other program whose authors commit to
17
  using it. (Some other Free Software Foundation software is covered by
18
+ the GNU Lesser General Public License instead.) You can apply it to
19
  your programs, too.
20
 
21
  When we speak of free software, we are referring to freedom, not
56
  The precise terms and conditions for copying, distribution and
57
  modification follow.
58
 
59
+ GNU GENERAL PUBLIC LICENSE
60
  TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61
 
62
  0. This License applies to any program or other work which contains
120
  on the Program, the distribution of the whole must be on the terms of
121
  this License, whose permissions for other licensees extend to the
122
  entire whole, and thus to each and every part regardless of who wrote it.
123
+
124
  Thus, it is not the intent of this section to claim rights or contest
125
  your rights to work written entirely by you; rather, the intent is to
126
  exercise the right to control the distribution of derivative or
255
  of preserving the free status of all derivatives of our free software and
256
  of promoting the sharing and reuse of software generally.
257
 
258
+ NO WARRANTY
259
 
260
  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261
  FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
277
  PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278
  POSSIBILITY OF SUCH DAMAGES.
279
 
280
+ END OF TERMS AND CONDITIONS
281
+
282
+ How to Apply These Terms to Your New Programs
283
+
284
+ If you develop a new program, and you want it to be of the greatest
285
+ possible use to the public, the best way to achieve this is to make it
286
+ free software which everyone can redistribute and change under these terms.
287
+
288
+ To do so, attach the following notices to the program. It is safest
289
+ to attach them to the start of each source file to most effectively
290
+ convey the exclusion of warranty; and each file should have at least
291
+ the "copyright" line and a pointer to where the full notice is found.
292
+
293
+ {description}
294
+ Copyright (C) {year} {fullname}
295
+
296
+ This program is free software; you can redistribute it and/or modify
297
+ it under the terms of the GNU General Public License as published by
298
+ the Free Software Foundation; either version 2 of the License, or
299
+ (at your option) any later version.
300
+
301
+ This program is distributed in the hope that it will be useful,
302
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
303
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304
+ GNU General Public License for more details.
305
+
306
+ You should have received a copy of the GNU General Public License along
307
+ with this program; if not, write to the Free Software Foundation, Inc.,
308
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309
+
310
+ Also add information on how to contact you by electronic and paper mail.
311
+
312
+ If the program is interactive, make it output a short notice like this
313
+ when it starts in an interactive mode:
314
+
315
+ Gnomovision version 69, Copyright (C) year name of author
316
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317
+ This is free software, and you are welcome to redistribute it
318
+ under certain conditions; type `show c' for details.
319
+
320
+ The hypothetical commands `show w' and `show c' should show the appropriate
321
+ parts of the General Public License. Of course, the commands you use may
322
+ be called something other than `show w' and `show c'; they could even be
323
+ mouse-clicks or menu items--whatever suits your program.
324
+
325
+ You should also get your employer (if you work as a programmer) or your
326
+ school, if any, to sign a "copyright disclaimer" for the program, if
327
+ necessary. Here is a sample; alter the names:
328
+
329
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
331
+
332
+ {signature of Ty Coon}, 1 April 1989
333
+ Ty Coon, President of Vice
334
+
335
+ This General Public License does not permit incorporating your program into
336
+ proprietary programs. If your program is a subroutine library, you may
337
+ consider it more useful to permit linking proprietary applications with the
338
+ library. If this is what you want to do, use the GNU Lesser General
339
+ Public License instead of this License.
340
+
README.md DELETED
@@ -1,32 +0,0 @@
1
- ### Welcome to the WP-Staging repository
2
-
3
- ## Note ##
4
-
5
- This is the latest developer version of WP-Staging for WordPress.
6
-
7
- ## Installation ##
8
-
9
- 1. You can clone the GitHub repository: `https://github.com/rene-hermenau/wp-staging.git`
10
- 2. Or download it directly as a ZIP file: `https://github.com/rene-hermenau/wp-staging/archive/master.zip`
11
- 3. Upload it via WordPress->Plugin->AddNew
12
-
13
- This will download the latest developer copy of WP-Staging.
14
-
15
- ## Bugs ##
16
- If you find an issue, let us know [here](https://github.com/rene-hermenau/wp-staging/issues?state=open)!
17
-
18
- ## Support ##
19
- This is a developer's portal for WP-Staging
20
-
21
- ## Contributions ##
22
- Anyone is welcome to contribute to WP-Staging. Please read the [guidelines for contributing](https://github.com/rene-hermenau/wp-staging/blob/master/CONTRIBUTING.md) to this repository.
23
-
24
- There are various ways you can contribute:
25
-
26
- 1. Raise an [Issue](https://github.com/rene-hermenau/wp-staging/issues) on GitHub
27
- 2. Send us a Pull Request with your bug fixes and/or new features
28
- 3. Translate WP-Staging into different languages
29
- 4. Provide feedback and suggestions on [enhancements](https://github.com/rene-hermenau/wp-staging/issues?direction=desc&labels=Enhancement&page=1&sort=created&state=open)
30
-
31
- ## Contributors ##
32
- [@rene-hermenau](https://github.com/rene-hermenau), [@ilgityildirim](https://github.com/ilgityildirim)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
apps/Backend/Activation/Activation.php ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Activation;
4
+
5
+ // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
8
+ }
9
+
10
+ use WPStaging\WPStaging;
11
+ use WPStaging\Backend\Optimizer\Optimizer;
12
+ use WPStaging\Cron\Cron;
13
+
14
+ class Activation {
15
+
16
+ /**
17
+ * Checks if another version of WPSTG (Pro) is active and deactivates it.
18
+ * To be hooked on `activated_plugin` so other plugin is deactivated when current plugin is activated.
19
+ *
20
+ * @param string $plugin
21
+ *
22
+ */
23
+ public static function deactivate_other_instances( $plugin ) {
24
+ if( !in_array( basename( $plugin ), array('wp-staging-pro.php', 'wp-staging.php') ) ) {
25
+ return;
26
+ }
27
+ $plugin_to_deactivate = 'wp-staging.php';
28
+ $deactivated_notice_id = '1';
29
+ if( basename( $plugin ) == $plugin_to_deactivate ) {
30
+ $plugin_to_deactivate = 'wp-staging-pro.php';
31
+ $deactivated_notice_id = '2';
32
+ }
33
+ if( is_multisite() ) {
34
+ $active_plugins = ( array ) get_site_option( 'active_sitewide_plugins', array() );
35
+ $active_plugins = array_keys( $active_plugins );
36
+ } else {
37
+ $active_plugins = ( array ) get_option( 'active_plugins', array() );
38
+ }
39
+ foreach ( $active_plugins as $basename ) {
40
+ if( false !== strpos( $basename, $plugin_to_deactivate ) ) {
41
+ set_transient( 'wp_staging_deactivated_notice_id', $deactivated_notice_id, 1 * HOUR_IN_SECONDS );
42
+ deactivate_plugins( $basename );
43
+ return;
44
+ }
45
+ }
46
+ }
47
+
48
+ public static function install_dependancies() {
49
+ // Register cron job.
50
+ $cron = new \WPStaging\Cron\Cron;
51
+ $cron->schedule_event();
52
+
53
+ // Install Optimizer
54
+ $optimizer = new Optimizer();
55
+ $optimizer->installOptimizer();
56
+
57
+ // Add the transient to redirect for class Welcome (not for multisites)
58
+ set_transient( 'wpstg_activation_redirect', true, 3600 );
59
+ }
60
+
61
+ }
apps/Backend/Activation/Welcome.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Activation;
4
+
5
+ // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
8
+ }
9
+
10
+ class Welcome {
11
+
12
+ public function __construct() {
13
+ add_action( 'admin_init', array( $this, 'welcome' ) );
14
+ }
15
+
16
+
17
+
18
+ /**
19
+ * Sends user to the welcome page on first activation of WPSTG as well as each
20
+ * time WPSTG is upgraded to a new version
21
+ *
22
+ * @access public
23
+ * @since 1.0.1
24
+ * @return void
25
+ */
26
+ public function welcome() {
27
+ // Bail if no activation redirect
28
+ if ( false === get_transient( 'wpstg_activation_redirect' ) ){
29
+ return;
30
+ }
31
+
32
+ // Delete the redirect transient
33
+ delete_transient( 'wpstg_activation_redirect' );
34
+
35
+ // Bail if activating from network, or bulk
36
+ if ( is_network_admin() || isset( $_GET['activate-multi'] ) ){
37
+ return;
38
+ }
39
+
40
+ wp_safe_redirect( admin_url( 'admin.php?page=wpstg-welcome' ) ); exit;
41
+ }
42
+
43
+
44
+ }
apps/Backend/Administrator.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  namespace WPStaging\Backend;
3
 
4
  // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
  }
9
 
10
  use WPStaging\Backend\Modules\Jobs\Cancel;
@@ -21,611 +21,631 @@ use WPStaging\Backend\Modules\Views\Tabs\Tabs;
21
  use WPStaging\Backend\Notices\Notices;
22
  use WPStaging\DI\InjectionAware;
23
  use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
 
24
  use WPStaging\WPStaging;
 
 
25
 
26
  /**
27
  * Class Administrator
28
  * @package WPStaging\Backend
29
  */
30
- class Administrator extends InjectionAware
31
- {
32
-
33
- /**
34
- * @var string
35
- */
36
- private $path;
37
-
38
- /**
39
- * @var string
40
- */
41
- private $url;
42
-
43
- /**
44
- * Initialize class
45
- */
46
- public function initialize()
47
- {
48
- $this->defineHooks();
49
-
50
- // Path to backend
51
- $this->path = plugin_dir_path(__FILE__);
52
-
53
- // URL to public backend folder
54
- $this->url = plugin_dir_url(__FILE__) . "public/";
55
-
56
- }
57
-
58
- /**
59
- * Define Hooks
60
- */
61
- private function defineHooks()
62
- {
63
- // Get loader
64
- $loader = $this->di->get("loader");
65
-
66
- $loader->addAction("admin_menu", $this, "addMenu", 10);
67
- $loader->addAction("admin_init", $this, "setOptionFormElements");
68
- $loader->addAction("admin_init", $this, "upgrade");
69
- $loader->addAction("admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload");
70
- $loader->addAction("admin_post_wpstg_export", $this, "export");
71
- $loader->addAction("admin_post_wpstg_import_settings", $this, "import");
72
- $loader->addAction("admin_notices", $this, "messages");
73
-
74
- // Settings
75
- $settings = $this->di->get("settings");
76
-
77
- // Optimizer is ON
78
- if ($settings->isOptimizer())
79
- {
80
- $optimizer = new Optimizer($this->di);
81
-
82
- $loader->addAction("admin_init", $optimizer, "compatibility", 1);
83
- $loader->addFilter("option_active_plugins", $optimizer, "excludedPlugins");
84
- $loader->addFilter("site_option_active_sitewide_plugins", $optimizer, "excludedPlugins");
85
- }
86
-
87
- // Ajax Requests
88
- $loader->addAction("wp_ajax_wpstg_overview", $this, "ajaxOverview");
89
- $loader->addAction("wp_ajax_wpstg_scanning", $this, "ajaxScan");
90
- $loader->addAction("wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName");
91
- $loader->addAction("wp_ajax_wpstg_cloning", $this, "ajaxStartClone");
92
- $loader->addAction("wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase");
93
- $loader->addAction("wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories");
94
- $loader->addAction("wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles");
95
- $loader->addAction("wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData");
96
- $loader->addAction("wp_ajax_wpstg_clone_finish", $this, "ajaxFinish");
97
- $loader->addAction("wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation");
98
- $loader->addAction("wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone");
99
- $loader->addAction("wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone");
100
- $loader->addAction("wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll");
101
- $loader->addAction("wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating");
102
- $loader->addAction("wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta");
103
- $loader->addAction("wp_ajax_wpstg_logs", $this, "ajaxLogs");
104
- $loader->addAction("wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace");
105
- }
106
-
107
- /**
108
- * Register options form elements
109
- */
110
- public function setOptionFormElements()
111
- {
112
- register_setting("wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions"));
113
- }
114
-
115
- /**
116
- * Upgrade routine
117
- */
118
- public function upgrade(){
119
- $upgrade = new Upgrade\Upgrade();
120
- $upgrade->doUpgrade();
121
- }
122
-
123
- /**
124
- * Sanitize options data and delete the cache
125
- * @param array $data
126
- * @return array
127
- */
128
- public function sanitizeOptions($data = array())
129
- {
130
- $sanitized = $this->sanitizeData($data);
131
-
132
- add_settings_error("wpstg-notices", '', __("Settings updated.", "wpstg"), "updated");
133
-
134
- // Return sanitized data
135
- //return $sanitized;
136
- return apply_filters("wpstg-settings", $sanitized, $data);
137
- }
138
-
139
- /**
140
- * @param array $data
141
- * @return array
142
- */
143
- private function sanitizeData($data = array())
144
- {
145
- $sanitized = array();
146
-
147
- foreach ($data as $key => $value)
148
- {
149
- $sanitized[$key] = (is_array($value)) ? $this->sanitizeData($value) : htmlspecialchars($value);
150
- }
151
-
152
- return $sanitized;
153
- }
154
-
155
- /**
156
- * Add Admin Menu(s)
157
- */
158
- public function addMenu()
159
- {
160
- // Main WP Staging Menu
161
- add_menu_page(
162
- "WP-Staging",
163
- __("WP Staging", "wpstg"),
164
- "manage_options",
165
- "wpstg_clone",
166
- array($this, "getClonePage"),
167
- "dashicons-hammer"
168
- );
169
-
170
- // Page: Clone
171
- add_submenu_page(
172
- "wpstg_clone",
173
- __("WP Staging Jobs", "wpstg"),
174
- __("Start", "wpstg"),
175
- "manage_options",
176
- "wpstg_clone",
177
- array($this, "getClonePage")
178
- );
179
-
180
- // Page: Settings
181
- add_submenu_page(
182
- "wpstg_clone",
183
- __("WP Staging Settings", "wpstg"),
184
- __("Settings", "wpstg"),
185
- "manage_options",
186
- "wpstg-settings",
187
- array($this, "getSettingsPage")
188
- );
189
-
190
- // Page: Tools
191
- add_submenu_page(
192
- "wpstg_clone",
193
- __("WP Staging Tools", "wpstg"),
194
- __("Tools", "wpstg"),
195
- "manage_options",
196
- "wpstg-tools",
197
- array($this, "getToolsPage")
198
- );
199
- }
200
-
201
- /**
202
- * Settings Page
203
- */
204
- public function getSettingsPage()
205
- {
206
- // Tabs
207
- $tabs = new Tabs(array(
208
- "general" => __("General", "wpstg")
209
- ));
210
-
211
-
212
- $this->di
213
- // Set tabs
214
- ->set("tabs", $tabs)
215
- // Forms
216
- ->set("forms", new FormSettings($tabs));
217
-
218
- require_once "{$this->path}views/settings/index.php";
219
- }
220
-
221
- /**
222
- * Clone Page
223
- */
224
- public function getClonePage()
225
- {
226
- // Existing clones
227
- $availableClones = get_option("wpstg_existing_clones", array());
228
-
229
- require_once "{$this->path}views/clone/index.php";
230
- }
231
-
232
- /**
233
- * Tools Page
234
- */
235
- public function getToolsPage()
236
- {
237
- // Tabs
238
- $tabs = new Tabs(array(
239
- "import_export" => __("Import/Export", "wpstg"),
240
- "system_info" => __("System Info", "wpstg")
241
- ));
242
-
243
- $this->di->set("tabs", $tabs);
244
-
245
- $this->di->set("systemInfo", new SystemInfo($this->di));
246
-
247
- require_once "{$this->path}views/tools/index.php";
248
- }
249
-
250
- /**
251
- * System Information Download
252
- */
253
- public function systemInfoDownload()
254
- {
255
- if (!current_user_can("update_plugins"))
256
- {
257
- return;
258
- }
259
-
260
- nocache_headers();
261
- header("Content-Type: text/plain");
262
- header("Content-Disposition: attachment; filename='wpstg-system-info.txt'");
263
- echo wp_strip_all_tags(new SystemInfo($this->di));
264
- }
265
-
266
- /**
267
- * Import JSON settings file
268
- */
269
- public function import()
270
- {
271
- if (empty($_POST["wpstg_import_nonce"]))
272
- {
273
- return;
274
- }
275
-
276
- if (!wp_verify_nonce($_POST["wpstg_import_nonce"], "wpstg_import_nonce"))
277
- {
278
- return;
279
- }
280
-
281
- if (!current_user_can("update_plugins"))
282
- {
283
- return;
284
- }
285
-
286
- $fileExtension = explode('.', $_FILES["import_file"]["name"]);
287
- $fileExtension = end($fileExtension);
288
- if ("json" !== $fileExtension)
289
- {
290
- wp_die("Please upload a valid .json file", "wpstg");
291
- }
292
-
293
-
294
- $importFile = $_FILES["import_file"]["tmp_name"];
295
-
296
- if (empty($importFile))
297
- {
298
- wp_die(__("Please upload a file to import", "wpstg"));
299
- }
300
-
301
- update_option("wpstg_settings", json_decode(file_get_contents($importFile, true)));
302
-
303
- wp_safe_redirect(admin_url("admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported"));
304
-
305
- return;
306
- }
307
-
308
- /**
309
- * Export settings to JSON file
310
- */
311
- public function export()
312
- {
313
- if (empty($_POST["wpstg_export_nonce"]))
314
- {
315
- return;
316
- }
317
-
318
- if (!wp_verify_nonce($_POST["wpstg_export_nonce"], "wpstg_export_nonce"))
319
- {
320
- return;
321
- }
322
-
323
- if (!current_user_can("manage_options"))
324
- {
325
- return;
326
- }
327
-
328
- $settings = get_option("wpstg_settings", array());
329
-
330
- ignore_user_abort(true);
331
-
332
- if (!in_array("set_time_limit", explode(',', ini_get("disable_functions"))) && !@ini_get("safe_mode"))
333
- {
334
- set_time_limit(0);
335
- }
336
-
337
- $fileName = apply_filters("wpstg_settings_export_filename", "wpstg-settings-export-" . date("m-d-Y")) . ".json";
338
-
339
- nocache_headers();
340
- header("Content-Type: application/json; charset=utf-8");
341
- header("Content-Disposition: attachment; filename={$fileName}");
342
- header("Expires: 0");
343
-
344
- echo json_encode($settings);
345
- }
346
-
347
-
348
- /**
349
- * Render a view file
350
- * @param string $file
351
- * @param array $vars
352
- * @return string
353
- */
354
- public function render($file, $vars = array())
355
- {
356
- $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
357
- $fullPath = str_replace(array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php");
358
-
359
- if (!file_exists($fullPath) || !is_readable($fullPath))
360
- {
361
- return "Can't render : {$fullPath} either file doesn't exist or can't read it";
362
- }
363
-
364
- $contents = @file_get_contents($fullPath);
365
-
366
- // Variables are set
367
- if (count($vars) > 0)
368
- {
369
- $vars = array_combine(
370
- array_map(function ($key)
371
- {
372
  return "{{" . $key . "}}";
373
- },
374
- array_keys($vars)
375
- ),
376
- $vars
377
- );
378
-
379
- $contents = str_replace(array_keys($vars), array_values($vars), $contents);
380
- }
381
-
382
- return $contents;
383
- }
384
-
385
- /**
386
- * Ajax Overview
387
- */
388
- public function ajaxOverview()
389
- {
390
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
391
-
392
- // Existing clones
393
- $availableClones = get_option("wpstg_existing_clones", array());
394
-
395
- require_once "{$this->path}views/clone/ajax/single-overview.php";
396
-
397
- wp_die();
398
- }
399
-
400
- /**
401
- * Ajax Scan
402
- */
403
- public function ajaxScan()
404
- {
405
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
406
-
407
- // Scan
408
- $scan = new Scan();
409
- $scan->start();
410
-
411
- // Get Options
412
- $options = $scan->getOptions();
413
-
414
- require_once "{$this->path}views/clone/ajax/scan.php";
415
-
416
- wp_die();
417
- }
418
-
419
- /**
420
- * Ajax Check Clone Name
421
- */
422
- public function ajaxCheckCloneName()
423
- {
424
- $cloneName = sanitize_key($_POST["cloneID"]);
425
- $cloneNameLength = strlen($cloneName);
426
- $clones = get_option("wpstg_existing_clones", array());
427
-
428
- // Check clone name length
429
- if ($cloneNameLength < 1 || $cloneNameLength > 16)
430
- {
431
- echo wp_send_json(array(
432
- "status" => "failed",
433
- "message" => "Clone name must be between 1 - 16 characters"
434
- ));
435
- }
436
- elseif (array_key_exists($cloneName, $clones))
437
- {
438
- echo wp_send_json(array(
439
- "status" => "failed",
440
- "message" => "Clone name is already in use, please choose an another clone name"
441
- ));
442
- }
443
-
444
- echo wp_send_json(array("status" => "success"));
445
- }
446
-
447
- /**
448
- * Ajax Start Clone (Basically just layout and saving data)
449
- */
450
- public function ajaxStartClone()
451
- {
452
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
453
-
454
- $cloning = new Cloning();
455
-
456
- if (!$cloning->save())
457
- {
458
- wp_die();
459
- }
460
-
461
- require_once "{$this->path}views/clone/ajax/start.php";
462
-
463
- wp_die();
464
- }
465
-
466
- /**
467
- * Ajax Clone Database
468
- */
469
- public function ajaxCloneDatabase()
470
- {
471
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
472
-
473
- $cloning = new Cloning();
474
-
475
- wp_send_json($cloning->start());
476
- }
477
-
478
- /**
479
- * Ajax Prepare Directories (get listing of files)
480
- */
481
- public function ajaxPrepareDirectories()
482
- {
483
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
484
-
485
- $cloning = new Cloning();
486
-
487
- wp_send_json($cloning->start());
488
- }
489
-
490
- /**
491
- * Ajax Clone Files
492
- */
493
- public function ajaxCopyFiles()
494
- {
495
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
496
-
497
- $cloning = new Cloning();
498
-
499
- wp_send_json($cloning->start());
500
- }
501
-
502
- /**
503
- * Ajax Replace Data
504
- */
505
- public function ajaxReplaceData()
506
- {
507
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
508
-
509
- $cloning = new Cloning();
510
-
511
- wp_send_json($cloning->start());
512
- }
513
-
514
- /**
515
- * Ajax Finish
516
- */
517
- public function ajaxFinish()
518
- {
519
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
520
-
521
- $cloning = new Cloning();
522
-
523
- wp_send_json($cloning->start());
524
- }
525
-
526
- /**
527
- * Ajax Delete Confirmation
528
- */
529
- public function ajaxDeleteConfirmation()
530
- {
531
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
532
-
533
- $delete = new Delete();
534
- $delete->setData();
535
-
536
- $clone = $delete->getClone();
537
-
538
- require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
539
-
540
- wp_die();
541
- }
542
-
543
- /**
544
- * Delete clone
545
- */
546
- public function ajaxDeleteClone()
547
- {
548
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
549
-
550
- $delete = new Delete();
551
- wp_send_json($delete->start());
552
- }
553
-
554
- /**
555
- * Delete clone
556
- */
557
- public function ajaxCancelClone()
558
- {
559
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
560
-
561
- $cancel = new Cancel();
562
- wp_send_json($cancel->start());
563
- }
564
-
565
- /**
566
- * Admin Messages
567
- */
568
- public function messages()
569
- {
570
- $notice = new Notices($this->path, $this->url);
571
-
572
- $run = $notice->messages();
573
- }
574
-
575
- /**
576
- * Ajax Hide Poll
577
- * @return mixed boolean | json
578
- */
579
- public function ajaxHidePoll()
580
- {
581
- if( false !== update_option( "wpstg_poll", "no" ) ) {
582
- wp_send_json( true );
583
- }
584
- return wp_send_json();
585
- }
586
-
587
- /**
588
- * Ajax Hide Rating
589
- * @return mixed bool | json
590
- */
591
- public function ajaxHideRating()
592
- {
593
- if( false !== update_option( "wpstg_rating", "no" ) ) {
594
- wp_send_json( true );
595
- }
596
- return wp_send_json();
597
- }
598
-
599
- /**
600
- * Ajax Hide Beta
601
- */
602
- public function ajaxHideBeta()
603
- {
604
- wp_send_json(update_option("wpstg_beta", "no"));
605
- }
606
-
607
- /**
608
- * Clone logs
609
- */
610
- public function ajaxLogs()
611
- {
612
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
613
-
614
- $logs = new Logs();
615
- wp_send_json($logs->start());
616
- }
617
-
618
- /**
619
- * Ajax Checks Free Disk Space
620
- */
621
- public function ajaxCheckFreeSpace()
622
- {
623
- check_ajax_referer("wpstg_ajax_nonce", "nonce");
624
-
625
- $scan = new Scan();
626
- return $scan->hasFreeDiskSpace();
627
- }
628
-
629
-
630
-
631
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+
3
  namespace WPStaging\Backend;
4
 
5
  // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
 
8
  }
9
 
10
  use WPStaging\Backend\Modules\Jobs\Cancel;
21
  use WPStaging\Backend\Notices\Notices;
22
  use WPStaging\DI\InjectionAware;
23
  use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
24
+ use WPStaging\Backend\Activation;
25
  use WPStaging\WPStaging;
26
+ use WPStaging\Backend\Pro\Modules\Jobs\Processing;
27
+ use WPStaging\Backend\Pro\Licensing;
28
 
29
  /**
30
  * Class Administrator
31
  * @package WPStaging\Backend
32
  */
33
+ class Administrator extends InjectionAware {
34
+
35
+ /**
36
+ * @var string
37
+ */
38
+ private $path;
39
+
40
+ /**
41
+ * @var string
42
+ */
43
+ private $url;
44
+
45
+ /**
46
+ * Initialize class
47
+ */
48
+ public function initialize() {
49
+ $this->defineHooks();
50
+
51
+ // Path to backend
52
+ $this->path = plugin_dir_path( __FILE__ );
53
+
54
+ // URL to public backend folder
55
+ $this->url = plugin_dir_url( __FILE__ ) . "public/";
56
+
57
+ // Load plugins meta data
58
+ $this->loadMeta();
59
+ }
60
+
61
+ /**
62
+ * Load plugn meta data
63
+ */
64
+ public function loadMeta() {
65
+ $run = new \WPStaging\Backend\Pluginmeta\Pluginmeta();
66
+ }
67
+
68
+ /**
69
+ * Define Hooks
70
+ */
71
+ private function defineHooks() {
72
+ // Get loader
73
+ $loader = $this->di->get( "loader" );
74
+
75
+ $Activation = new \WPStaging\Backend\Activation\Activation();
76
+
77
+ $Welcome = new Activation\Welcome();
78
+
79
+ $loader->addAction( "activated_plugin", $Activation, 'deactivate_other_instances' );
80
+ $loader->addAction( "admin_menu", $this, "addMenu", 10 );
81
+ $loader->addAction( "admin_init", $this, "setOptionFormElements" );
82
+ $loader->addAction( "admin_init", $this, "upgrade" );
83
+ $loader->addAction( "admin_post_wpstg_download_sysinfo", $this, "systemInfoDownload" );
84
+ $loader->addAction( "admin_post_wpstg_export", $this, "export" );
85
+ $loader->addAction( "admin_post_wpstg_import_settings", $this, "import" );
86
+ $loader->addAction( "admin_notices", $this, "messages" );
87
+
88
+ // Settings
89
+ $settings = $this->di->get( "settings" );
90
+
91
+ // Optimizer is ON
92
+ if( $settings->isOptimizer() ) {
93
+ $optimizer = new Optimizer( $this->di );
94
+
95
+ $loader->addAction( "admin_init", $optimizer, "compatibility", 1 );
96
+ $loader->addFilter( "option_active_plugins", $optimizer, "excludedPlugins" );
97
+ $loader->addFilter( "site_option_active_sitewide_plugins", $optimizer, "excludedPlugins" );
98
+ }
99
+
100
+ // Ajax Requests
101
+ $loader->addAction( "wp_ajax_wpstg_overview", $this, "ajaxOverview" );
102
+ $loader->addAction( "wp_ajax_wpstg_scanning", $this, "ajaxScan" );
103
+ $loader->addAction( "wp_ajax_wpstg_check_clone", $this, "ajaxcheckCloneName" );
104
+ $loader->addAction( "wp_ajax_wpstg_cloning", $this, "ajaxStartClone" );
105
+ $loader->addAction( "wp_ajax_wpstg_clone_database", $this, "ajaxCloneDatabase" );
106
+ $loader->addAction( "wp_ajax_wpstg_clone_prepare_directories", $this, "ajaxPrepareDirectories" );
107
+ $loader->addAction( "wp_ajax_wpstg_clone_files", $this, "ajaxCopyFiles" );
108
+ $loader->addAction( "wp_ajax_wpstg_clone_replace_data", $this, "ajaxReplaceData" );
109
+ $loader->addAction( "wp_ajax_wpstg_clone_finish", $this, "ajaxFinish" );
110
+ $loader->addAction( "wp_ajax_wpstg_confirm_delete_clone", $this, "ajaxDeleteConfirmation" );
111
+ $loader->addAction( "wp_ajax_wpstg_delete_clone", $this, "ajaxDeleteClone" );
112
+ $loader->addAction( "wp_ajax_wpstg_cancel_clone", $this, "ajaxCancelClone" );
113
+ $loader->addAction( "wp_ajax_wpstg_hide_poll", $this, "ajaxHidePoll" );
114
+ $loader->addAction( "wp_ajax_wpstg_hide_rating", $this, "ajaxHideRating" );
115
+ $loader->addAction( "wp_ajax_wpstg_hide_beta", $this, "ajaxHideBeta" );
116
+ $loader->addAction( "wp_ajax_wpstg_logs", $this, "ajaxLogs" );
117
+ $loader->addAction( "wp_ajax_wpstg_check_disk_space", $this, "ajaxCheckFreeSpace" );
118
+
119
+ // Ajax hooks pro Version
120
+ $loader->addAction( "wp_ajax_wpstg_start_processing", $this, "ajaxProcessing" );
121
+ $loader->addAction( "wp_ajax_wpstg_push_changes", $this, "ajaxPushChanges" );
122
+ }
123
+
124
+ /**
125
+ * Register options form elements
126
+ */
127
+ public function setOptionFormElements() {
128
+ register_setting( "wpstg_settings", "wpstg_settings", array($this, "sanitizeOptions") );
129
+ }
130
+
131
+ /**
132
+ * Upgrade routine
133
+ */
134
+ public function upgrade() {
135
+ $upgrade = new Upgrade\Upgrade();
136
+ $upgrade->doUpgrade();
137
+ }
138
+
139
+ /**
140
+ * Sanitize options data and delete the cache
141
+ * @param array $data
142
+ * @return array
143
+ */
144
+ public function sanitizeOptions( $data = array() ) {
145
+ $sanitized = $this->sanitizeData( $data );
146
+
147
+ add_settings_error( "wpstg-notices", '', __( "Settings updated.", "wpstg" ), "updated" );
148
+
149
+ // Return sanitized data
150
+ //return $sanitized;
151
+ return apply_filters( "wpstg-settings", $sanitized, $data );
152
+ }
153
+
154
+ /**
155
+ * @param array $data
156
+ * @return array
157
+ */
158
+ private function sanitizeData( $data = array() ) {
159
+ $sanitized = array();
160
+
161
+ foreach ( $data as $key => $value ) {
162
+ $sanitized[$key] = (is_array( $value )) ? $this->sanitizeData( $value ) : htmlspecialchars( $value );
163
+ }
164
+
165
+ return $sanitized;
166
+ }
167
+
168
+ /**
169
+ * Add Admin Menu(s)
170
+ */
171
+ public function addMenu() {
172
+
173
+ $logo = 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4KPHN2ZyB2ZXJzaW9uPSIxLjEiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgMTAwMCAxMDAwIiBlbmFibGUtYmFja2dyb3VuZD0ibmV3IDAgMCAxMDAwIDEwMDAiIHhtbDpzcGFjZT0icHJlc2VydmUiIGZpbGw9Im5vbmUiPgo8Zz48Zz48cGF0aCBzdHlsZT0iZmlsbDojZmZmIiAgZD0iTTEzNy42LDU2MS4zSDEzLjhIMTB2MzA2LjNsOTAuNy04My40QzE4OS42LDkwOC43LDMzNS4zLDk5MCw1MDAsOTkwYzI0OS45LDAsNDU2LjEtMTg3LjEsNDg2LjItNDI4LjhIODYyLjRDODMzLjMsNzM1LjEsNjgyLjEsODY3LjUsNTAwLDg2Ny41Yy0xMjksMC0yNDIuNS02Ni41LTMwOC4xLTE2Ny4ybDE1MS4zLTEzOS4xSDEzNy42eiIvPjxwYXRoIHN0eWxlPSJmaWxsOiNmZmYiICBkPSJNNTAwLDEwQzI1MC4xLDEwLDQzLjksMTk3LjEsMTMuOCw0MzguOGgxMjMuOEMxNjYuNywyNjQuOSwzMTcuOSwxMzIuNSw1MDAsMTMyLjVjMTMyLjksMCwyNDkuMyw3MC41LDMxMy44LDE3Ni4yTDY4My44LDQzOC44aDEyMi41aDU2LjJoMTIzLjhoMy44VjEzMi41bC04Ny43LDg3LjdDODEzLjgsOTMuMSw2NjYuNiwxMCw1MDAsMTB6Ii8+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjxnPjwvZz48Zz48L2c+PGc+PC9nPjwvZz4KPC9zdmc+';
174
+
175
+ // Main WP Staging Menu
176
+ add_menu_page(
177
+ "WP-Staging", __( "WP Staging", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage"), $logo
178
+ );
179
+
180
+ // Page: Clone
181
+ add_submenu_page(
182
+ "wpstg_clone", __( "WP Staging Jobs", "wpstg" ), __( "Start", "wpstg" ), "manage_options", "wpstg_clone", array($this, "getClonePage")
183
+ );
184
+
185
+ // Page: Settings
186
+ add_submenu_page(
187
+ "wpstg_clone", __( "WP Staging Settings", "wpstg" ), __( "Settings", "wpstg" ), "manage_options", "wpstg-settings", array($this, "getSettingsPage")
188
+ );
189
+
190
+ // Page: Tools
191
+ add_submenu_page(
192
+ "wpstg_clone", __( "WP Staging Tools", "wpstg" ), __( "Tools", "wpstg" ), "manage_options", "wpstg-tools", array($this, "getToolsPage")
193
+ );
194
+ // Page: Tools
195
+ add_submenu_page(
196
+ "wpstg_clone", __( "WP Staging Welcome", "wpstg" ), __( "Get WP Staging Pro", "wpstg" ), "manage_options", "wpstg-welcome", array($this, "getWelcomePage")
197
+ );
198
+
199
+ if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
200
+ // Page: License
201
+ add_submenu_page(
202
+ "wpstg_clone", __( "WP Staging License", "wpstg" ), __( "License", "wpstg" ), "manage_options", "wpstg-license", array($this, "getLicensePage")
203
+ );
204
+ }
205
+ }
206
+
207
+ /**
208
+ * Settings Page
209
+ */
210
+ public function getSettingsPage() {
211
+ // Tabs
212
+ $tabs = new Tabs( array(
213
+ "general" => __( "General", "wpstg" )
214
+ ) );
215
+
216
+
217
+ $this->di
218
+ // Set tabs
219
+ ->set( "tabs", $tabs )
220
+ // Forms
221
+ ->set( "forms", new FormSettings( $tabs ) );
222
+
223
+ require_once "{$this->path}views/settings/index.php";
224
+ }
225
+
226
+ /**
227
+ * Clone Page
228
+ */
229
+ public function getClonePage() {
230
+ // Existing clones
231
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
232
+
233
+ require_once "{$this->path}views/clone/index.php";
234
+ }
235
+
236
+ /**
237
+ * Welcome Page
238
+ */
239
+ public function getWelcomePage() {
240
+ require_once "{$this->path}views/welcome/welcome.php";
241
+ }
242
+
243
+ /**
244
+ * Tools Page
245
+ */
246
+ public function getToolsPage() {
247
+ // Tabs
248
+ $tabs = new Tabs( array(
249
+ "import_export" => __( "Import/Export", "wpstg" ),
250
+ "system_info" => __( "System Info", "wpstg" )
251
+ ) );
252
+
253
+ $this->di->set( "tabs", $tabs );
254
+
255
+ $this->di->set( "systemInfo", new SystemInfo( $this->di ) );
256
+
257
+ require_once "{$this->path}views/tools/index.php";
258
+ }
259
+
260
+ /**
261
+ * System Information Download
262
+ */
263
+ public function systemInfoDownload() {
264
+ if( !current_user_can( "update_plugins" ) ) {
265
+ return;
266
+ }
267
+
268
+ nocache_headers();
269
+ header( "Content-Type: text/plain" );
270
+ header( "Content-Disposition: attachment; filename='wpstg-system-info.txt'" );
271
+ echo wp_strip_all_tags( new SystemInfo( $this->di ) );
272
+ }
273
+
274
+ /**
275
+ * Import JSON settings file
276
+ */
277
+ public function import() {
278
+ if( empty( $_POST["wpstg_import_nonce"] ) ) {
279
+ return;
280
+ }
281
+
282
+ if( !wp_verify_nonce( $_POST["wpstg_import_nonce"], "wpstg_import_nonce" ) ) {
283
+ return;
284
+ }
285
+
286
+ if( !current_user_can( "update_plugins" ) ) {
287
+ return;
288
+ }
289
+
290
+ $fileExtension = explode( '.', $_FILES["import_file"]["name"] );
291
+ $fileExtension = end( $fileExtension );
292
+ if( "json" !== $fileExtension ) {
293
+ wp_die( "Please upload a valid .json file", "wpstg" );
294
+ }
295
+
296
+
297
+ $importFile = $_FILES["import_file"]["tmp_name"];
298
+
299
+ if( empty( $importFile ) ) {
300
+ wp_die( __( "Please upload a file to import", "wpstg" ) );
301
+ }
302
+
303
+ update_option( "wpstg_settings", json_decode( file_get_contents( $importFile, true ) ) );
304
+
305
+ wp_safe_redirect( admin_url( "admin.php?page=wpstg-tools&amp;wpstg-message=settings-imported" ) );
306
+
307
+ return;
308
+ }
309
+
310
+ /**
311
+ * Export settings to JSON file
312
+ */
313
+ public function export() {
314
+ if( empty( $_POST["wpstg_export_nonce"] ) ) {
315
+ return;
316
+ }
317
+
318
+ if( !wp_verify_nonce( $_POST["wpstg_export_nonce"], "wpstg_export_nonce" ) ) {
319
+ return;
320
+ }
321
+
322
+ if( !current_user_can( "manage_options" ) ) {
323
+ return;
324
+ }
325
+
326
+ $settings = get_option( "wpstg_settings", array() );
327
+
328
+ ignore_user_abort( true );
329
+
330
+ if( !in_array( "set_time_limit", explode( ',', ini_get( "disable_functions" ) ) ) && !@ini_get( "safe_mode" ) ) {
331
+ set_time_limit( 0 );
332
+ }
333
+
334
+ $fileName = apply_filters( "wpstg_settings_export_filename", "wpstg-settings-export-" . date( "m-d-Y" ) ) . ".json";
335
+
336
+ nocache_headers();
337
+ header( "Content-Type: application/json; charset=utf-8" );
338
+ header( "Content-Disposition: attachment; filename={$fileName}" );
339
+ header( "Expires: 0" );
340
+
341
+ echo json_encode( $settings );
342
+ }
343
+
344
+ /**
345
+ * Render a view file
346
+ * @param string $file
347
+ * @param array $vars
348
+ * @return string
349
+ */
350
+ public function render( $file, $vars = array() ) {
351
+ $fullPath = $this->path . "views" . DIRECTORY_SEPARATOR;
352
+ $fullPath = str_replace( array('/', "\\"), DIRECTORY_SEPARATOR, $fullPath . $file . ".php" );
353
+
354
+ if( !file_exists( $fullPath ) || !is_readable( $fullPath ) ) {
355
+ return "Can't render : {$fullPath} either file doesn't exist or can't read it";
356
+ }
357
+
358
+ $contents = @file_get_contents( $fullPath );
359
+
360
+ // Variables are set
361
+ if( count( $vars ) > 0 ) {
362
+ $vars = array_combine(
363
+ array_map( function ($key) {
 
 
 
 
 
 
 
 
 
 
 
364
  return "{{" . $key . "}}";
365
+ }, array_keys( $vars )
366
+ ), $vars
367
+ );
368
+
369
+ $contents = str_replace( array_keys( $vars ), array_values( $vars ), $contents );
370
+ }
371
+
372
+ return $contents;
373
+ }
374
+
375
+ /**
376
+ * Ajax Overview
377
+ */
378
+ public function ajaxOverview() {
379
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
380
+
381
+ // Existing clones
382
+ $availableClones = get_option( "wpstg_existing_clones_beta", array() );
383
+
384
+ // Get license data
385
+ $license = get_option( 'wpstg_license_status' );
386
+
387
+ if( \WPStaging\WPStaging::getSlug() === 'wp-staging-pro' ) {
388
+ require_once "{$this->path}Pro/views/single-overview-pro.php";
389
+ } else {
390
+ require_once "{$this->path}views/clone/ajax/single-overview.php";
391
+ }
392
+
393
+ wp_die();
394
+ }
395
+
396
+ /**
397
+ * Ajax Scan
398
+ */
399
+ public function ajaxScan() {
400
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
401
+
402
+ // Scan
403
+ $scan = new Scan();
404
+ $scan->start();
405
+
406
+ // Get Options
407
+ $options = $scan->getOptions();
408
+
409
+ require_once "{$this->path}views/clone/ajax/scan.php";
410
+
411
+ wp_die();
412
+ }
413
+
414
+ /**
415
+ * Ajax Check Clone Name
416
+ */
417
+ public function ajaxCheckCloneName() {
418
+ $cloneName = sanitize_key( $_POST["cloneID"] );
419
+ $cloneNameLength = strlen( $cloneName );
420
+ $clones = get_option( "wpstg_existing_clones_beta", array() );
421
+
422
+ // Check clone name length
423
+ if( $cloneNameLength < 1 || $cloneNameLength > 16 ) {
424
+ echo wp_send_json( array(
425
+ "status" => "failed",
426
+ "message" => "Clone name must be between 1 - 16 characters"
427
+ ) );
428
+ } elseif( array_key_exists( $cloneName, $clones ) ) {
429
+ echo wp_send_json( array(
430
+ "status" => "failed",
431
+ "message" => "Clone name is already in use, please choose an another clone name"
432
+ ) );
433
+ }
434
+
435
+ echo wp_send_json( array("status" => "success") );
436
+ }
437
+
438
+ /**
439
+ * Ajax Start Clone (Basically just layout and saving data)
440
+ */
441
+ public function ajaxStartClone() {
442
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
443
+
444
+ $cloning = new Cloning();
445
+
446
+ if( !$cloning->save() ) {
447
+ wp_die();
448
+ }
449
+
450
+ require_once "{$this->path}views/clone/ajax/start.php";
451
+
452
+ wp_die();
453
+ }
454
+
455
+ /**
456
+ * Ajax Clone Database
457
+ */
458
+ public function ajaxCloneDatabase() {
459
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
460
+
461
+ $cloning = new Cloning();
462
+
463
+ wp_send_json( $cloning->start() );
464
+ }
465
+
466
+ /**
467
+ * Ajax Prepare Directories (get listing of files)
468
+ */
469
+ public function ajaxPrepareDirectories() {
470
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
471
+
472
+ $cloning = new Cloning();
473
+
474
+ wp_send_json( $cloning->start() );
475
+ }
476
+
477
+ /**
478
+ * Ajax Clone Files
479
+ */
480
+ public function ajaxCopyFiles() {
481
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
482
+
483
+ $cloning = new Cloning();
484
+
485
+ wp_send_json( $cloning->start() );
486
+ }
487
+
488
+ /**
489
+ * Ajax Replace Data
490
+ */
491
+ public function ajaxReplaceData() {
492
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
493
+
494
+ $cloning = new Cloning();
495
+
496
+ wp_send_json( $cloning->start() );
497
+ }
498
+
499
+ /**
500
+ * Ajax Finish
501
+ */
502
+ public function ajaxFinish() {
503
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
504
+
505
+ $cloning = new Cloning();
506
+
507
+ wp_send_json( $cloning->start() );
508
+ }
509
+
510
+ /**
511
+ * Ajax Delete Confirmation
512
+ */
513
+ public function ajaxDeleteConfirmation() {
514
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
515
+
516
+ $delete = new Delete();
517
+ $delete->setData();
518
+
519
+ $clone = $delete->getClone();
520
+
521
+ require_once "{$this->path}views/clone/ajax/delete-confirmation.php";
522
+
523
+ wp_die();
524
+ }
525
+
526
+ /**
527
+ * Delete clone
528
+ */
529
+ public function ajaxDeleteClone() {
530
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
531
+
532
+ $delete = new Delete();
533
+ wp_send_json( $delete->start() );
534
+ }
535
+
536
+ /**
537
+ * Delete clone
538
+ */
539
+ public function ajaxCancelClone() {
540
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
541
+
542
+ $cancel = new Cancel();
543
+ wp_send_json( $cancel->start() );
544
+ }
545
+
546
+ /**
547
+ * Admin Messages
548
+ */
549
+ public function messages() {
550
+ $notice = new Notices( $this->path, $this->url );
551
+
552
+ $run = $notice->messages();
553
+ }
554
+
555
+ /**
556
+ * Ajax Hide Poll
557
+ * @return mixed boolean | json
558
+ */
559
+ public function ajaxHidePoll() {
560
+ if( false !== update_option( "wpstg_poll", "no" ) ) {
561
+ wp_send_json( true );
562
+ }
563
+ return wp_send_json();
564
+ }
565
+
566
+ /**
567
+ * Ajax Hide Rating
568
+ * @return mixed bool | json
569
+ */
570
+ public function ajaxHideRating() {
571
+ if( false !== update_option( "wpstg_rating", "no" ) ) {
572
+ wp_send_json( true );
573
+ }
574
+ return wp_send_json();
575
+ }
576
+
577
+ /**
578
+ * Ajax Hide Beta
579
+ */
580
+ public function ajaxHideBeta() {
581
+ wp_send_json( update_option( "wpstg_beta", "no" ) );
582
+ }
583
+
584
+ /**
585
+ * Clone logs
586
+ */
587
+ public function ajaxLogs() {
588
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
589
+
590
+ $logs = new Logs();
591
+ wp_send_json( $logs->start() );
592
+ }
593
+
594
+ /**
595
+ * Ajax Checks Free Disk Space
596
+ */
597
+ public function ajaxCheckFreeSpace() {
598
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
599
+
600
+ $scan = new Scan();
601
+ return $scan->hasFreeDiskSpace();
602
+ }
603
+
604
+ /**
605
+ * Ajax Start Push Changes Process
606
+ */
607
+ public function ajaxProcessing() {
608
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
609
+
610
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Scan' ) ) {
611
+ return false;
612
+ }
613
+
614
+ // Scan
615
+ $scan = new Pro\Modules\Jobs\Scan();
616
+ $scan->start();
617
+
618
+ // Get Options
619
+ $options = $scan->getOptions();
620
+
621
+ require_once "{$this->path}Pro/views/scan.php";
622
+
623
+ wp_die();
624
+ }
625
+
626
+ /**
627
+ * Ajax Start Pushing. Needs wp quads pro)
628
+ */
629
+ public function ajaxPushChanges() {
630
+ check_ajax_referer( "wpstg_ajax_nonce", "nonce" );
631
+
632
+ if( !class_exists( 'WPStaging\Backend\Pro\Modules\Jobs\Processing' ) ) {
633
+ return false;
634
+ }
635
+ // Start the process
636
+ $processing = new Processing();
637
+ wp_send_json( $processing->start() );
638
+ }
639
+
640
+ /**
641
+ * License Page
642
+ */
643
+ public function getLicensePage() {
644
+
645
+ // Get license data
646
+ $license = get_option( 'wpstg_license_status' );
647
+
648
+ require_once "{$this->path}Pro/views/licensing.php";
649
+ }
650
+
651
+ }
apps/Backend/Modules/Jobs/Cloning.php CHANGED
@@ -3,6 +3,10 @@ namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
 
 
 
 
 
6
  /**
7
  * Class Cloning
8
  * @package WPStaging\Backend\Modules\Jobs
@@ -59,8 +63,8 @@ class Cloning extends Job
59
  }
60
 
61
  // Extra Directories
62
- if (isset($_POST["extraDirectories"]) && strlen($_POST["extraDirectories"]) > 0)
63
- {
64
  $this->options->extraDirectories = $_POST["extraDirectories"];
65
  }
66
 
@@ -71,7 +75,9 @@ class Cloning extends Job
71
  );
72
 
73
  array_unshift($this->options->directoriesToCopy, ABSPATH);
74
-
 
 
75
  // Delete files to copy listing
76
  $this->cache->delete("files_to_copy");
77
 
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\JobNotFoundException;
5
 
6
+ //ini_set('display_startup_errors', 1);
7
+ //ini_set('display_errors', 1);
8
+ //error_reporting(-1);
9
+
10
  /**
11
  * Class Cloning
12
  * @package WPStaging\Backend\Modules\Jobs
63
  }
64
 
65
  // Extra Directories
66
+ if (isset($_POST["extraDirectories"]) && !empty($_POST["extraDirectories"]) )
67
+ {
68
  $this->options->extraDirectories = $_POST["extraDirectories"];
69
  }
70
 
75
  );
76
 
77
  array_unshift($this->options->directoriesToCopy, ABSPATH);
78
+
79
+ //var_dump($this->options->directoriesToCopy);
80
+
81
  // Delete files to copy listing
82
  $this->cache->delete("files_to_copy");
83
 
apps/Backend/Modules/Jobs/Data.php CHANGED
@@ -164,7 +164,7 @@ class Data extends JobExecutable
164
  */
165
  protected function step1()
166
  {
167
- $this->log( "Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_ERROR );
168
 
169
  $result = $this->db->query(
170
  $this->db->prepare(
164
  */
165
  protected function step1()
166
  {
167
+ $this->log( "Updating siteurl and homeurl in {$this->prefix}options {$this->db->last_error}", Logger::TYPE_INFO );
168
 
169
  $result = $this->db->query(
170
  $this->db->prepare(
apps/Backend/Modules/Jobs/Database.php CHANGED
@@ -1,6 +1,10 @@
1
  <?php
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
 
 
 
 
4
  // No Direct Access
5
  if (!defined("WPINC"))
6
  {
1
  <?php
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
+ //ini_set('display_startup_errors', 1);
5
+ //ini_set('display_errors', 1);
6
+ //error_reporting(-1);
7
+
8
  // No Direct Access
9
  if (!defined("WPINC"))
10
  {
apps/Backend/Modules/Jobs/Delete.php CHANGED
@@ -2,7 +2,7 @@
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\CloneNotFoundException;
5
- use WPStaging\Utils\Directories;
6
  use WPStaging\Utils\Logger;
7
  use WPStaging\WPStaging;
8
 
@@ -70,24 +70,16 @@ class Delete extends Job
70
  $name = $_POST["clone"];
71
  }
72
 
73
- $clones = get_option("wpstg_existing_clones", array());
74
 
75
  if (empty($clones) || !isset($clones[$name]))
76
  {
77
  $this->log("Couldn't find clone name {$name} or no existing clone", Logger::TYPE_FATAL);
78
- throw new CloneNotFoundException();
79
  }
80
 
81
  $this->clone = $clones[$name];
82
  $this->clone["name"] = $name;
83
- // $this->clone["size"] = null;
84
- //
85
- // if (isset($this->settings->checkDirectorySize) || '1' === $this->settings->checkDirectorySize)
86
- // {
87
- // $directories = new Directories();
88
- // $this->clone["size"] = $this->formatSize($directories->size($this->clone));
89
- // unset($directories);
90
- // }
91
 
92
  $this->clone = (object) $this->clone;
93
 
@@ -101,10 +93,6 @@ class Delete extends Job
101
  {
102
  $wpdb = WPStaging::getInstance()->get("wpdb");
103
 
104
- // if ($this->clone['version']){
105
- //
106
- // }
107
-
108
  $tables = $wpdb->get_results("SHOW TABLE STATUS LIKE 'wpstg{$this->clone->number}_%'");
109
 
110
  $this->tables = array();
@@ -119,8 +107,8 @@ class Delete extends Job
119
 
120
  $this->tables = json_decode(json_encode($this->tables));
121
  }
122
-
123
- /**
124
  * Format bytes into human readable form
125
  * @param int $bytes
126
  * @param int $precision
@@ -142,6 +130,7 @@ class Delete extends Job
142
  return round($pow, $precision) . ' ' . $units[(int) floor($base)];
143
  }
144
 
 
145
  /**
146
  * @return false
147
  */
@@ -178,25 +167,27 @@ class Delete extends Job
178
  /**
179
  * Get job data
180
  */
181
- private function getJob()
182
- {
183
- $this->job = $this->cache->get("delete_job_{$this->clone->name}");
184
 
185
- if (null !== $this->job)
186
- {
187
- return;
188
- }
189
 
190
- // Generate JOB
191
- $this->job = (object) array(
192
- "current" => "tables",
193
- "nextDirectoryToDelete" => $this->clone->path
194
- );
195
 
196
- $this->cache->save("delete_job_{$this->clone->name}", $this->job);
197
- }
 
 
 
 
198
 
199
- /**
 
 
 
 
 
200
  * @return bool
201
  */
202
  private function updateJob()
@@ -269,8 +260,43 @@ class Delete extends Job
269
  $length = strlen($needle);
270
  return (substr($haystack, 0, $length) === $needle);
271
  }
272
-
273
- /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
274
  * Delete Directories
275
  */
276
  public function deleteDirectory()
@@ -294,8 +320,9 @@ class Delete extends Job
294
  public function isDirectoryDeletingFinished()
295
  {
296
  return (
 
297
  (false === $this->forceDeleteDirectories && (!isset($_POST["deleteDir"]) || '1' !== $_POST["deleteDir"])) ||
298
- !is_dir($this->clone->path) || ABSPATH === $this->job->nextDirectoryToDelete
299
  );
300
  }
301
 
@@ -370,7 +397,7 @@ class Delete extends Job
370
  */
371
  public function deleteFinish()
372
  {
373
- $existingClones = get_option("wpstg_existing_clones", array());
374
 
375
  // Check if clones still exist
376
  $this->log("Verifying existing clones...");
@@ -383,7 +410,7 @@ class Delete extends Job
383
  }
384
  $this->log("Existing clones verified!");
385
 
386
- if (false === update_option("wpstg_existing_clones", $existingClones))
387
  {
388
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
389
  }
@@ -392,6 +419,8 @@ class Delete extends Job
392
  $this->cache->delete("delete_job_{$this->clone->name}");
393
  $this->cache->delete("delete_directories_{$this->clone->name}");
394
 
395
- return true;
 
 
396
  }
397
  }
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
4
  use WPStaging\Backend\Modules\Jobs\Exceptions\CloneNotFoundException;
5
+ //use WPStaging\Utils\Directories;
6
  use WPStaging\Utils\Logger;
7
  use WPStaging\WPStaging;
8
 
70
  $name = $_POST["clone"];
71
  }
72
 
73
+ $clones = get_option("wpstg_existing_clones_beta", array());
74
 
75
  if (empty($clones) || !isset($clones[$name]))
76
  {
77
  $this->log("Couldn't find clone name {$name} or no existing clone", Logger::TYPE_FATAL);
78
+ //throw new CloneNotFoundException();
79
  }
80
 
81
  $this->clone = $clones[$name];
82
  $this->clone["name"] = $name;
 
 
 
 
 
 
 
 
83
 
84
  $this->clone = (object) $this->clone;
85
 
93
  {
94
  $wpdb = WPStaging::getInstance()->get("wpdb");
95
 
 
 
 
 
96
  $tables = $wpdb->get_results("SHOW TABLE STATUS LIKE 'wpstg{$this->clone->number}_%'");
97
 
98
  $this->tables = array();
107
 
108
  $this->tables = json_decode(json_encode($this->tables));
109
  }
110
+
111
+ /**
112
  * Format bytes into human readable form
113
  * @param int $bytes
114
  * @param int $precision
130
  return round($pow, $precision) . ' ' . $units[(int) floor($base)];
131
  }
132
 
133
+
134
  /**
135
  * @return false
136
  */
167
  /**
168
  * Get job data
169
  */
170
+ private function getJob() {
171
+ $this->job = $this->cache->get( "delete_job_{$this->clone->name}" );
 
172
 
 
 
 
 
173
 
174
+ if( null !== $this->job ) {
175
+ return;
176
+ }
 
 
177
 
178
+ // Generate JOB
179
+ $this->job = ( object ) array(
180
+ "current" => "tables",
181
+ "nextDirectoryToDelete" => $this->clone->path,
182
+ "name" => $this->clone->name
183
+ );
184
 
185
+ $this->cache->save( "delete_job_{$this->clone->name}", $this->job );
186
+ }
187
+
188
+
189
+
190
+ /**
191
  * @return bool
192
  */
193
  private function updateJob()
260
  $length = strlen($needle);
261
  return (substr($haystack, 0, $length) === $needle);
262
  }
263
+
264
+ /**
265
+ * Delete a specific directory and all of its subfolders in a native way without using any external caching data
266
+ *
267
+ * @param array $dir
268
+ * @param array $excluded_dirs
269
+ * @return boolean false when its finished
270
+ */
271
+ function deleteDirectoryNative( $dir = '' ) {
272
+
273
+ if( !file_exists( $dir ) ) {
274
+ return $this->isFinished();
275
+ }
276
+
277
+ if( !is_dir( $dir ) || is_link( $dir ) ) {
278
+ unlink( $dir );
279
+ return $this->isFinished();
280
+ }
281
+ foreach ( scandir( $dir ) as $item ) {
282
+ if( $item == '.' || $item == '..' ) {
283
+ continue;
284
+ }
285
+ if( !$this->deleteDirectoryNative( $dir . "/" . $item, false ) ) {
286
+ //chmod( $dir . "/" . $item, 0777 );
287
+ //if( !$this->deleteDirectoryNative( $dir . "/" . $item, false ) ){
288
+ //return false;
289
+ //}
290
+ }
291
+ };
292
+
293
+ rmdir( $dir );
294
+ return $this->isFinished();
295
+ }
296
+
297
+
298
+
299
+ /**
300
  * Delete Directories
301
  */
302
  public function deleteDirectory()
320
  public function isDirectoryDeletingFinished()
321
  {
322
  return (
323
+ !is_dir($this->clone->path) ||
324
  (false === $this->forceDeleteDirectories && (!isset($_POST["deleteDir"]) || '1' !== $_POST["deleteDir"])) ||
325
+ ABSPATH === $this->job->nextDirectoryToDelete
326
  );
327
  }
328
 
397
  */
398
  public function deleteFinish()
399
  {
400
+ $existingClones = get_option("wpstg_existing_clones_beta", array());
401
 
402
  // Check if clones still exist
403
  $this->log("Verifying existing clones...");
410
  }
411
  $this->log("Existing clones verified!");
412
 
413
+ if (false === update_option("wpstg_existing_clones_beta", $existingClones))
414
  {
415
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
416
  }
419
  $this->cache->delete("delete_job_{$this->clone->name}");
420
  $this->cache->delete("delete_directories_{$this->clone->name}");
421
 
422
+ //return true;
423
+ $response = array('delete' => 'finished');
424
+ wp_die(json_encode($response));
425
  }
426
  }
apps/Backend/Modules/Jobs/Delete_deprecated.php ADDED
@@ -0,0 +1,397 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ use WPStaging\Backend\Modules\Jobs\Exceptions\CloneNotFoundException;
5
+ //use WPStaging\Utils\Directories;
6
+ use WPStaging\Utils\Logger;
7
+ use WPStaging\WPStaging;
8
+
9
+ /**
10
+ * Class Delete
11
+ * @package WPStaging\Backend\Modules\Jobs
12
+ */
13
+ class Delete_deprecated extends Job
14
+ {
15
+
16
+ /**
17
+ * @var false
18
+ */
19
+ private $clone = false;
20
+
21
+ /**
22
+ * @var null|object
23
+ */
24
+ private $tables = null;
25
+
26
+ /**
27
+ * @var object|null
28
+ */
29
+ private $job = null;
30
+
31
+ /**
32
+ * @var bool
33
+ */
34
+ private $forceDeleteDirectories = false;
35
+
36
+ /**
37
+ * Sets Clone and Table Records
38
+ * @param null|array $clone
39
+ */
40
+ public function setData($clone = null)
41
+ {
42
+ if (!is_array($clone))
43
+ {
44
+ $this->getCloneRecords();
45
+ }
46
+ else
47
+ {
48
+ $this->clone = (object) $clone;
49
+ $this->forceDeleteDirectories = true;
50
+ }
51
+
52
+ $this->getTableRecords();
53
+ }
54
+
55
+ /**
56
+ * Get clone
57
+ * @param null|string $name
58
+ * @throws CloneNotFoundException
59
+ */
60
+ private function getCloneRecords($name = null)
61
+ {
62
+ if (null === $name && !isset($_POST["clone"]))
63
+ {
64
+ $this->log("Clone name is not set", Logger::TYPE_FATAL);
65
+ throw new CloneNotFoundException();
66
+ }
67
+
68
+ if (null === $name)
69
+ {
70
+ $name = $_POST["clone"];
71
+ }
72
+
73
+ $clones = get_option("wpstg_existing_clones_beta", array());
74
+
75
+ if (empty($clones) || !isset($clones[$name]))
76
+ {
77
+ $this->log("Couldn't find clone name {$name} or no existing clone", Logger::TYPE_FATAL);
78
+ throw new CloneNotFoundException();
79
+ }
80
+
81
+ $this->clone = $clones[$name];
82
+ $this->clone["name"] = $name;
83
+ // $this->clone["size"] = null;
84
+ //
85
+ // if (isset($this->settings->checkDirectorySize) || '1' === $this->settings->checkDirectorySize)
86
+ // {
87
+ // $directories = new Directories();
88
+ // $this->clone["size"] = $this->formatSize($directories->size($this->clone));
89
+ // unset($directories);
90
+ // }
91
+
92
+ $this->clone = (object) $this->clone;
93
+
94
+ unset($clones);
95
+ }
96
+
97
+ /**
98
+ * Get Tables
99
+ */
100
+ private function getTableRecords()
101
+ {
102
+ $wpdb = WPStaging::getInstance()->get("wpdb");
103
+
104
+ // if ($this->clone['version']){
105
+ //
106
+ // }
107
+
108
+ $tables = $wpdb->get_results("SHOW TABLE STATUS LIKE 'wpstg{$this->clone->number}_%'");
109
+
110
+ $this->tables = array();
111
+
112
+ foreach ($tables as $table)
113
+ {
114
+ $this->tables[] = array(
115
+ "name" => $table->Name,
116
+ "size" => $this->formatSize(($table->Data_length + $table->Index_length))
117
+ );
118
+ }
119
+
120
+ $this->tables = json_decode(json_encode($this->tables));
121
+ }
122
+
123
+ /**
124
+ * Format bytes into human readable form
125
+ * @param int $bytes
126
+ * @param int $precision
127
+ * @return string
128
+ */
129
+ public function formatSize($bytes, $precision = 2)
130
+ {
131
+ if ((int) $bytes < 1)
132
+ {
133
+ return '';
134
+ }
135
+
136
+ $units = array('B', "KB", "MB", "GB", "TB");
137
+
138
+ $bytes = (int) $bytes;
139
+ $base = log($bytes) / log(1000); // 1024 would be for MiB KiB etc
140
+ $pow = pow(1000, $base - floor($base)); // Same rule for 1000
141
+
142
+ return round($pow, $precision) . ' ' . $units[(int) floor($base)];
143
+ }
144
+
145
+ /**
146
+ * @return false
147
+ */
148
+ public function getClone()
149
+ {
150
+ return $this->clone;
151
+ }
152
+
153
+ /**
154
+ * @return null|object
155
+ */
156
+ public function getTables()
157
+ {
158
+ return $this->tables;
159
+ }
160
+
161
+ /**
162
+ * Start Module
163
+ * @param null|array $clone
164
+ * @return bool
165
+ */
166
+ public function start($clone = null)
167
+ {
168
+ // Set data
169
+ $this->setData($clone);
170
+
171
+ // Get the job first
172
+ $this->getJob();
173
+
174
+ $method = "delete" . ucwords($this->job->current);
175
+ return $this->{$method}();
176
+ }
177
+
178
+ /**
179
+ * Get job data
180
+ */
181
+ private function getJob()
182
+ {
183
+ $this->job = $this->cache->get("delete_job_{$this->clone->name}");
184
+
185
+ if (null !== $this->job)
186
+ {
187
+ return;
188
+ }
189
+
190
+ // Generate JOB
191
+ $this->job = (object) array(
192
+ "current" => "tables",
193
+ "nextDirectoryToDelete" => $this->clone->path
194
+ );
195
+
196
+ $this->cache->save("delete_job_{$this->clone->name}", $this->job);
197
+ }
198
+
199
+ /**
200
+ * @return bool
201
+ */
202
+ private function updateJob()
203
+ {
204
+ $this->job->nextDirectoryToDelete = trim($this->job->nextDirectoryToDelete);
205
+ return $this->cache->save("delete_job_{$this->clone->name}", $this->job);
206
+ }
207
+
208
+ /**
209
+ * @return array
210
+ */
211
+ private function getTablesToRemove()
212
+ {
213
+ $tables = $this->getTableNames();
214
+
215
+ if (!isset($_POST["excludedTables"]) || !is_array($_POST["excludedTables"]) || empty($_POST["excludedTables"]))
216
+ {
217
+ return $tables;
218
+ }
219
+
220
+ return array_diff($tables, $_POST["excludedTables"]);
221
+ }
222
+
223
+ /**
224
+ * @return array
225
+ */
226
+ private function getTableNames()
227
+ {
228
+ return (!is_array($this->tables)) ? array() : array_map(function($value) {
229
+ return ($value->name);
230
+ }, $this->tables);
231
+ }
232
+
233
+ /**
234
+ * Delete Tables
235
+ */
236
+ public function deleteTables()
237
+ {
238
+ if ($this->isOverThreshold())
239
+ {
240
+ return;
241
+ }
242
+
243
+ $wpdb = WPStaging::getInstance()->get("wpdb");
244
+
245
+ foreach ($this->getTablesToRemove() as $table)
246
+ {
247
+ // PROTECTION: Never delete any table that beginns with wp prefix of live site
248
+ if($this->startsWith($table, $wpdb->prefix)){
249
+ $this->log("Fatal Error: Trying to delete table {$table} of main WP installation!", Logger::TYPE_CRITICAL);
250
+ return false;
251
+ } else{
252
+ $wpdb->query("DROP TABLE {$table}");
253
+ }
254
+ }
255
+
256
+ // Move on to the next
257
+ $this->job->current = "directory";
258
+ $this->updateJob();
259
+ }
260
+
261
+ /**
262
+ * Check if a strings start with a specific string
263
+ * @param string $haystack
264
+ * @param string $needle
265
+ * @return bool
266
+ */
267
+ protected function startsWith($haystack, $needle)
268
+ {
269
+ $length = strlen($needle);
270
+ return (substr($haystack, 0, $length) === $needle);
271
+ }
272
+
273
+ /**
274
+ * Delete Directories
275
+ */
276
+ public function deleteDirectory()
277
+ {
278
+ // No deleting directories or root of this clone is deleted
279
+ if ($this->isDirectoryDeletingFinished())
280
+ {
281
+ $this->job->current = "finish";
282
+ $this->updateJob();
283
+ return;
284
+ }
285
+
286
+ $this->processDirectory($this->job->nextDirectoryToDelete);
287
+
288
+ return;
289
+ }
290
+
291
+ /**
292
+ * @return bool
293
+ */
294
+ public function isDirectoryDeletingFinished()
295
+ {
296
+ return (
297
+ (false === $this->forceDeleteDirectories && (!isset($_POST["deleteDir"]) || '1' !== $_POST["deleteDir"])) ||
298
+ !is_dir($this->clone->path) || ABSPATH === $this->job->nextDirectoryToDelete
299
+ );
300
+ }
301
+
302
+ /**
303
+ * Delete contents of the directory if there are no directories in it and then delete itself
304
+ * @param string $path
305
+ * @return mixed
306
+ */
307
+ private function processDirectory($path)
308
+ {
309
+ // We hit the limit, stop
310
+ if ($this->shouldStop($path))
311
+ {
312
+ $this->updateJob();
313
+ return false;
314
+ }
315
+
316
+ $this->totalRecursion++;
317
+
318
+ $contents = new \DirectoryIterator($path);
319
+
320
+ foreach ($contents as $content)
321
+ {
322
+ // Skip dots
323
+ if ($content->isDot())
324
+ {
325
+ continue;
326
+ }
327
+
328
+ // Get into the directory
329
+ if (!$content->isLink() && $content->isDir())
330
+ {
331
+ return $this->processDirectory($content->getRealPath());
332
+ }
333
+
334
+ // Delete file
335
+ if ($content->isFile())
336
+ {
337
+ @unlink($content->getRealPath());
338
+ }
339
+ }
340
+
341
+ // Delete directory
342
+ $this->job->lastDeletedDirectory = realpath($path . "/..");
343
+ @rmdir($path);
344
+ $this->updateJob();
345
+ $this->processDirectory($this->job->nextDirectoryToDelete);
346
+ }
347
+
348
+ /**
349
+ * @param string $path
350
+ * @return bool
351
+ */
352
+ private function shouldStop($path)
353
+ {
354
+ // Just to make sure the root dir is never deleted!
355
+ if ($path === get_home_path()){
356
+ $this->log("Fatal Error: Trying to delete root of WP installation!", Logger::TYPE_CRITICAL);
357
+ return true;
358
+ }
359
+
360
+ // Check if threshold is reached and is valid dir
361
+ return (
362
+ $this->isOverThreshold() ||
363
+ !is_dir($path) ||
364
+ $this->isDirectoryDeletingFinished()
365
+ );
366
+ }
367
+
368
+ /**
369
+ * Finish / Update Existing Clones
370
+ */
371
+ public function deleteFinish()
372
+ {
373
+ $existingClones = get_option("wpstg_existing_clones_beta", array());
374
+
375
+ // Check if clones still exist
376
+ $this->log("Verifying existing clones...");
377
+ foreach ($existingClones as $name => $clone)
378
+ {
379
+ if (!is_dir($clone["path"]))
380
+ {
381
+ unset($existingClones[$name]);
382
+ }
383
+ }
384
+ $this->log("Existing clones verified!");
385
+
386
+ if (false === update_option("wpstg_existing_clones_beta", $existingClones))
387
+ {
388
+ $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
389
+ }
390
+
391
+ // Delete cached file
392
+ $this->cache->delete("delete_job_{$this->clone->name}");
393
+ $this->cache->delete("delete_directories_{$this->clone->name}");
394
+
395
+ return true;
396
+ }
397
+ }
apps/Backend/Modules/Jobs/Delete_new.php ADDED
@@ -0,0 +1,382 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPStaging\Backend\Modules\Jobs;
3
+
4
+ use WPStaging\Backend\Modules\Jobs\Exceptions\CloneNotFoundException;
5
+ //use WPStaging\Utils\Directories;
6
+ use WPStaging\Utils\Logger;
7
+ use WPStaging\WPStaging;
8
+
9
+ /**
10
+ * Class Delete
11
+ * @package WPStaging\Backend\Modules\Jobs
12
+ */
13
+ class Delete_new extends Job
14
+ {
15
+
16
+ /**
17
+ * @var false
18
+ */
19
+ private $clone = false;
20
+
21
+ /**
22
+ * @var null|object
23
+ */
24
+ private $tables = null;
25
+
26
+ /**
27
+ * @var object|null
28
+ */
29
+ private $job = null;
30
+
31
+ /**
32
+ * @var bool
33
+ */
34
+ private $forceDeleteDirectories = false;
35
+
36
+ /**
37
+ * Sets Clone and Table Records
38
+ * @param null|array $clone
39
+ */
40
+ public function setData($clone = null)
41
+ {
42
+ if (!is_array($clone))
43
+ {
44
+ $this->getCloneRecords();
45
+ }
46
+ else
47
+ {
48
+ $this->clone = (object) $clone;
49
+ $this->forceDeleteDirectories = true;
50
+ }
51
+
52
+ $this->getTableRecords();
53
+ }
54
+
55
+ /**
56
+ * Get clone
57
+ * @param null|string $name
58
+ * @throws CloneNotFoundException
59
+ */
60
+ private function getCloneRecords($name = null)
61
+ {
62
+ if (null === $name && !isset($_POST["clone"]))
63
+ {
64
+ $this->log("Clone name is not set", Logger::TYPE_FATAL);
65
+ throw new CloneNotFoundException();
66
+ }
67
+
68
+ if (null === $name)
69
+ {
70
+ $name = $_POST["clone"];
71
+ }
72
+
73
+ $clones = get_option("wpstg_existing_clones_beta", array());
74
+
75
+ if (empty($clones) || !isset($clones[$name]))
76
+ {
77
+ $this->log("Couldn't find clone name {$name} or no existing clone", Logger::TYPE_FATAL);
78
+ throw new CloneNotFoundException();
79
+ }
80
+
81
+ $this->clone = $clones[$name];
82
+ $this->clone["name"] = $name;
83
+ $this->clone = (object) $this->clone;
84
+
85
+ unset($clones);
86
+ }
87
+
88
+ /**
89
+ * Get Tables
90
+ */
91
+ private function getTableRecords()
92
+ {
93
+ $wpdb = WPStaging::getInstance()->get("wpdb");
94
+
95
+ $tables = $wpdb->get_results("SHOW TABLE STATUS LIKE 'wpstg{$this->clone->number}_%'");
96
+
97
+ $this->tables = array();
98
+
99
+ foreach ($tables as $table)
100
+ {
101
+ $this->tables[] = array(
102
+ "name" => $table->Name,
103
+ "size" => $this->formatSize(($table->Data_length + $table->Index_length))
104
+ );
105
+ }
106
+
107
+ $this->tables = json_decode(json_encode($this->tables));
108
+ }
109
+
110
+ /**
111
+ * @return false
112
+ */
113
+ public function getClone()
114
+ {
115
+ return $this->clone;
116
+ }
117
+
118
+ /**
119
+ * @return null|object
120
+ */
121
+ public function getTables()
122
+ {
123
+ return $this->tables;
124
+ }
125
+
126
+ /**
127
+ * Start Module
128
+ * @param null|array $clone
129
+ * @return bool
130
+ */
131
+ public function start($clone = null)
132
+ {
133
+ // Set data
134
+ $this->setData($clone);
135
+
136
+ // Get the job first
137
+ $this->getJob();
138
+
139
+ $method = "delete" . ucwords($this->job->current);
140
+ return $this->{$method}();
141
+ }
142
+
143
+
144
+
145
+ /**
146
+ * Get job data
147
+ */
148
+ private function getJob()
149
+ {
150
+ $this->job = $this->cache->get("delete_job_{$this->clone->name}");
151
+
152
+ if (null !== $this->job)
153
+ {
154
+ return;
155
+ }
156
+
157
+ // Generate JOB
158
+ $this->job = (object) array(
159
+ "current" => "tables",
160
+ "nextDirectoryToDelete" => $this->clone->path
161
+ );
162
+
163
+ $this->cache->save("delete_job_{$this->clone->name}", $this->job);
164
+ }
165
+
166
+ /**
167
+ * Delete Directories
168
+ */
169
+ // public function deleteDirectory()
170
+ // {
171
+ // // No deleting directories or root of this clone is deleted
172
+ // if ($this->isDirectoryDeletingFinished())
173
+ // {
174
+ // $this->job->current = "finish";
175
+ // $this->updateJob();
176
+ // return;
177
+ // }
178
+ //
179
+ // $this->processDirectory($this->job->nextDirectoryToDelete);
180
+ //
181
+ // return;
182
+ // }
183
+
184
+ public function deleteDirectory(){
185
+ // Just to make sure the root dir is never deleted!
186
+ if ($this->clone->path === get_home_path()){
187
+ $this->log("Fatal Error: Trying to delete root of WP installation!", Logger::TYPE_CRITICAL);
188
+ return false;
189
+ }
190
+
191
+ $files = glob($this->clone->path . '/*');
192
+ foreach ($files as $file) {
193
+ is_dir($file) ? $this->deleteDirectory($file) : unlink($file);
194
+ }
195
+ rmdir($path);
196
+ $this->processDirectory($this->job->nextDirectoryToDelete);
197
+ return;
198
+ }
199
+
200
+ /**
201
+ * @return bool
202
+ */
203
+ private function updateJob()
204
+ {
205
+ $this->job->nextDirectoryToDelete = trim($this->job->nextDirectoryToDelete);
206
+ return $this->cache->save("delete_job_{$this->clone->name}", $this->job);
207
+ }
208
+
209
+ /**
210
+ * @return array
211
+ */
212
+ private function getTablesToRemove()
213
+ {
214
+ $tables = $this->getTableNames();
215
+
216
+ if (!isset($_POST["excludedTables"]) || !is_array($_POST["excludedTables"]) || empty($_POST["excludedTables"]))
217
+ {
218
+ return $tables;
219
+ }
220
+
221
+ return array_diff($tables, $_POST["excludedTables"]);
222
+ }
223
+
224
+ /**
225
+ * @return array
226
+ */
227
+ private function getTableNames()
228
+ {
229
+ return (!is_array($this->tables)) ? array() : array_map(function($value) {
230
+ return ($value->name);
231
+ }, $this->tables);
232
+ }
233
+
234
+ /**
235
+ * Delete Tables
236
+ */
237
+ public function deleteTables()
238
+ {
239
+ if ($this->isOverThreshold())
240
+ {
241
+ return;
242
+ }
243
+
244
+ $wpdb = WPStaging::getInstance()->get("wpdb");
245
+
246
+ foreach ($this->getTablesToRemove() as $table)
247
+ {
248
+ // PROTECTION: Never delete any table that beginns with wp prefix of live site
249
+ if($this->startsWith($table, $wpdb->prefix)){
250
+ $this->log("Fatal Error: Trying to delete table {$table} of main WP installation!", Logger::TYPE_CRITICAL);
251
+ return false;
252
+ } else{
253
+ $wpdb->query("DROP TABLE {$table}");
254
+ }
255
+ }
256
+
257
+ // Move on to the next
258
+ $this->job->current = "directory";
259
+ $this->updateJob();
260
+ }
261
+
262
+ /**
263
+ * Check if a strings start with a specific string
264
+ * @param string $haystack
265
+ * @param string $needle
266
+ * @return bool
267
+ */
268
+ protected function startsWith($haystack, $needle)
269
+ {
270
+ $length = strlen($needle);
271
+ return (substr($haystack, 0, $length) === $needle);
272
+ }
273
+
274
+
275
+
276
+ /**
277
+ * @return bool
278
+ */
279
+ public function isDirectoryDeletingFinished()
280
+ {
281
+ return (
282
+ (false === $this->forceDeleteDirectories && (!isset($_POST["deleteDir"]) || '1' !== $_POST["deleteDir"])) ||
283
+ !is_dir($this->clone->path) || ABSPATH === $this->job->nextDirectoryToDelete
284
+ );
285
+ }
286
+
287
+ /**
288
+ * Delete contents of the directory if there are no directories in it and then delete itself
289
+ * @param string $path
290
+ * @return mixed
291
+ */
292
+ private function processDirectory($path)
293
+ {
294
+ // We hit the limit, stop
295
+ if ($this->shouldStop($path))
296
+ {
297
+ $this->updateJob();
298
+ return false;
299
+ }
300
+
301
+ $this->totalRecursion++;
302
+
303
+ $contents = new \DirectoryIterator($path);
304
+
305
+ foreach ($contents as $content)
306
+ {
307
+ // Skip dots
308
+ if ($content->isDot())
309
+ {
310
+ continue;
311
+ }
312
+
313
+ // Get into the directory
314
+ if (!$content->isLink() && $content->isDir())
315
+ {
316
+ return $this->processDirectory($content->getRealPath());
317
+ }
318
+
319
+ // Delete file
320
+ if ($content->isFile())
321
+ {
322
+ @unlink($content->getRealPath());
323
+ }
324
+ }
325
+
326
+ // Delete directory
327
+ $this->job->lastDeletedDirectory = realpath($path . "/..");
328
+ @rmdir($path);
329
+ $this->updateJob();
330
+ $this->processDirectory($this->job->nextDirectoryToDelete);
331
+ }
332
+
333
+ /**
334
+ * @param string $path
335
+ * @return bool
336
+ */
337
+ private function shouldStop($path)
338
+ {
339
+ // Just to make sure the root dir is never deleted!
340
+ if ($path === get_home_path()){
341
+ $this->log("Fatal Error: Trying to delete root of WP installation!", Logger::TYPE_CRITICAL);
342
+ return true;
343
+ }
344
+
345
+ // Check if threshold is reached and is valid dir
346
+ return (
347
+ $this->isOverThreshold() ||
348
+ !is_dir($path) ||
349
+ $this->isDirectoryDeletingFinished()
350
+ );
351
+ }
352
+
353
+ /**
354
+ * Finish / Update Existing Clones
355
+ */
356
+ public function deleteFinish()
357
+ {
358
+ $existingClones = get_option("wpstg_existing_clones_beta", array());
359
+
360
+ // Check if clones still exist
361
+ $this->log("Verifying existing clones...");
362
+ foreach ($existingClones as $name => $clone)
363
+ {
364
+ if (!is_dir($clone["path"]))
365
+ {
366
+ unset($existingClones[$name]);
367
+ }
368
+ }
369
+ $this->log("Existing clones verified!");
370
+
371
+ if (false === update_option("wpstg_existing_clones_beta", $existingClones))
372
+ {
373
+ $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
374
+ }
375
+
376
+ // Delete cached file
377
+ $this->cache->delete("delete_job_{$this->clone->name}");
378
+ $this->cache->delete("delete_directories_{$this->clone->name}");
379
+
380
+ return true;
381
+ }
382
+ }
apps/Backend/Modules/Jobs/Delete_old.php CHANGED
@@ -10,7 +10,7 @@ use WPStaging\WPStaging;
10
  * Class Delete
11
  * @package WPStaging\Backend\Modules\Jobs
12
  */
13
- class Delete extends Job
14
  {
15
 
16
  /**
@@ -70,7 +70,7 @@ class Delete extends Job
70
  $name = $_POST["clone"];
71
  }
72
 
73
- $clones = get_option("wpstg_existing_clones", array());
74
 
75
  if (empty($clones) || !isset($clones[$name]))
76
  {
@@ -340,7 +340,7 @@ class Delete extends Job
340
  */
341
  public function deleteFinish()
342
  {
343
- $existingClones = get_option("wpstg_existing_clones", array());
344
 
345
  // Check if clones still exist
346
  $this->log("Verifying existing clones...");
@@ -353,7 +353,7 @@ class Delete extends Job
353
  }
354
  $this->log("Existing clones verified!");
355
 
356
- if (false === update_option("wpstg_existing_clones", $existingClones))
357
  {
358
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
359
  }
10
  * Class Delete
11
  * @package WPStaging\Backend\Modules\Jobs
12
  */
13
+ class Delete_old extends Job
14
  {
15
 
16
  /**
70
  $name = $_POST["clone"];
71
  }
72
 
73
+ $clones = get_option("wpstg_existing_clones_beta", array());
74
 
75
  if (empty($clones) || !isset($clones[$name]))
76
  {
340
  */
341
  public function deleteFinish()
342
  {
343
+ $existingClones = get_option("wpstg_existing_clones_beta", array());
344
 
345
  // Check if clones still exist
346
  $this->log("Verifying existing clones...");
353
  }
354
  $this->log("Existing clones verified!");
355
 
356
+ if (false === update_option("wpstg_existing_clones_beta", $existingClones))
357
  {
358
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
359
  }
apps/Backend/Modules/Jobs/Directories.php CHANGED
@@ -1,9 +1,13 @@
1
  <?php
 
2
  namespace WPStaging\Backend\Modules\Jobs;
3
 
 
 
 
 
4
  // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
  die;
8
  }
9
 
@@ -13,8 +17,8 @@ use WPStaging\WPStaging;
13
  * Class Files
14
  * @package WPStaging\Backend\Modules\Directories
15
  */
16
- class Directories extends JobExecutable
17
- {
18
  /**
19
  * @var array
20
  */
@@ -28,9 +32,8 @@ class Directories extends JobExecutable
28
  /**
29
  * Initialize
30
  */
31
- public function initialize()
32
- {
33
- $this->total = count($this->options->directoriesToCopy);
34
  $this->getFiles();
35
  }
36
 
@@ -38,30 +41,26 @@ class Directories extends JobExecutable
38
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
39
  * @return void
40
  */
41
- protected function calculateTotalSteps()
42
- {
43
  $this->options->totalSteps = $this->total;
44
  }
45
 
46
  /**
47
  * Get Root Files
48
  */
49
- protected function getRootFiles()
50
- {
51
- if (1 < $this->options->totalFiles)
52
- {
53
  return;
54
  }
55
 
56
- $this->getFilesFromDirectory(ABSPATH);
57
  }
58
 
59
  /**
60
  * Start Module
61
  * @return object
62
  */
63
- public function start()
64
- {
65
  // Root files
66
  $this->getRootFiles();
67
 
@@ -71,7 +70,7 @@ class Directories extends JobExecutable
71
  // Save option, progress
72
  $this->saveProgress();
73
 
74
- return (object) $this->response;
75
  }
76
 
77
  /**
@@ -79,12 +78,10 @@ class Directories extends JobExecutable
79
  * Returns false when over threshold limits are hit or when the job is done, true otherwise
80
  * @return bool
81
  */
82
- protected function execute()
83
- {
84
  // No job left to execute
85
- if ($this->isFinished())
86
- {
87
- $this->prepareResponse(true, false);
88
  return false;
89
  }
90
 
@@ -92,9 +89,8 @@ class Directories extends JobExecutable
92
  $directory = $this->options->directoriesToCopy[$this->options->currentStep];
93
 
94
  // Get files recursively
95
- if (!$this->getFilesFromSubDirectories($directory))
96
- {
97
- $this->prepareResponse(false, false);
98
  return false;
99
  }
100
 
@@ -112,57 +108,52 @@ class Directories extends JobExecutable
112
  * Checks Whether There is Any Job to Execute or Not
113
  * @return bool
114
  */
115
- private function isFinished()
116
- {
117
  return (
118
- $this->options->currentStep > $this->total ||
119
- empty($this->options->directoriesToCopy) ||
120
- !isset($this->options->directoriesToCopy[$this->options->currentStep])
121
- );
122
  }
123
 
124
  /**
125
  * @param $path
126
  * @return bool
127
  */
128
- protected function getFilesFromSubDirectories($path)
129
- {
130
  $this->totalRecursion++;
131
 
132
- if ($this->isOverThreshold())
133
- {
134
  //$this->saveProgress();
135
 
136
  return false;
137
  }
138
 
139
- $this->log("Scanning {$path} for its sub-directories and files");
140
 
141
- $directories = new \DirectoryIterator($path);
142
 
143
- foreach($directories as $directory)
144
- {
 
145
  // Not a valid directory
146
- if (false === ($path = $this->getPath($directory)))
147
- {
148
  continue;
149
  }
150
 
151
  // Excluded directory
152
- if ($this->isDirectoryExcluded($directory->getRealPath()))
153
- {
154
  continue;
155
  }
156
 
157
  // This directory is already scanned
158
- if (in_array($path, $this->options->scannedDirectories))
159
- {
160
  continue;
161
  }
162
 
163
  // Save all files
164
  $dir = ABSPATH . $path . DIRECTORY_SEPARATOR;
165
- $this->getFilesFromDirectory($dir);
166
 
167
  // Add scanned directory listing
168
  $this->options->scannedDirectories[] = $dir;
@@ -178,32 +169,35 @@ class Directories extends JobExecutable
178
  * @param $directory
179
  * @return bool
180
  */
181
- protected function getFilesFromDirectory($directory)
182
- {
183
  $this->totalRecursion++;
184
-
185
  // Save all files
186
- $files = array_diff(scandir($directory), array('.', ".."));
187
 
188
- foreach ($files as $file)
189
- {
190
  $fullPath = $directory . $file;
191
 
192
- if (is_dir($fullPath) && !in_array($fullPath, $this->options->directoriesToCopy) && !$this->isDirectoryExcluded($fullPath))
193
- {
194
  $this->options->directoriesToCopy[] = $fullPath;
195
- return $this->getFilesFromSubDirectories($fullPath);
 
196
  //continue;
197
  }
198
 
199
- if (!is_file($fullPath) || in_array($fullPath, $this->files))
200
- {
201
  continue;
202
  }
203
 
204
  $this->options->totalFiles++;
205
 
206
  $this->files[] = $fullPath;
 
 
 
 
 
 
207
  }
208
  }
209
 
@@ -212,13 +206,21 @@ class Directories extends JobExecutable
212
  * @param \SplFileInfo $directory
213
  * @return string|false
214
  */
215
- protected function getPath($directory)
216
- {
217
- $path = str_replace(ABSPATH, null, $directory->getRealPath());
 
 
 
 
 
 
 
 
 
218
 
219
  // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
220
- if (!$directory->isDir() || strlen($path) < 1 || strpos($directory->getRealPath(), ABSPATH) !== 0)
221
- {
222
  return false;
223
  }
224
 
@@ -226,15 +228,13 @@ class Directories extends JobExecutable
226
  }
227
 
228
  /**
 
229
  * @param string $directory
230
  * @return bool
231
  */
232
- protected function isDirectoryExcluded($directory)
233
- {
234
- foreach ($this->options->excludedDirectories as $excludedDirectory)
235
- {
236
- if (strpos($directory, $excludedDirectory) === 0)
237
- {
238
  return true;
239
  }
240
  }
@@ -242,39 +242,112 @@ class Directories extends JobExecutable
242
  return false;
243
  }
244
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
245
  /**
246
  * Save files
247
  * @return bool
248
  */
249
- protected function saveProgress()
250
- {
251
  $this->saveOptions();
252
 
253
- $fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
254
- $files = implode(PHP_EOL, $this->files);
255
 
256
- if (strlen($files) > 0)
257
- {
258
  //$files .= PHP_EOL;
259
  }
260
 
261
- return (false !== @file_put_contents($fileName, $files));
262
  }
263
 
264
  /**
265
  * Get files
266
  * @return void
267
  */
268
- protected function getFiles()
269
- {
270
- $fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
271
 
272
- if (false === ($this->files = file_get_contents($fileName)))
273
- {
274
  $this->files = array();
275
  return;
276
  }
277
 
278
- $this->files = explode(PHP_EOL, $this->files);
279
  }
280
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+
3
  namespace WPStaging\Backend\Modules\Jobs;
4
 
5
+ //ini_set('display_startup_errors', 1);
6
+ //ini_set('display_errors', 1);
7
+ //error_reporting(-1);
8
+
9
  // No Direct Access
10
+ if( !defined( "WPINC" ) ) {
 
11
  die;
12
  }
13
 
17
  * Class Files
18
  * @package WPStaging\Backend\Modules\Directories
19
  */
20
+ class Directories extends JobExecutable {
21
+
22
  /**
23
  * @var array
24
  */
32
  /**
33
  * Initialize
34
  */
35
+ public function initialize() {
36
+ $this->total = count( $this->options->directoriesToCopy );
 
37
  $this->getFiles();
38
  }
39
 
41
  * Calculate Total Steps in This Job and Assign It to $this->options->totalSteps
42
  * @return void
43
  */
44
+ protected function calculateTotalSteps() {
 
45
  $this->options->totalSteps = $this->total;
46
  }
47
 
48
  /**
49
  * Get Root Files
50
  */
51
+ protected function getRootFiles() {
52
+ if( 1 < $this->options->totalFiles ) {
 
 
53
  return;
54
  }
55
 
56
+ $this->getFilesFromDirectory( ABSPATH );
57
  }
58
 
59
  /**
60
  * Start Module
61
  * @return object
62
  */
63
+ public function start() {
 
64
  // Root files
65
  $this->getRootFiles();
66
 
70
  // Save option, progress
71
  $this->saveProgress();
72
 
73
+ return ( object ) $this->response;
74
  }
75
 
76
  /**
78
  * Returns false when over threshold limits are hit or when the job is done, true otherwise
79
  * @return bool
80
  */
81
+ protected function execute() {
 
82
  // No job left to execute
83
+ if( $this->isFinished() ) {
84
+ $this->prepareResponse( true, false );
 
85
  return false;
86
  }
87
 
89
  $directory = $this->options->directoriesToCopy[$this->options->currentStep];
90
 
91
  // Get files recursively
92
+ if( !$this->getFilesFromSubDirectories( $directory ) ) {
93
+ $this->prepareResponse( false, false );
 
94
  return false;
95
  }
96
 
108
  * Checks Whether There is Any Job to Execute or Not
109
  * @return bool
110
  */
111
+ private function isFinished() {
 
112
  return (
113
+ $this->options->currentStep > $this->total ||
114
+ empty( $this->options->directoriesToCopy ) ||
115
+ !isset( $this->options->directoriesToCopy[$this->options->currentStep] )
116
+ );
117
  }
118
 
119
  /**
120
  * @param $path
121
  * @return bool
122
  */
123
+ protected function getFilesFromSubDirectories( $path ) {
 
124
  $this->totalRecursion++;
125
 
126
+ if( $this->isOverThreshold() ) {
 
127
  //$this->saveProgress();
128
 
129
  return false;
130
  }
131
 
132
+ $this->log( "Scanning {$path} for its sub-directories and files" );
133
 
134
+ $directories = new \DirectoryIterator( $path );
135
 
136
+ foreach ( $directories as $directory ) {
137
+
138
+
139
  // Not a valid directory
140
+ if( false === ($path = $this->getPath( $directory )) ) {
 
141
  continue;
142
  }
143
 
144
  // Excluded directory
145
+ if( $this->isDirectoryExcluded( $directory->getRealPath() ) ) {
 
146
  continue;
147
  }
148
 
149
  // This directory is already scanned
150
+ if( in_array( $path, $this->options->scannedDirectories ) ) {
 
151
  continue;
152
  }
153
 
154
  // Save all files
155
  $dir = ABSPATH . $path . DIRECTORY_SEPARATOR;
156
+ $this->getFilesFromDirectory( $dir );
157
 
158
  // Add scanned directory listing
159
  $this->options->scannedDirectories[] = $dir;
169
  * @param $directory
170
  * @return bool
171
  */
172
+ protected function getFilesFromDirectory( $directory ) {
 
173
  $this->totalRecursion++;
174
+
175
  // Save all files
176
+ $files = array_diff( scandir( $directory ), array('.', "..") );
177
 
178
+ foreach ( $files as $file ) {
 
179
  $fullPath = $directory . $file;
180
 
181
+ if( is_dir( $fullPath ) && !in_array( $fullPath, $this->options->directoriesToCopy ) && !$this->isDirectoryExcluded( $fullPath ) ) {
 
182
  $this->options->directoriesToCopy[] = $fullPath;
183
+
184
+ return $this->getFilesFromSubDirectories( $fullPath );
185
  //continue;
186
  }
187
 
188
+ if( !is_file( $fullPath ) || in_array( $fullPath, $this->files ) ) {
 
189
  continue;
190
  }
191
 
192
  $this->options->totalFiles++;
193
 
194
  $this->files[] = $fullPath;
195
+
196
+ /**
197
+ * Test and measure if its faster to copy at the same time while the array with folders is generated
198
+ */
199
+ //$this->copy($fullPath);
200
+
201
  }
202
  }
203
 
206
  * @param \SplFileInfo $directory
207
  * @return string|false
208
  */
209
+ protected function getPath( $directory ) {
210
+
211
+ /*
212
+ * Do not follow root path like src/web/..
213
+ * This must be done before \SplFileInfo->isDir() is used!
214
+ * Prevents open base dir restriction fatal errors
215
+ */
216
+ if (strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
217
+ return false;
218
+ }
219
+
220
+ $path = str_replace( ABSPATH, null, $directory->getRealPath() );
221
 
222
  // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
223
+ if( !$directory->isDir() || strlen( $path ) < 1 ) {
 
224
  return false;
225
  }
226
 
228
  }
229
 
230
  /**
231
+ * Check if directory is excluded from copying
232
  * @param string $directory
233
  * @return bool
234
  */
235
+ protected function isDirectoryExcluded( $directory ) {
236
+ foreach ( $this->options->excludedDirectories as $excludedDirectory ) {
237
+ if( strpos( $directory, $excludedDirectory ) === 0 && !$this->isExtraDirectory( $directory ) ) {
 
 
 
238
  return true;
239
  }
240
  }
242
  return false;
243
  }
244
 
245
+ /**
246
+ * Check if directory is an extra directory and should be copied
247
+ * @param string $directory
248
+ * @return boolean
249
+ */
250
+ protected function isExtraDirectory( $directory ) {
251
+ foreach ( $this->options->extraDirectories as $extraDirectory ) {
252
+ if( strpos( $directory, $extraDirectory ) === 0 ) {
253
+ return true;
254
+ }
255
+ }
256
+
257
+ return false;
258
+ }
259
+
260
  /**
261
  * Save files
262
  * @return bool
263
  */
264
+ protected function saveProgress() {
 
265
  $this->saveOptions();
266
 
267
+ $fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
268
+ $files = implode( PHP_EOL, $this->files );
269
 
270
+ if( strlen( $files ) > 0 ) {
 
271
  //$files .= PHP_EOL;
272
  }
273
 
274
+ return (false !== @file_put_contents( $fileName, $files ));
275
  }
276
 
277
  /**
278
  * Get files
279
  * @return void
280
  */
281
+ protected function getFiles() {
282
+ $fileName = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
 
283
 
284
+ if( false === ($this->files = @file_get_contents( $fileName )) ) {
 
285
  $this->files = array();
286
  return;
287
  }
288
 
289
+ $this->files = explode( PHP_EOL, $this->files );
290
  }
291
+
292
+ /**
293
+ * Copy File using PHP (Only for testing)
294
+ * @param string $file
295
+ * @param string $destination
296
+ * @return bool
297
+ *
298
+ * @deprecated since version 2.0.2
299
+ */
300
+ protected function copy($file)
301
+ {
302
+
303
+ if( $this->isOverThreshold() ) {
304
+ return false;
305
+ }
306
+
307
+ // Failed to get destination
308
+ if (false === ($destination = $this->getDestination($file)))
309
+ {
310
+ //$this->log("Can't get the destination of {$file}");
311
+ //return false;
312
+ }
313
+
314
+ // Attempt to copy
315
+ if (!@copy($file, $destination))
316
+ {
317
+ //$this->log("Failed to copy file to destination: {$file} -> {$destination}", Logger::TYPE_ERROR);
318
+ //return false;
319
+ }
320
+
321
+ //$this->log("Copy {$file} -> {$destination}", Logger::TYPE_INFO);
322
+
323
+ // Not finished
324
+ return true;
325
+ }
326
+
327
+
328
+ /**
329
+ * (only for testing)
330
+ * Gets destination file and checks if the directory exists, if it does not attempts to create it.
331
+ * If creating destination directory fails, it returns false, gives destination full path otherwise
332
+ * @param string $file
333
+ * @return bool|string
334
+ *
335
+ * @deprecated
336
+ */
337
+ private function getDestination($file)
338
+ {
339
+ $destination = ABSPATH . $this->options->cloneDirectoryName . DIRECTORY_SEPARATOR;
340
+ $relativePath = str_replace(ABSPATH, null, $file);
341
+ $destinationPath = $destination . $relativePath;
342
+ $destinationDirectory = dirname($destinationPath);
343
+
344
+ if (!is_dir($destinationDirectory) && !@mkdir($destinationDirectory, 0775, true))
345
+ {
346
+ $this->log("Destination directory doesn't exist; {$destinationDirectory}", Logger::TYPE_ERROR);
347
+ //return false;
348
+ }
349
+
350
+ return $destinationPath;
351
+ }
352
+
353
+ }
apps/Backend/Modules/Jobs/Finish.php CHANGED
@@ -187,14 +187,7 @@ class Finish extends Job
187
  {
188
  // Check if clones still exist
189
  $this->log("Verifying existing clones...");
190
- // foreach ($this->options->existingClones as $name => $clone)
191
- // {
192
- // if (!is_dir($clone["path"]))
193
- // {
194
- // unset($this->options->existingClones[$name]);
195
- // }
196
- // }
197
- // $this->log("Existing clones verified!");
198
 
199
  // Clone data already exists
200
  if (isset($this->options->existingClones[$this->options->clone]))
@@ -214,22 +207,10 @@ class Finish extends Job
214
  "url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
215
  "number" => $this->options->cloneNumber,
216
  "version" => \WPStaging\WPStaging::VERSION,
 
217
  );
218
-
219
- // $array = json_decode(json_encode($this->options->existingClones[$this->options->clone], JSON_FORCE_OBJECT), false);
220
- //
221
- // var_dump($this->options->existingClones[$this->options->clone]);
222
- // echo '###########################';
223
- // var_dump($this->options->existingClones);
224
- // echo '###########################';
225
- // var_dump($array);
226
- // echo '###########################';
227
- //
228
- // die();
229
-
230
- //wp_die(var_dump($this->options->existingClones));
231
 
232
- if (false === update_option("wpstg_existing_clones", $this->options->existingClones))
233
  {
234
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
235
  return false;
187
  {
188
  // Check if clones still exist
189
  $this->log("Verifying existing clones...");
190
+
 
 
 
 
 
 
 
191
 
192
  // Clone data already exists
193
  if (isset($this->options->existingClones[$this->options->clone]))
207
  "url" => get_site_url() . '/' . $this->options->cloneDirectoryName,
208
  "number" => $this->options->cloneNumber,
209
  "version" => \WPStaging\WPStaging::VERSION,
210
+ "status" => false
211
  );
 
 
 
 
 
 
 
 
 
 
 
 
 
212
 
213
+ if (false === update_option("wpstg_existing_clones_beta", $this->options->existingClones))
214
  {
215
  $this->log("Failed to save {$this->options->clone}'s clone job data to database'");
216
  return false;
apps/Backend/Modules/Jobs/Job.php CHANGED
@@ -49,19 +49,22 @@ abstract class Job implements JobInterface
49
  protected $settings;
50
 
51
  /**
 
52
  * @var int
53
  */
54
  protected $maxMemoryLimit;
55
-
56
  /**
 
57
  * @var int
58
  */
59
- protected $maxExecutionTime;
60
 
61
  /**
62
  * @var int
63
  */
64
- protected $memoryLimit;
 
65
 
66
  /**
67
  * @var int
@@ -92,12 +95,19 @@ abstract class Job implements JobInterface
92
  $this->start = $this->time();
93
  $this->maxMemoryLimit = $this->getMemoryInBytes(@ini_get("memory_limit"));
94
  $this->maxExecutionTime = (int) ini_get("max_execution_time");
 
 
 
 
 
 
95
 
96
  if ($this->maxExecutionTime < 1)
97
  {
98
  $this->maxExecutionTime = 30;
99
  }
100
 
 
101
  // Services
102
  $this->cache = new Cache(-1, \WPStaging\WPStaging::getContentDir());
103
  $this->logger = WPStaging::getInstance()->get("logger");
@@ -173,7 +183,8 @@ abstract class Job implements JobInterface
173
  */
174
  protected function setLimits()
175
  {
176
- if (!isset($this->settings->wpstg_cpu_load))
 
177
  {
178
  $this->settings->cpuLoad = "medium";
179
  }
@@ -184,15 +195,15 @@ abstract class Job implements JobInterface
184
  switch($this->settings->cpuLoad)
185
  {
186
  case "medium":
187
- $memoryLimit= $memoryLimit / 2;
188
- $timeLimit = $timeLimit / 2;
189
  break;
190
  case "low":
191
- $memoryLimit= $memoryLimit / 4;
192
  $timeLimit = $timeLimit / 4;
193
  break;
194
 
195
- case "default":
196
  default:
197
  break;
198
  }
@@ -301,9 +312,12 @@ abstract class Job implements JobInterface
301
  // Check if the memory is over threshold
302
  $usedMemory = (int) @memory_get_usage(true);
303
 
 
 
304
  if ($usedMemory >= $this->memoryLimit)
305
  {
306
- $this->log('RESET MEMORY');
 
307
  return true;
308
  }
309
 
@@ -316,11 +330,10 @@ abstract class Job implements JobInterface
316
  // Check if execution time is over threshold
317
  ///$time = round($this->start + $this->time(), 4);
318
  $time = round($this->time() - $this->start, 4);
319
-
320
  if ($time >= $this->executionLimit)
321
  {
322
  //$this->log('RESET TIME');
323
- //return (!$this->resetTime());
324
  return true;
325
  }
326
 
@@ -331,7 +344,6 @@ abstract class Job implements JobInterface
331
  * Attempt to reset memory
332
  * @return bool
333
  *
334
- * @deprecated since version 2.0.0
335
  */
336
  protected function resetMemory()
337
  {
@@ -340,6 +352,7 @@ abstract class Job implements JobInterface
340
  // Failed to set
341
  if (false === ini_set("memory_limit", $this->formatBytes($newMemoryLimit)))
342
  {
 
343
  return false;
344
  }
345
 
@@ -418,12 +431,40 @@ abstract class Job implements JobInterface
418
  */
419
  protected function log($msg, $type = Logger::TYPE_INFO)
420
  {
 
 
 
 
 
421
  if (false === $this->hasLoggedFileNameSet && 0 < strlen($this->options->clone))
422
  {
423
  $this->logger->setFileName($this->options->clone);
424
  $this->hasLoggedFileNameSet = true;
425
  }
426
-
427
  $this->logger->add($msg, $type);
428
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429
  }
49
  protected $settings;
50
 
51
  /**
52
+ * System total maximum memory consumption
53
  * @var int
54
  */
55
  protected $maxMemoryLimit;
56
+
57
  /**
58
+ * Script maximum memory consumption
59
  * @var int
60
  */
61
+ protected $memoryLimit;
62
 
63
  /**
64
  * @var int
65
  */
66
+ protected $maxExecutionTime;
67
+
68
 
69
  /**
70
  * @var int
95
  $this->start = $this->time();
96
  $this->maxMemoryLimit = $this->getMemoryInBytes(@ini_get("memory_limit"));
97
  $this->maxExecutionTime = (int) ini_get("max_execution_time");
98
+ //$this->maxExecutionTime = (int) 30;
99
+
100
+ if ($this->maxExecutionTime > 30)
101
+ {
102
+ $this->maxExecutionTime = 30;
103
+ }
104
 
105
  if ($this->maxExecutionTime < 1)
106
  {
107
  $this->maxExecutionTime = 30;
108
  }
109
 
110
+
111
  // Services
112
  $this->cache = new Cache(-1, \WPStaging\WPStaging::getContentDir());
113
  $this->logger = WPStaging::getInstance()->get("logger");
183
  */
184
  protected function setLimits()
185
  {
186
+
187
+ if (!isset($this->settings->cpuLoad))
188
  {
189
  $this->settings->cpuLoad = "medium";
190
  }
195
  switch($this->settings->cpuLoad)
196
  {
197
  case "medium":
198
+ //$memoryLimit= $memoryLimit / 2; // 0.4
199
+ $timeLimit = $timeLimit / 2;
200
  break;
201
  case "low":
202
+ //$memoryLimit= $memoryLimit / 4; // 0.2
203
  $timeLimit = $timeLimit / 4;
204
  break;
205
 
206
+ case "fast": // 0.8
207
  default:
208
  break;
209
  }
312
  // Check if the memory is over threshold
313
  $usedMemory = (int) @memory_get_usage(true);
314
 
315
+ $this->debugLog('Used Memory: ' . $this->formatBytes( $usedMemory ) . ' Max Memory Limit: ' . $this->formatBytes( $this->maxMemoryLimit ) . ' Max Script Memory Limit: ' . $this->formatBytes( $this->memoryLimit), Logger::TYPE_DEBUG );
316
+
317
  if ($usedMemory >= $this->memoryLimit)
318
  {
319
+ $this->log('Used Memory: ' . $this->formatBytes($usedMemory) . ' Memory Limit: ' . $this->formatBytes($this->maxMemoryLimit) . ' Max Script memory limit: ' . $this->formatBytes( $this->memoryLimit ) );
320
+ $this->resetMemory();
321
  return true;
322
  }
323
 
330
  // Check if execution time is over threshold
331
  ///$time = round($this->start + $this->time(), 4);
332
  $time = round($this->time() - $this->start, 4);
333
+ $this->debugLog( 'Execution time: ' . $time . ' Execution Limit' . $this->executionLimit );
334
  if ($time >= $this->executionLimit)
335
  {
336
  //$this->log('RESET TIME');
 
337
  return true;
338
  }
339
 
344
  * Attempt to reset memory
345
  * @return bool
346
  *
 
347
  */
348
  protected function resetMemory()
349
  {
352
  // Failed to set
353
  if (false === ini_set("memory_limit", $this->formatBytes($newMemoryLimit)))
354
  {
355
+ $this->log('Can not free some memory', Logger::TYPE_CRITICAL);
356
  return false;
357
  }
358
 
431
  */
432
  protected function log($msg, $type = Logger::TYPE_INFO)
433
  {
434
+
435
+ if (!isset($this->options->clone)){
436
+ $this->options->clone = date(DATE_ATOM, mktime(0, 0, 0, 7, 1, 2000));
437
+ }
438
+
439
  if (false === $this->hasLoggedFileNameSet && 0 < strlen($this->options->clone))
440
  {
441
  $this->logger->setFileName($this->options->clone);
442
  $this->hasLoggedFileNameSet = true;
443
  }
444
+
445
  $this->logger->add($msg, $type);
446
  }
447
+ /**
448
+ * @param string $msg
449
+ * @param string $type
450
+ */
451
+ protected function debugLog($msg, $type = Logger::TYPE_INFO)
452
+ {
453
+
454
+ if (!isset($this->options->clone)){
455
+ $this->options->clone = date(DATE_ATOM, mktime(0, 0, 0, 7, 1, 2000));
456
+ }
457
+
458
+ if (false === $this->hasLoggedFileNameSet && 0 < strlen($this->options->clone))
459
+ {
460
+ $this->logger->setFileName($this->options->clone);
461
+ $this->hasLoggedFileNameSet = true;
462
+ }
463
+
464
+
465
+ if (isset($this->settings->debugMode)){
466
+ $this->logger->add($msg, $type);
467
+ }
468
+
469
+ }
470
  }
apps/Backend/Modules/Jobs/JobExecutable.php CHANGED
@@ -39,7 +39,7 @@ abstract class JobExecutable extends Job
39
 
40
  /**
41
  * Prepare Response Array
42
- * @param bool $status
43
  * @param bool $incrementCurrentStep
44
  * @return array
45
  */
39
 
40
  /**
41
  * Prepare Response Array
42
+ * @param bool $status false when the job is not done
43
  * @param bool $incrementCurrentStep
44
  * @return array
45
  */
apps/Backend/Modules/Jobs/Scan.php CHANGED
@@ -49,7 +49,7 @@ class Scan extends Job
49
  {
50
  // Basic Options
51
  $this->options->root = str_replace(array("\\", '/'), DIRECTORY_SEPARATOR, ABSPATH);
52
- $this->options->existingClones = get_option("wpstg_existing_clones", array());
53
  $this->options->current = null;
54
 
55
  if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $this->options->existingClones))
@@ -92,14 +92,14 @@ class Scan extends Job
92
  */
93
  public function formatSize($bytes, $precision = 2)
94
  {
95
- if ((int) $bytes < 1)
96
  {
97
  return '';
98
  }
99
 
100
  $units = array('B', "KB", "MB", "GB", "TB");
101
 
102
- $bytes = (int) $bytes;
103
  $base = log($bytes) / log(1000); // 1024 would be for MiB KiB etc
104
  $pow = pow(1000, $base - floor($base)); // Same rule for 1000
105
 
@@ -165,24 +165,33 @@ class Scan extends Job
165
  * Returns null when can't run disk_free_space function one way or another
166
  * @return bool|null
167
  */
168
- public function hasFreeDiskSpace()
169
- {
170
- if (!function_exists("disk_free_space"))
171
- {
172
- return null;
173
- }
174
 
175
- $freeSpace = @disk_free_space(ABSPATH);
176
 
177
- if (false === $freeSpace)
178
- {
179
- return null;
180
- }
 
 
 
 
181
 
182
- return ($freeSpace >= $this->getDirectorySize(ABSPATH));
183
- }
184
 
185
- /**
 
 
 
 
 
 
 
 
 
186
  * Get Database Tables
187
  */
188
  protected function getTables()
@@ -276,10 +285,18 @@ class Scan extends Job
276
  */
277
  protected function getPath($directory)
278
  {
 
 
 
 
 
 
 
 
279
  $path = str_replace(ABSPATH, null, $directory->getRealPath());
280
 
281
  // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
282
- if (!$directory->isDir() || strlen($path) < 1 || strpos($directory->getRealPath(), ABSPATH) !== 0)
283
  {
284
  return false;
285
  }
@@ -343,4 +360,18 @@ class Scan extends Job
343
 
344
  return $this->objDirectories->size($path);
345
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
346
  }
49
  {
50
  // Basic Options
51
  $this->options->root = str_replace(array("\\", '/'), DIRECTORY_SEPARATOR, ABSPATH);
52
+ $this->options->existingClones = get_option("wpstg_existing_clones_beta", array());
53
  $this->options->current = null;
54
 
55
  if (isset($_POST["clone"]) && array_key_exists($_POST["clone"], $this->options->existingClones))
92
  */
93
  public function formatSize($bytes, $precision = 2)
94
  {
95
+ if ((double) $bytes < 1)
96
  {
97
  return '';
98
  }
99
 
100
  $units = array('B', "KB", "MB", "GB", "TB");
101
 
102
+ $bytes = (double) $bytes;
103
  $base = log($bytes) / log(1000); // 1024 would be for MiB KiB etc
104
  $pow = pow(1000, $base - floor($base)); // Same rule for 1000
105
 
165
  * Returns null when can't run disk_free_space function one way or another
166
  * @return bool|null
167
  */
168
+ public function hasFreeDiskSpace() {
169
+ if( !function_exists( "disk_free_space" ) ) {
170
+ return null;
171
+ }
 
 
172
 
173
+ $freeSpace = @disk_free_space( ABSPATH );
174
 
175
+ if( false === $freeSpace ) {
176
+ $data = array(
177
+ 'freespace' => false,
178
+ 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
179
+ );
180
+ echo json_encode($data);
181
+ die();
182
+ }
183
 
 
 
184
 
185
+ $data = array(
186
+ 'freespace' => $this->formatSize($freeSpace),
187
+ 'usedspace' => $this->formatSize($this->getDirectorySizeInclSubdirs(ABSPATH))
188
+ );
189
+
190
+ echo json_encode( $data );
191
+ die();
192
+ }
193
+
194
+ /**
195
  * Get Database Tables
196
  */
197
  protected function getTables()
285
  */
286
  protected function getPath($directory)
287
  {
288
+ /*
289
+ * Do not follow root path like src/web/..
290
+ * This must be done before \SplFileInfo->isDir() is used!
291
+ * Prevents open base dir restriction fatal errors
292
+ */
293
+ if (strpos( $directory->getRealPath(), ABSPATH ) !== 0 ) {
294
+ return false;
295
+ }
296
  $path = str_replace(ABSPATH, null, $directory->getRealPath());
297
 
298
  // Using strpos() for symbolic links as they could create nasty stuff in nix stuff for directory structures
299
+ if (!$directory->isDir() || strlen($path) < 1)
300
  {
301
  return false;
302
  }
360
 
361
  return $this->objDirectories->size($path);
362
  }
363
+
364
+ /**
365
+ * Get total size of a directory including all its subdirectories
366
+ * @param string $dir
367
+ * @return int
368
+ */
369
+ function getDirectorySizeInclSubdirs( $dir ) {
370
+ $size = 0;
371
+ foreach ( glob( rtrim( $dir, '/' ) . '/*', GLOB_NOSORT ) as $each ) {
372
+ $size += is_file( $each ) ? filesize( $each ) : $this->getDirectorySizeInclSubdirs( $each );
373
+ }
374
+ return $size;
375
+ }
376
+
377
  }
apps/Backend/Modules/Optimizer.php DELETED
@@ -1,141 +0,0 @@
1
- <?php
2
- namespace WPStaging\Backend\Modules;
3
-
4
- use WPStaging\DI\InjectionAware;
5
-
6
- // No Direct Access
7
- if (!defined("WPINC"))
8
- {
9
- die;
10
- }
11
-
12
- /**
13
- * Class Optimizer
14
- * @package WPStaging\Backend\Modules;
15
- */
16
- class Optimizer extends InjectionAware
17
- {
18
-
19
- /**
20
- * @var array
21
- */
22
- private $wpFilter;
23
-
24
- /**
25
- * Optimizer constructor.
26
- */
27
- public function initialize()
28
- {
29
- $this->wpFilter = $this->getDI()->get("wpFilter");
30
- }
31
-
32
- /**
33
- * Remove TGM Plugin Activation "force_activation" from admin_init action hook if it exists
34
- * @desc Stop excluded plugins being deactivated after a migration when a theme uses TGMPA
35
- * to require a plugin to be always active
36
- * @return bool
37
- */
38
- public function compatibility()
39
- {
40
- if (!$this->shouldRemove() || !$this->wpFilter)
41
- {
42
- return false;
43
- }
44
-
45
- foreach ($this->wpFilter["admin_init"] as $priority => $functions)
46
- {
47
- foreach ($functions as $key => $function)
48
- {
49
- if (false !== strpos($key, "force_activation"))
50
- {
51
- unset($this->wpFilter["admin_init"][$priority][$key]);
52
- break;
53
- }
54
- }
55
- }
56
-
57
- return true;
58
- }
59
-
60
- /**
61
- * @return bool
62
- */
63
- public function shouldRemove()
64
- {
65
- return (
66
- (isset($_GET["page"]) && "wpstg_clone" === $_GET["page"]) ||
67
- $this->isCompatibilityModeRequest()
68
- );
69
- }
70
-
71
- /**
72
- * Checks if the current request should be processed by compatibility mode
73
- * @return bool
74
- */
75
- public function isCompatibilityModeRequest()
76
- {
77
- return (
78
- defined("DOING_AJAX") &&
79
- DOING_AJAX &&
80
- isset($_POST["action"]) &&
81
- false !== strpos($_POST["action"], "wpstg")
82
- );
83
- }
84
-
85
- /**
86
- * Returns an array of plugin slugs to be blacklisted.
87
- * @return array
88
- */
89
- public function blackListedPlugins()
90
- {
91
- $blackListedPlugins = $this->getDI()->get("settings")->getBlackListedPlugins();
92
-
93
- return (empty($blackListedPlugins)) ? $blackListedPlugins : array_flip($blackListedPlugins);
94
- }
95
-
96
- /**
97
- * @param array $plugins
98
- * @return array|bool
99
- */
100
- public function getBlackListedPluginsForExcludes($plugins = array())
101
- {
102
- if (!is_array($plugins) || empty($plugins) || !$this->isCompatibilityModeRequest())
103
- {
104
- return false;
105
- }
106
-
107
- $blackListedPlugins = $this->blackListedPlugins();
108
-
109
- if (empty($blackListedPlugins))
110
- {
111
- return false;
112
- }
113
-
114
- return $blackListedPlugins;
115
- }
116
-
117
- /**
118
- * Remove blacklisted plugins
119
- * @param array $plugins
120
- * @return array
121
- */
122
- public function excludedPlugins($plugins = array())
123
- {
124
- $blackListedPlugins = $this->getBlackListedPluginsForExcludes($plugins);
125
-
126
- if (false === $blackListedPlugins)
127
- {
128
- return $plugins;
129
- }
130
-
131
- foreach ($plugins as $key => $plugin)
132
- {
133
- if (false === strpos($plugin, "wp-staging") || isset($blackListedPlugins[$plugin]))
134
- {
135
- unset($plugins[$key]);
136
- }
137
- }
138
-
139
- return $plugins;
140
- }
141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
apps/Backend/Modules/Views/Forms/Settings.php CHANGED
@@ -85,7 +85,6 @@ class Settings
85
  $element = new Select(
86
  "wpstg_settings[cpuLoad]",
87
  array(
88
- "default" => "Default",
89
  "high" => "High (fast)",
90
  "medium" => "Medium (average)",
91
  "low" => "Low (slow)"
@@ -94,7 +93,7 @@ class Settings
94
 
95
  $this->form["general"]->add(
96
  $element->setLabel("CPU load priority")
97
- ->setDefault(isset($settings->cpuLoad) ? $settings->cpuLoad : "default")
98
  );
99
 
100
  // Optimizer
85
  $element = new Select(
86
  "wpstg_settings[cpuLoad]",
87
  array(
 
88
  "high" => "High (fast)",
89
  "medium" => "Medium (average)",
90
  "low" => "Low (slow)"
93
 
94
  $this->form["general"]->add(
95
  $element->setLabel("CPU load priority")
96
+ ->setDefault(isset($settings->cpuLoad) ? $settings->cpuLoad : "fast")
97
  );
98
 
99
  // Optimizer
apps/Backend/Notices/Notices.php CHANGED
@@ -2,13 +2,12 @@
2
 
3
  namespace WPStaging\Backend\Notices;
4
 
5
- /*
6
  * Admin Notices | Warnings | Messages
7
  */
8
 
9
  // No Direct Access
10
- if (!defined("WPINC"))
11
- {
12
  die;
13
  }
14
 
@@ -18,8 +17,7 @@ use WPStaging\WPStaging;
18
  * Class Notices
19
  * @package WPStaging\Backend\Notices
20
  */
21
- class Notices
22
- {
23
 
24
  /**
25
  * @var string
@@ -31,108 +29,119 @@ class Notices
31
  */
32
  private $url;
33
 
34
- public function __construct($path, $url)
35
- {
36
  $this->path = $path;
37
- $this->url = $url;
38
  }
39
-
40
  /**
41
  * Check whether the page is admin page or not
42
  * @return bool
43
  */
44
- private function isAdminPage()
45
- {
46
- $currentPage = (isset($_GET["page"])) ? $_GET["page"] : null;
47
 
48
  $availablePages = array(
49
  "wpstg-settings", "wpstg-addons", "wpstg-tools", "wpstg-clone", "wpstg_clone"
50
  );
51
 
52
- if (!is_admin() || !did_action("wp_loaded") || !in_array($currentPage, $availablePages, true))
53
- {
54
  return false;
55
  }
56
 
57
  return true;
58
  }
59
-
60
  /**
61
  * Check if notice should be shown after certain days of installation
62
  * @param int $days default 10
63
  * @return bool
64
  */
65
- private function canShow($option, $days = 10)
66
- {
67
-
68
- if (empty($option)){
69
  return false;
70
  }
71
-
72
- $installDate= new \DateTime(get_option("wpstg_installDate"));
73
- $now = new \DateTime("now");
74
 
75
  // Get days difference
76
- $difference = $now->diff($installDate)->days;
77
-
78
- return ($days <= $difference && "no" !== get_option($option));
79
-
80
  return false;
81
  }
82
 
83
- public function messages()
84
- {
 
 
85
  // Display messages to only admins, only on admin panel
86
- if (!current_user_can("update_plugins") || !$this->isAdminPage())
87
- {
88
  return;
89
  }
90
 
91
- $viewsNoticesPath = "{$this->path}views/_includes/messages/";
92
 
93
- $varsDirectory = \WPStaging\WPStaging::getContentDir();
94
-
95
-
96
- // Poll
97
- if ($this->canShow("wpstg_poll", 7))
98
- {
99
  require_once "{$viewsNoticesPath}poll.php";
100
- }
101
-
102
  // Cache directory in uploads is not writable
103
- if (!wp_is_writable($varsDirectory))
104
- {
105
  require_once "{$viewsNoticesPath}/uploads-cache-directory-permission-problem.php";
106
  }
107
  // Staging directory is not writable
108
- if (!wp_is_writable(get_home_path()))
109
- {
110
  require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
111
  }
112
 
113
  // Version Control
114
- if (version_compare(WPStaging::WP_COMPATIBLE, get_bloginfo("version"), "<"))
115
- {
116
  require_once "{$viewsNoticesPath}wp-version-compatible-message.php";
117
  }
118
 
119
  // Beta
120
- if (false === get_option("wpstg_beta") || "no" !== get_option("wpstg_beta"))
121
- {
122
  require_once "{$viewsNoticesPath}beta.php";
123
  }
124
 
125
  // WP Staging Pro and Free can not be activated both
126
- if (false !== ( $deactivatedNoticeID = get_transient("wp_staging_deactivated_notice_id") ))
127
- {
128
  require_once "{$viewsNoticesPath}transient.php";
129
- delete_transient("wp_staging_deactivated_notice_id");
130
  }
131
 
132
- if ($this->canShow("wpstg_rating", 7))
133
- {
134
  require_once "{$viewsNoticesPath}rating.php";
 
 
 
135
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
136
  }
137
  }
138
- }
 
2
 
3
  namespace WPStaging\Backend\Notices;
4
 
5
+ /*
6
  * Admin Notices | Warnings | Messages
7
  */
8
 
9
  // No Direct Access
10
+ if( !defined( "WPINC" ) ) {
 
11
  die;
12
  }
13
 
17
  * Class Notices
18
  * @package WPStaging\Backend\Notices
19
  */
20
+ class Notices {
 
21
 
22
  /**
23
  * @var string
29
  */
30
  private $url;
31
 
32
+ public function __construct( $path, $url ) {
 
33
  $this->path = $path;
34
+ $this->url = $url;
35
  }
36
+
37
  /**
38
  * Check whether the page is admin page or not
39
  * @return bool
40
  */
41
+ private function isAdminPage() {
42
+ $currentPage = (isset( $_GET["page"] )) ? $_GET["page"] : null;
 
43
 
44
  $availablePages = array(
45
  "wpstg-settings", "wpstg-addons", "wpstg-tools", "wpstg-clone", "wpstg_clone"
46
  );
47
 
48
+ if( !is_admin() || !did_action( "wp_loaded" ) || !in_array( $currentPage, $availablePages, true ) ) {
 
49
  return false;
50
  }
51
 
52
  return true;
53
  }
54
+
55
  /**
56
  * Check if notice should be shown after certain days of installation
57
  * @param int $days default 10
58
  * @return bool
59
  */
60
+ private function canShow( $option, $days = 10 ) {
61
+
62
+ if( empty( $option ) ) {
 
63
  return false;
64
  }
65
+
66
+ $installDate = new \DateTime( get_option( "wpstg_installDate" ) );
67
+ $now = new \DateTime( "now" );
68
 
69
  // Get days difference
70
+ $difference = $now->diff( $installDate )->days;
71
+
72
+ return ($days <= $difference && "no" !== get_option( $option ));
73
+
74
  return false;
75
  }
76
 
77
+ public function messages() {
78
+
79
+ $this->plugin_deactivated_notice();
80
+
81
  // Display messages to only admins, only on admin panel
82
+ if( !current_user_can( "update_plugins" ) || !$this->isAdminPage() ) {
 
83
  return;
84
  }
85
 
86
+ $viewsNoticesPath = "{$this->path}views/_includes/messages/";
87
 
88
+ $varsDirectory = \WPStaging\WPStaging::getContentDir();
89
+
90
+
91
+ // Poll do not show any longer
92
+ /*if( $this->canShow( "wpstg_poll", 7 ) ) {
 
93
  require_once "{$viewsNoticesPath}poll.php";
94
+ }*/
95
+
96
  // Cache directory in uploads is not writable
97
+ if( !wp_is_writable( $varsDirectory ) ) {
 
98
  require_once "{$viewsNoticesPath}/uploads-cache-directory-permission-problem.php";
99
  }
100
  // Staging directory is not writable
101
+ if( !wp_is_writable( get_home_path() ) ) {
 
102
  require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
103
  }
104
 
105
  // Version Control
106
+ if( version_compare( WPStaging::WP_COMPATIBLE, get_bloginfo( "version" ), "<" ) ) {
 
107
  require_once "{$viewsNoticesPath}wp-version-compatible-message.php";
108
  }
109
 
110
  // Beta
111
+ if( false === get_option( "wpstg_beta" ) || "no" !== get_option( "wpstg_beta" ) ) {
 
112
  require_once "{$viewsNoticesPath}beta.php";
113
  }
114
 
115
  // WP Staging Pro and Free can not be activated both
116
+ if( false !== ( $deactivatedNoticeID = get_transient( "wp_staging_deactivated_notice_id" ) ) ) {
 
117
  require_once "{$viewsNoticesPath}transient.php";
118
+ delete_transient( "wp_staging_deactivated_notice_id" );
119
  }
120
 
121
+ if( $this->canShow( "wpstg_rating", 7 ) ) {
 
122
  require_once "{$viewsNoticesPath}rating.php";
123
+ }
124
+
125
+ }
126
 
127
+ /**
128
+ * Show a message when pro or free plugin becomes deactivated
129
+ *
130
+ * @return void
131
+ */
132
+ private function plugin_deactivated_notice() {
133
+ if( false !== ( $deactivated_notice_id = get_transient( 'wp_staging_deactivated_notice_id' ) ) ) {
134
+ if( '1' === $deactivated_notice_id ) {
135
+ $message = __( "WP Staging and WP Staging Pro cannot both be active. We've automatically deactivated WP Staging.", 'wpstg' );
136
+ } else {
137
+ $message = __( "WP Staging and WP Staging Pro cannot both be active. We've automatically deactivated WP Staging Pro.", 'wpstg' );
138
+ }
139
+ ?>
140
+ <div class="updated notice is-dismissible" style="border-left: 4px solid #ffba00;">
141
+ <p><?php echo esc_html( $message ); ?></p>
142
+ </div> <?php
143
+ delete_transient( 'wp_staging_deactivated_notice_id' );
144
  }
145
  }
146
+
147
+ }
apps/Backend/Optimizer/Optimizer.php ADDED
@@ -0,0 +1,45 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ namespace WPStaging\Backend\Optimizer;
3
+
4
+ // No Direct Access
5
+ if( !defined( "WPINC" ) ) {
6
+ die;
7
+ }
8
+
9
+ /**
10
+ * Optimizer
11
+ */
12
+
13
+ class Optimizer {
14
+
15
+ private $mudir;
16
+ private $source;
17
+ private $dest;
18
+
19
+ public function __construct() {
20
+ $this->mudir = ( defined( 'WPMU_PLUGIN_DIR' ) && defined( 'WPMU_PLUGIN_URL' ) ) ? WPMU_PLUGIN_DIR : trailingslashit( WP_CONTENT_DIR ) . 'mu-plugins';
21
+
22
+ $this->source = trailingslashit( WPSTG_PLUGIN_DIR ) . 'apps/Backend/Optimizer/wp-staging-optimizer.php';
23
+ $this->dest = trailingslashit( $this->mudir ) . 'wp-staging-optimizer.php';
24
+ }
25
+
26
+ public function installOptimizer() {
27
+ if( wp_mkdir_p( $this->mudir ) ) {
28
+ $this->copy();
29
+ }
30
+ return false;
31
+ }
32
+
33
+ public function unstallOptimizer() {
34
+ if( file_exists( $this->dest ) && !unlink( $this->dest ) ) {
35
+ return false;
36
+ }
37
+ }
38
+
39
+ private function copy() {
40
+ if( !copy( $this->source, $this->dest ) ) {
41
+ return false;
42
+ }
43
+ }
44
+
45
+ }
apps/Backend/Optimizer/wp-staging-optimizer.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ Plugin Name: WP Staging Optimizer
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.0
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
17
+ *
18
+ * @param array $plugins numerically keyed array of plugin names
19
+ *
20
+ * @return array
21
+ */
22
+ function wpstg_exclude_plugins( $plugins ) {
23
+ if( !is_array( $plugins ) || empty( $plugins ) ) {
24
+ return $plugins;
25
+ }
26
+
27
+ if( !wpstg_is_compatibility_mode_request() ) {
28
+ return $plugins;
29
+ }
30
+
31
+ foreach ( $plugins as $key => $plugin ) {
32
+ if( false !== strpos( $plugin, 'wp-staging' ) ) {
33
+ continue;
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
45
+ *
46
+ * @param array $plugins array of plugins keyed by name (name=>timestamp pairs)
47
+ *
48
+ * @return array
49
+ */
50
+ function wpstg_exclude_site_plugins( $plugins ) {
51
+ if( !is_array( $plugins ) || empty( $plugins ) ) {
52
+ return $plugins;
53
+ }
54
+
55
+ if( !wpstg_is_compatibility_mode_request() ) {
56
+ return $plugins;
57
+ }
58
+
59
+
60
+ foreach ( array_keys( $plugins ) as $plugin ) {
61
+ if( false !== strpos( $plugin, 'wp-staging' ) || !isset( $blacklist_plugins[$plugin] ) ) {
62
+ continue;
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
+ /**
72
+ * Should the current request be processed by Compatibility Mode?
73
+ *
74
+ * @return bool
75
+ */
76
+ function wpstg_is_compatibility_mode_request() {
77
+ if( !defined( 'DOING_AJAX' ) ||
78
+ !DOING_AJAX ||
79
+ !isset( $_POST['action'] ) ||
80
+ false === strpos( $_POST['action'], 'wpstg' )
81
+ ) {
82
+
83
+ return false;
84
+ }
85
+ return true;
86
+ }
87
+
88
+ /**
89
+ * Remove TGM Plugin Activation 'force_activation' admin_init action hook if present.
90
+ *
91
+ * This is to stop excluded plugins being deactivated after a migration, when a theme uses TGMPA to require a plugin to be always active.
92
+ */
93
+ function wpstg_tgmpa_compatibility() {
94
+ $remove_function = false;
95
+
96
+ // run on wpstg page
97
+ if( isset( $_GET['page'] ) && 'wpstg_clone' == $_GET['page'] ) {
98
+ $remove_function = true;
99
+ }
100
+ // run on wpstg ajax requests
101
+ if( defined( 'DOING_AJAX' ) && DOING_AJAX && isset( $_POST['action'] ) && false !== strpos( $_POST['action'], 'wpstg' ) ) {
102
+ $remove_function = true;
103
+ }
104
+
105
+ if( $remove_function ) {
106
+ global $wp_filter;
107
+ $admin_init_functions = $wp_filter['admin_init'];
108
+ foreach ( $admin_init_functions as $priority => $functions ) {
109
+ foreach ( $functions as $key => $function ) {
110
+ // searching for function this way as can't rely on the calling class being named TGM_Plugin_Activation
111
+ if( false !== strpos( $key, 'force_activation' ) ) {
112
+ unset( $wp_filter['admin_init'][$priority][$key] );
113
+
114
+ return;
115
+ }
116
+ }
117
+ }
118
+ }
119
+ }
120
+ add_action( 'admin_init', 'wpstg_tgmpa_compatibility', 1 );
apps/Backend/Pluginmeta/Pluginmeta.php ADDED
@@ -0,0 +1,69 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend\Pluginmeta;
4
+
5
+ /*
6
+ * Admin Plugins Meta Data
7
+ */
8
+
9
+ // No Direct Access
10
+ if( !defined( "WPINC" ) ) {
11
+ die;
12
+ }
13
+
14
+ use WPStaging\WPStaging;
15
+
16
+
17
+ class Pluginmeta {
18
+
19
+ public function __construct() {
20
+ $this->defineHooks();
21
+ }
22
+
23
+ /**
24
+ * Define Hooks
25
+ */
26
+ public function defineHooks() {
27
+ add_filter( 'plugin_row_meta', array($this, 'rowMeta'), 10, 2 );
28
+ add_filter( 'plugin_action_links', array($this,'actionLinks'), 10, 2 );
29
+
30
+ }
31
+
32
+ /**
33
+ * Plugins row action links
34
+ *
35
+ * @author Michael Cannon <mc@aihr.us>
36
+ * @since 0.9.0
37
+ * @param array $links already defined action links
38
+ * @param string $file plugin file path and name being processed
39
+ * @return array $links
40
+ */
41
+ public function actionLinks( $links, $file ) {
42
+ $settings_link = '<a href="' . admin_url( 'admin.php?page=wpstg-settings' ) . '">' . esc_html__( 'Settings', 'wpstg' ) . '</a>';
43
+ if( $file == 'wp-staging/wp-staging.php' || $file == 'wp-staging-pro/wp-staging-pro.php')
44
+ array_unshift( $links, $settings_link );
45
+ return $links;
46
+ }
47
+
48
+ /**
49
+ * Plugin row meta links
50
+ *
51
+ * @author Michael Cannon <mc@aihr.us>
52
+ * @since 2.0
53
+ * @param array $input already defined meta links
54
+ * @param string $file plugin file path and name being processed
55
+ * @return array $input
56
+ */
57
+ public function rowMeta( $input, $file ) {
58
+ if( $file != 'wp-staging/wp-staging.php' && $file != 'wp-staging-pro/wp-staging-pro.php'){
59
+ return $input;
60
+ }
61
+
62
+ $links = array(
63
+ '<a href="' . admin_url( 'admin.php?page=wpstg_clone' ) . '">' . esc_html__( 'Start Now', 'wpstg' ) . '</a>',
64
+ );
65
+ $input = array_merge( $input, $links );
66
+ return $input;
67
+ }
68
+
69
+ }
apps/Backend/Upgrade/Upgrade.php CHANGED
@@ -7,7 +7,10 @@ use WPStaging\Utils\Logger;
7
 
8
  /**
9
  * Upgrade Class
 
 
10
  */
 
11
  // No Direct Access
12
  if( !defined( "WPINC" ) ) {
13
  die;
@@ -16,7 +19,7 @@ if( !defined( "WPINC" ) ) {
16
  class Upgrade {
17
 
18
  /**
19
- * Previous Version
20
  * @var string
21
  */
22
  private $previousVersion;
@@ -26,29 +29,80 @@ class Upgrade {
26
  * @var obj
27
  */
28
  private $clones;
29
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  private $logger;
31
 
32
  public function __construct() {
 
 
 
 
 
33
  $this->previousVersion = preg_replace( '/[^0-9.].*/', '', get_option( 'wpstg_version' ) );
 
 
34
  $this->clones = get_option( "wpstg_existing_clones", array() );
 
 
 
 
 
35
  $this->logger = new Logger;
36
  }
37
 
38
  public function doUpgrade() {
39
- // Previous version lower than 2.0.0 or new install
40
- if( false === $this->previousVersion || version_compare( $this->previousVersion, '2.0.0', '<' ) ) {
41
- $this->newInstall();
42
- $this->upgradeV1();
 
 
 
 
 
 
 
 
 
43
  $this->upgradeNotices();
44
  }
45
- $this->setVersion();
46
  }
47
-
48
  /**
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  * Upgrade routine for new install
50
  */
51
- private function newInstall(){
52
  // Write some default vars
53
  add_option( 'wpstg_installDate', date( 'Y-m-d h:i:s' ) );
54
  }
@@ -71,56 +125,90 @@ class Upgrade {
71
  }
72
 
73
  /**
74
- * Convert clone data from wpstg 1.x to wpstg 2.0.1
 
75
  */
76
- private function upgradeV1() {
 
 
 
77
 
78
  $new = array();
79
-
80
- if (empty($this->clones)){
81
  return false;
82
  }
83
 
 
84
  foreach ( $this->clones as $key => &$value ) {
85
-
86
- // Skip the rest of the loop if data is already compatible to wpstg 2.0.1
87
  if( isset( $value['directoryName'] ) || !empty( $value['directoryName'] ) ) {
88
  continue;
89
- }
 
90
  $new[$value]['directoryName'] = $value;
91
  $new[$value]['path'] = get_home_path() . $value;
92
  $new[$value]['url'] = get_home_url() . "/" . $value;
93
- $new[$value]['number'] = $key+1;
94
  $new[$value]['version'] = $this->previousVersion;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
95
 
 
 
96
  }
97
- unset($value);
98
- //var_dump( $new );
99
 
100
- if( empty($new) || false === update_option( 'wpstg_existing_clones', $new ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
101
  $this->logger->log( 'Failed to upgrade clone data from ' . $this->previousVersion . ' to ' . \WPStaging\WPStaging::VERSION );
102
- //wp_die('error');
103
  }
104
  }
105
-
106
  /**
107
- * Upgrade Notices Db options from wpstg 1.3 -> 2.0.1
108
  * Fix some logical db options
109
  */
110
- private function upgradeNotices(){
111
- $poll = get_option( "wpstg_start_poll", false );
112
- $beta = get_option( "wpstg_hide_beta", false );
113
- $rating = get_option( "wpstg_RatingDiv", false );
114
-
115
- if ($poll && $poll === "no"){
116
- update_option('wpstg_poll', 'no');
117
- }
118
- if ($beta && $beta === "yes"){
119
- update_option('wpstg_beta', 'no');
120
- }
121
- if ($rating && $rating === 'yes'){
122
- update_option('wpstg_rating', 'no');
123
- }
124
  }
125
 
126
  }
7
 
8
  /**
9
  * Upgrade Class
10
+ * This must be loaded on every page init to ensure all settings are
11
+ * adjusted correctly and to run any upgrade process if necessary.
12
  */
13
+
14
  // No Direct Access
15
  if( !defined( "WPINC" ) ) {
16
  die;
19
  class Upgrade {
20
 
21
  /**
22
+ * Previous Version number
23
  * @var string
24
  */
25
  private $previousVersion;
29
  * @var obj
30
  */
31
  private $clones;
32
+
33
+ /**
34
+ * Clone data
35
+ * @var obj
36
+ */
37
+ private $clonesBeta;
38
+
39
+ /**
40
+ * Cron data
41
+ * @var obj
42
+ */
43
+ private $cron;
44
+
45
+ /**
46
+ * Logger
47
+ * @var obj
48
+ */
49
  private $logger;
50
 
51
  public function __construct() {
52
+
53
+ // add wpstg_weekly_event to cron events
54
+ $this->cron = new \WPStaging\Cron\Cron;
55
+
56
+ // Previous version
57
  $this->previousVersion = preg_replace( '/[^0-9.].*/', '', get_option( 'wpstg_version' ) );
58
+
59
+ // Options earlier than version 2.0.0
60
  $this->clones = get_option( "wpstg_existing_clones", array() );
61
+
62
+ // Current options
63
+ $this->clonesBeta = get_option( "wpstg_existing_clones_beta", array() );
64
+
65
+ // Logger
66
  $this->logger = new Logger;
67
  }
68
 
69
  public function doUpgrade() {
70
+ $this->upgrade2_0_3();
71
+ //$this->upgrade2_0_4();
72
+ $this->setVersion();
73
+ }
74
+
75
+ /**
76
+ * Upgrade method 2.0.3
77
+ */
78
+ public function upgrade2_0_3() {
79
+ // Previous version lower than 2.0.2 or new install
80
+ if( false === $this->previousVersion || version_compare( $this->previousVersion, '2.0.2', '<' ) ) {
81
+ $this->upgradeOptions();
82
+ $this->upgradeClonesBeta();
83
  $this->upgradeNotices();
84
  }
 
85
  }
86
+
87
  /**
88
+ * Upgrade method 2.0.4
89
+ */
90
+ // public function upgrade2_0_4() {
91
+ // if( false === $this->previousVersion || version_compare( $this->previousVersion, '2.0.4', '<' ) ) {
92
+ //
93
+ // // Register cron job.
94
+ // $this->cron->schedule_event();
95
+ //
96
+ // // Install Optimizer
97
+ // $optimizer = new Optimizer();
98
+ // $optimizer->installOptimizer();
99
+ // }
100
+ // }
101
+
102
+ /**
103
  * Upgrade routine for new install
104
  */
105
+ private function upgradeOptions() {
106
  // Write some default vars
107
  add_option( 'wpstg_installDate', date( 'Y-m-d h:i:s' ) );
108
  }
125
  }
126
 
127
  /**
128
+ * Create a new db option for beta version 2.0.2
129
+ * @return bool
130
  */
131
+ private function upgradeClonesBeta() {
132
+
133
+ // Copy old data to new option
134
+ //update_option( 'wpstg_existing_clones_beta', $this->clones );
135
 
136
  $new = array();
137
+
138
+ if( empty( $this->clones ) ) {
139
  return false;
140
  }
141
 
142
+
143
  foreach ( $this->clones as $key => &$value ) {
144
+
145
+ // Skip the rest of the loop if data is already compatible to wpstg 2.0.2
146
  if( isset( $value['directoryName'] ) || !empty( $value['directoryName'] ) ) {
147
  continue;
148
+ }
149
+
150
  $new[$value]['directoryName'] = $value;
151
  $new[$value]['path'] = get_home_path() . $value;
152
  $new[$value]['url'] = get_home_url() . "/" . $value;
153
+ $new[$value]['number'] = $key + 1;
154
  $new[$value]['version'] = $this->previousVersion;
155
+ }
156
+ unset( $value );
157
+
158
+ if( empty( $new ) || false === update_option( 'wpstg_existing_clones_beta', $new ) ) {
159
+ $this->logger->log( 'Failed to upgrade clone data from ' . $this->previousVersion . ' to ' . \WPStaging\WPStaging::VERSION );
160
+ }
161
+ }
162
+
163
+ /**
164
+ * Convert clone data from wpstg 1.x to wpstg 2.x
165
+ * Only use this later when wpstg 2.x is ready for production
166
+ */
167
+ private function upgradeClones() {
168
+
169
+ $new = array();
170
 
171
+ if( empty( $this->clones ) ) {
172
+ return false;
173
  }
 
 
174
 
175
+ foreach ( $this->clones as $key => &$value ) {
176
+
177
+ // Skip the rest of the loop if data is already compatible to wpstg 2.0.1
178
+ if( isset( $value['directoryName'] ) || !empty( $value['directoryName'] ) ) {
179
+ continue;
180
+ }
181
+ $new[$value]['directoryName'] = $value;
182
+ $new[$value]['path'] = get_home_path() . $value;
183
+ $new[$value]['url'] = get_home_url() . "/" . $value;
184
+ $new[$value]['number'] = $key + 1;
185
+ $new[$value]['version'] = $this->previousVersion;
186
+ }
187
+ unset( $value );
188
+
189
+ if( empty( $new ) || false === update_option( 'wpstg_existing_clones', $new ) ) {
190
  $this->logger->log( 'Failed to upgrade clone data from ' . $this->previousVersion . ' to ' . \WPStaging\WPStaging::VERSION );
 
191
  }
192
  }
193
+
194
  /**
195
+ * Upgrade Notices db options from wpstg 1.3 -> 2.0.1
196
  * Fix some logical db options
197
  */
198
+ private function upgradeNotices() {
199
+ $poll = get_option( "wpstg_start_poll", false );
200
+ $beta = get_option( "wpstg_hide_beta", false );
201
+ $rating = get_option( "wpstg_RatingDiv", false );
202
+
203
+ if( $poll && $poll === "no" ) {
204
+ update_option( 'wpstg_poll', 'no' );
205
+ }
206
+ if( $beta && $beta === "yes" ) {
207
+ update_option( 'wpstg_beta', 'no' );
208
+ }
209
+ if( $rating && $rating === 'yes' ) {
210
+ update_option( 'wpstg_rating', 'no' );
211
+ }
212
  }
213
 
214
  }
apps/Backend/public/css/wpstg-admin.css CHANGED
@@ -190,14 +190,14 @@ color:#777777;
190
  /* Cloning workflow */
191
  #wpstg-clonepage-wrapper {
192
  margin-bottom: 20px;
193
- width: 690px;
194
  }
195
 
196
  @media screen and (min-width:1090px){
197
  #wpstg-clonepage-wrapper {
198
  float: left;
199
  margin-bottom: 20px;
200
- width: 690px;
201
  }
202
  .wpstg-sidebar{
203
  display: none;
@@ -371,17 +371,42 @@ color:#777777;
371
  margin-top:-5px;
372
  }
373
 
 
 
 
 
 
 
 
 
374
  #wpstg-workflow {
375
  position: relative;
376
  clear:both;
377
  padding-top:20px;
378
  margin-right:20px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
379
  }
380
 
381
  #wpstg-workflow.loading::after,
382
  #wpstg-removing-clone.loading::after {
383
  background: rgba(255, 255, 255, .7);
384
- content: 'LOADING May take little bit longer for large sites... ';
385
  display: block;
386
  width: 100%;
387
  height: 100%;
@@ -580,13 +605,16 @@ color:#777777;
580
 
581
  #wpstg-log-details{
582
  height: 300px;
 
583
  overflow: scroll;
584
- max-width: 650px;
585
- font-size: 11px;
 
 
586
  border: 1px solid #FFF;
587
  background-color: black;
588
- color: white;
589
- padding:10px;
590
  white-space: nowrap;
591
  margin-top: 15px;
592
  }
@@ -676,4 +704,69 @@ color:#777777;
676
 
677
  .wpstg-share-button-twitter .share:active,.wpstg-share-button-facebook .share:active,.wpstg-share-button-googleplus .share:active {
678
  background-color:#353535;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
679
  }
190
  /* Cloning workflow */
191
  #wpstg-clonepage-wrapper {
192
  margin-bottom: 20px;
193
+ /*width: 690px; */
194
  }
195
 
196
  @media screen and (min-width:1090px){
197
  #wpstg-clonepage-wrapper {
198
  float: left;
199
  margin-bottom: 20px;
200
+ /*width: 690px;*/
201
  }
202
  .wpstg-sidebar{
203
  display: none;
371
  margin-top:-5px;
372
  }
373
 
374
+ #wpstg-loader.wpstg-finished {
375
+ content:"Finished";
376
+ background-color:#00c89a;
377
+ color:white;
378
+ padding:2px;
379
+ margin-top:6px;
380
+ }
381
+
382
  #wpstg-workflow {
383
  position: relative;
384
  clear:both;
385
  padding-top:20px;
386
  margin-right:20px;
387
+ float:left;
388
+ min-width: 500px;
389
+ border-right: 1px solid #DFDFDF;
390
+ min-height: 380px;
391
+ padding-right: 20px;
392
+ }
393
+
394
+ #wpstg-sidebar {
395
+ float: left;
396
+ max-width: 400px;
397
+ display: block;
398
+ }
399
+
400
+ @media screen and (max-width:1150px){
401
+ #wpstg-sidebar img{
402
+ margin-top: 30px;
403
+ }
404
  }
405
 
406
  #wpstg-workflow.loading::after,
407
  #wpstg-removing-clone.loading::after {
408
  background: rgba(255, 255, 255, .7);
409
+ content: 'Loading... may take a while for huge websites';
410
  display: block;
411
  width: 100%;
412
  height: 100%;
605
 
606
  #wpstg-log-details{
607
  height: 300px;
608
+ max-width: 700px;
609
  overflow: scroll;
610
+ /*max-width: 650px;*/
611
+ font-family: monospace;
612
+ font-size: 12px;
613
+ line-height: 15px;
614
  border: 1px solid #FFF;
615
  background-color: black;
616
+ color: #c0c0c0;
617
+ padding:3px;
618
  white-space: nowrap;
619
  margin-top: 15px;
620
  }
704
 
705
  .wpstg-share-button-twitter .share:active,.wpstg-share-button-facebook .share:active,.wpstg-share-button-googleplus .share:active {
706
  background-color:#353535;
707
+ }
708
+
709
+ #wpstg-check-space {
710
+ margin-left:8px;
711
+ }
712
+
713
+ /* welcome screen */
714
+ .wpstg-button.green {
715
+ display: inline-block;
716
+ background-color: #83c11f;
717
+ padding: 10px;
718
+ min-width: 170px;
719
+ color: white;
720
+ font-size: 16px;
721
+ text-decoration: none;
722
+ text-align: center;
723
+ margin-top: 20px;
724
+ }
725
+ #wpstg-welcome li {
726
+ font-size: 18px;
727
+ line-height: 29px;
728
+ position: relative;
729
+ padding-left: 23px;
730
+ list-style: none!important;
731
+ }
732
+ #wpstg-welcome {
733
+ margin-top:20px;
734
+ margin-right: 20px;
735
+ background-color: white;
736
+ }
737
+ .wpstg-heading-pro {
738
+ color: #0080ff;
739
+ font-weight: bold;
740
+ }
741
+ .wpstg-h2 {
742
+ margin-top: 0px;
743
+ margin-bottom: 1.2rem;
744
+ font-size: 30px;
745
+ line-height: 2.5rem;
746
+ }
747
+ #wpstg-welcome li:before {
748
+ width: 1em;
749
+ height: 100%;
750
+ background: url(data:image/svg+xml;charset=utf8,%3Csvg%20width%3D%221792%22%20height%3D%221792%22%20viewBox%3D%220%200%201792%201792%22%20xmlns%3D%22http%3A%2F%2Fwww%2Ew3%2Eorg%2F2000%2Fsvg%22%3E%3Cpath%20fill%3D%22%2377B227%22%20d%3D%22M1671%20566q0%2040%2D28%2068l%2D724%20724%2D136%20136q%2D28%2028%2D68%2028t%2D68%2D28l%2D136%2D136%2D362%2D362q%2D28%2D28%2D28%2D68t28%2D68l136%2D136q28%2D28%2068%2D28t68%2028l294%20295%20656%2D657q28%2D28%2068%2D28t68%2028l136%20136q28%2028%2028%2068z%22%2F%3E%3C%2Fsvg%3E) left .4em no-repeat;
751
+ background-size: contain;
752
+ content: "";
753
+ position: absolute;
754
+ top: 0;
755
+ left: 0;
756
+ color: #77b227;
757
+ }
758
+ .wpstg-h1 {
759
+ font-size: 2.75em;
760
+ margin-bottom: 1.35rem;
761
+ font-size: 2.5em;
762
+ line-height: 3.68rem;
763
+ letter-spacing: normal;
764
+ }
765
+ #wpstg-welcome h2 {
766
+ margin: 0 0 15px;
767
+ }
768
+ #wpstg-welcome .wpstg-footer {
769
+ clear: both;
770
+ margin-top: 20px;
771
+ font-style: italic;
772
  }
apps/Backend/public/img/wpstaging-banner200x400-tryout.gif ADDED
Binary file
apps/Backend/public/img/wpstaging-banner200x400.gif ADDED
Binary file
apps/Backend/public/js/wpstg-admin.js CHANGED
@@ -1,21 +1,22 @@
1
  "use strict";
2
 
3
- var WPStaging = (function($)
4
  {
5
- var that = {
6
- isCancelled : false,
7
- isFinished : false,
8
- getLogs : false
9
- },
10
- cache = {elements : []},
11
- timeout, ajaxSpinner;
 
12
 
13
  /**
14
  * Get / Set Cache for Selector
15
  * @param {String} selector
16
  * @returns {*}
17
  */
18
- cache.get = function(selector)
19
  {
20
  // It is already cached!
21
  if ($.inArray(selector, cache.elements) !== -1)
@@ -33,7 +34,7 @@ var WPStaging = (function($)
33
  * Refreshes given cache
34
  * @param {String} selector
35
  */
36
- cache.refresh = function(selector)
37
  {
38
  selector.elements[selector] = jQuery(selector);
39
  };
@@ -42,15 +43,15 @@ var WPStaging = (function($)
42
  * Show and Log Error Message
43
  * @param {String} message
44
  */
45
- var showError = function(message)
46
  {
47
  cache.get("#wpstg-try-again").css("display", "inline-block");
48
  cache.get("#wpstg-cancel-cloning").text("Reset");
49
  cache.get("#wpstg-cloning-result").text("Fail");
50
  cache.get("#wpstg-error-wrapper").show();
51
  cache.get("#wpstg-error-details")
52
- .show()
53
- .html(message);
54
 
55
  cache.get("#wpstg-loader").hide();
56
  };
@@ -58,12 +59,12 @@ var WPStaging = (function($)
58
  /**
59
  * Common Elements
60
  */
61
- var elements = function()
62
  {
63
- var $workFlow = cache.get("#wpstg-workflow"),
64
- isAllChecked = true,
65
- urlSpinner = ajaxurl.replace("/admin-ajax.php", '') + "/images/spinner",
66
- timer;
67
 
68
  if (2 < window.devicePixelRatio)
69
  {
@@ -75,200 +76,198 @@ var WPStaging = (function($)
75
  ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
76
 
77
  $workFlow
78
- // Check / Un-check Database Tables
79
- .on("click", ".wpstg-button-unselect", function (e) {
80
- e.preventDefault();
81
 
82
- if (false === isAllChecked)
83
- {
84
- cache.get(".wpstg-db-table-checkboxes").prop("checked", true);
85
- cache.get(".wpstg-button-unselect").text("Un-check All");
86
- isAllChecked = true;
87
- }
88
- else
89
- {
90
- cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
91
- cache.get(".wpstg-button-unselect").text("Check All");
92
- isAllChecked = false;
93
- }
94
- })
95
- // Expand Directories
96
- .on("click", ".wpstg-expand-dirs", function (e) {
97
- e.preventDefault();
98
 
99
- var $this = $(this);
100
 
101
- if (!$this.hasClass("disabled"))
102
- {
103
- $this.siblings(".wpstg-subdir").slideToggle();
104
- }
105
- })
106
- // When a Directory is Selected
107
- .on("change", ".wpstg-check-dir", function () {
108
- var $directory = $(this).parent(".wpstg-dir");
109
 
110
- if (this.checked)
111
- {
112
- $directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
113
- $directory.find(".wpstg-expand-dirs").removeClass("disabled");
114
- $directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
115
- }
116
- else
117
- {
118
- $directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
119
- $directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
120
- $directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
121
- $directory.children(".wpstg-subdir").slideUp();
122
- }
123
- })
124
- // Check the max length of the clone name and if the clone name already exists
125
- .on("keyup", "#wpstg-new-clone-id", function () {
126
 
127
- // This request was already sent, clear it up!
128
- if ("number" === typeof(timer))
129
- {
130
- clearInterval(timer);
131
- }
132
 
133
- var cloneID = this.value;
134
 
135
- timer = setTimeout(
136
- function() {
137
- ajax(
138
- {
139
- action : "wpstg_check_clone",
140
- cloneID : cloneID
141
- },
142
- function(response)
143
- {
144
- if (response.status === "success")
145
- {
146
- cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
147
- cache.get("#wpstg-start-cloning").removeAttr("disabled");
148
- cache.get("#wpstg-clone-id-error").text('').hide();
149
- }
150
- else
151
  {
152
- cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
153
- cache.get("#wpstg-start-cloning").prop("disabled", true);
154
- cache.get("#wpstg-clone-id-error").text(response.message).show();
 
 
 
 
 
 
 
 
 
155
  }
156
- }
157
- );
158
- },
159
- 500
160
- );
161
- })
162
- // Restart cloning process
163
- .on("click", "#wpstg-start-cloning", function() {
164
- that.isCancelled= false;
165
- that.getLogs = false;
166
- })
167
- // Display logs
168
- .on("click", "#wpstg-show-log-button", function (e) {
169
- e.preventDefault();
170
- var $logDetails = cache.get("#wpstg-log-details");
171
 
172
- $logDetails.toggle();
173
 
174
- logscroll();
175
 
176
- that.getLogs = (false === that.getLogs);
177
- });
178
 
179
  cloneActions();
180
  };
181
-
182
 
183
  /**
184
  * Clone actions
185
  */
186
- var cloneActions = function()
187
  {
188
  var $workFlow = cache.get("#wpstg-workflow");
189
 
190
  $workFlow
191
- // Cancel cloning
192
- .on("click", "#wpstg-cancel-cloning", function() {
193
- if (!confirm("Are you sure you want to cancel cloning process?"))
194
- {
195
- return false;
196
- }
197
 
198
- var $this = $(this);
199
 
200
- $("#wpstg-try-again, #wpstg-home-link").hide();
201
- $this.prop("disabled", true);
202
 
203
- that.isCancelled = true;
204
 
205
- $("#wpstg-cloning-result").text("Please wait...this can take up to a minute");
206
- $("#wpstg-loader, #wpstg-show-log-button").hide();
207
 
208
- $this.parent().append(ajaxSpinner);
209
 
210
- cancelCloning();
211
- })
212
- // Delete clone - confirmation
213
- .on("click", ".wpstg-remove-clone[data-clone]", function(e) {
214
- e.preventDefault();
215
 
216
- var $existingClones = cache.get("#wpstg-existing-clones");
217
 
218
- $workFlow.removeClass('active');
219
-
220
- cache.get("#wpstg-loader").show();
221
 
222
- ajax(
223
- {
224
- action : "wpstg_confirm_delete_clone",
225
- nonce : wpstg.nonce,
226
- clone : $(this).data("clone")
227
- },
228
- function(response)
 
 
229
  {
230
  cache.get("#wpstg-removing-clone").html(response);
231
 
232
  $existingClones.children("img").remove();
233
-
234
  cache.get("#wpstg-loader").hide();
235
  },
236
- "HTML"
237
- );
238
- })
239
- // Delete clone - confirmed
240
- .on("click", "#wpstg-remove-clone", function (e) {
241
- e.preventDefault();
242
-
243
- cache.get("#wpstg-removing-clone").addClass("loading");
244
-
245
- //$this.parent().append(ajaxSpinner);
246
-
247
- cache.get("#wpstg-loader").show();
248
-
249
- deleteClone($(this).data("clone"));
250
- })
251
- // Cancel deleting clone
252
- .on("click", "#wpstg-cancel-removing", function (e) {
253
- e.preventDefault();
254
- $(".wpstg-clone").removeClass("active");
255
- cache.get("#wpstg-removing-clone").html('');
256
- })
257
- // Edit
258
- .on("click", ".wpstg-execute-clone", function (e) {
259
- e.preventDefault();
260
-
261
- var clone = $(this).data("clone");
262
-
263
- $workFlow.addClass("loading");
264
-
265
- ajax(
266
- {
267
- action : "wpstg_scanning",
268
- clone : clone,
269
- nonce : wpstg.nonce
270
- },
271
- function(response)
272
  {
273
  if (response.length < 1)
274
  {
@@ -278,13 +277,13 @@ var WPStaging = (function($)
278
  $workFlow.removeClass("loading").html(response);
279
 
280
  cache.get(".wpstg-current-step")
281
- .removeClass("wpstg-current-step")
282
- .next("li")
283
- .addClass("wpstg-current-step");
284
  },
285
- "HTML"
286
- );
287
- });
288
  };
289
 
290
  /**
@@ -294,9 +293,9 @@ var WPStaging = (function($)
294
  * @param {String} dataType
295
  * @param {Boolean} showErrors
296
  */
297
- var ajax = function(data, callback, dataType, showErrors)
298
  {
299
- if ("undefined" === typeof(dataType))
300
  {
301
  dataType = "json";
302
  }
@@ -307,12 +306,12 @@ var WPStaging = (function($)
307
  }
308
 
309
  $.ajax({
310
- url : ajaxurl,
311
- type : "POST",
312
- dataType : dataType,
313
- cache : false,
314
- data : data,
315
- error : function(xhr, textStatus, errorThrown) {
316
  console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
317
  console.log(textStatus);
318
 
@@ -322,24 +321,23 @@ var WPStaging = (function($)
322
  }
323
 
324
  showError(
325
- "Fatal Error: This should not happen but is most often caused by other plugins. " +
326
- "Try first the option 'Optimizer' in WP Staging->Settings and try again. " +
327
- "If this does not help, enable " +
328
- "<a href='https://codex.wordpress.org/Debugging_in_WordPress' target='_blank'>wordpress debug mode</a> " +
329
- "to find out which plugin is causing this."
330
- );
331
  },
332
- success : function(data) {
333
- if ("function" === typeof(callback))
334
  {
335
  callback(data);
336
  }
337
  },
338
- statusCode : {
339
- 404: function() {
340
  showError("Something went wrong; can't find ajax request URL!");
341
  },
342
- 500: function() {
343
  showError("Something went wrong; internal server error while processing the request!");
344
  }
345
  }
@@ -349,77 +347,76 @@ var WPStaging = (function($)
349
  /**
350
  * Next / Previous Step Clicks to Navigate Through Staging Job
351
  */
352
- var stepButtons = function()
353
  {
354
  var $workFlow = cache.get("#wpstg-workflow");
355
 
356
  $workFlow
357
- // Next Button
358
- .on("click", ".wpstg-next-step-link", function(e) {
359
- e.preventDefault();
360
 
361
- var $this = $(this),
362
- isScan = false;
363
 
364
- // Button is disabled
365
- if ($this.attr("disabled"))
366
- {
367
- return false;
368
- }
369
 
370
- // Add loading overlay
371
- $workFlow.addClass("loading");
372
 
373
- // Prepare data
374
- that.data = {
375
- action : $this.data("action"),
376
- nonce : wpstg.nonce
377
- };
378
 
379
- // Cloning data
380
- getCloningData();
381
 
382
- console.log(that.data);
383
 
384
- isScan = ("wpstg_scanning" === that.action);
385
- console.log(isScan);
386
 
387
- // Send ajax request
388
- ajax(
389
- that.data,
390
- function(response) {
391
 
392
- if (response.length < 1)
393
- {
394
- showError("Something went wrong, please try again");
395
- }
396
 
397
- // Styling of elements
398
- $workFlow.removeClass("loading").html(response);
399
 
400
- cache.get(".wpstg-current-step")
401
- .removeClass("wpstg-current-step")
402
- .next("li")
403
- .addClass("wpstg-current-step");
404
 
405
- // Start cloning
406
- that.startCloning();
407
- },
408
- "HTML"
409
- );
410
- })
411
- // Previous Button
412
- .on("click", ".wpstg-prev-step-link", function(e) {
413
- e.preventDefault();
414
- loadOverview();
415
- });
416
  };
417
 
418
  /**
419
  * Get Excluded (Unchecked) Database Tables
420
  * @returns {Array}
421
  */
422
- var getExcludedTables = function()
423
  {
424
  var excludedTables = [];
425
 
@@ -434,7 +431,7 @@ var WPStaging = (function($)
434
  * Get Included Directories
435
  * @returns {Array}
436
  */
437
- var getIncludedDirectories = function()
438
  {
439
  var includedDirectories = [];
440
 
@@ -453,7 +450,7 @@ var WPStaging = (function($)
453
  * Get Excluded Directories
454
  * @returns {Array}
455
  */
456
- var getExcludedDirectories = function()
457
  {
458
  var excludedDirectories = [];
459
 
@@ -468,68 +465,89 @@ var WPStaging = (function($)
468
  return excludedDirectories;
469
  };
470
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
471
  /**
472
  * Get Cloning Step Data
473
  */
474
- var getCloningData = function()
475
  {
476
  if ("wpstg_cloning" !== that.data.action)
477
  {
478
  return;
479
  }
480
 
481
- that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
482
- that.data.excludedTables = getExcludedTables();
483
- that.data.includedDirectories = getIncludedDirectories();
484
- that.data.excludedDirectories = getExcludedDirectories();
485
- that.data.extraDirectories = $("#wpstg_extraDirectories").val() || null;
 
 
 
486
  };
487
 
488
  /**
489
  * Loads Overview (first step) of Staging Job
490
  */
491
- var loadOverview = function()
492
  {
493
  var $workFlow = cache.get("#wpstg-workflow");
494
 
495
  $workFlow.addClass("loading");
496
 
497
  ajax(
498
- {
499
- action : "wpstg_overview",
500
- nonce : wpstg.nonce
501
- },
502
- function(response) {
503
-
504
- if (response.length < 1)
505
  {
506
- showError("Something went wrong, please try again");
507
- }
 
 
508
 
509
- var $currentStep = cache.get(".wpstg-current-step");
 
 
 
510
 
511
- // Styling of elements
512
- $workFlow.removeClass("loading").html(response);
513
 
514
- $currentStep
515
- .removeClass("wpstg-current-step")
516
- .next("li")
517
- .addClass("wpstg-current-step");
518
- },
519
- "HTML"
520
- );
521
  };
522
 
523
  /**
524
  * Tabs
525
  */
526
- var tabs = function()
527
  {
528
- cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function(e) {
529
  e.preventDefault();
530
 
531
- var $this = $(this),
532
- $section = cache.get($this.data("id"));
533
 
534
  $this.toggleClass("expand");
535
 
@@ -550,42 +568,49 @@ var WPStaging = (function($)
550
  * Delete Clone
551
  * @param {String} clone
552
  */
553
- var deleteClone = function(clone)
554
  {
555
-
556
  ajax(
557
- {
558
- action : "wpstg_delete_clone",
559
- clone : clone,
560
- nonce : wpstg.nonce,
561
- excludedTables : getExcludedTables(),
562
- deleteDir : $("#deleteDirectory:checked").val()
563
- },
564
- function(response)
565
- {
566
- if (true !== response)
567
  {
568
- deleteClone(clone);
569
- return;
570
- }
 
 
 
 
 
 
 
571
 
572
- cache.get("#wpstg-removing-clone").removeClass("loading").html('');
573
- $(".wpstg-clone#" + clone).remove();
574
 
575
- if ($(".wpstg-clone").length < 1)
576
- {
577
- cache.get("#wpstg-existing-clones").find("h3").text('');
 
 
 
 
578
  }
579
-
580
- cache.get("#wpstg-loader").hide();
581
  }
 
 
 
 
 
 
 
 
582
  );
583
  };
584
 
585
  /**
586
  * Cancel Cloning Process
587
  */
588
- var cancelCloning = function()
589
  {
590
  if (true === that.isFinished)
591
  {
@@ -593,32 +618,41 @@ var WPStaging = (function($)
593
  }
594
 
595
  ajax(
596
- {
597
- action : "wpstg_cancel_clone",
598
- clone : that.data.cloneID,
599
- nonce : wpstg.nonce
600
- },
601
- function(response)
602
- {
603
- if (true !== response)
604
  {
605
- cancelCloning();
606
- return;
607
- }
608
-
 
 
 
 
 
609
  // Load overview
610
  loadOverview();
 
 
 
 
 
 
 
 
611
  }
 
 
 
 
612
  );
613
  };
614
-
615
  /**
616
  * Scroll the window log to bottom
617
  * @returns void
618
  */
619
  var logscroll = function () {
620
  var $div = cache.get("#wpstg-log-details");
621
- if ("undefined" !== typeof($div[0])){
622
  $div.scrollTop($div[0].scrollHeight);
623
  }
624
  }
@@ -630,17 +664,19 @@ var WPStaging = (function($)
630
  */
631
  var getLogs = function (log)
632
  {
633
-
634
-
635
-
636
  if (log != null && "undefined" !== typeof (log)) {
637
  if (log.constructor === Array) {
638
  $.each(log, function (index, value) {
 
639
  //console.log(index, value);
640
- cache.get("#wpstg-log-details").append(value.type + ' ' + value.date + ' ' + value.message + '</br>');
 
 
 
 
641
  })
642
  } else {
643
- cache.get("#wpstg-log-details").append(log.type + ' ' + log.date + ' ' + log.message + '</br>');
644
  }
645
  }
646
  logscroll();
@@ -650,7 +686,7 @@ var WPStaging = (function($)
650
  /**
651
  * Optimizer
652
  */
653
- var optimizer = function()
654
  {
655
  var $optimizer = cache.get('input[name="wpstg_settings\[optimizer\]"]');
656
 
@@ -658,7 +694,7 @@ var WPStaging = (function($)
658
  optimizerAction($optimizer.is(':checked'));
659
 
660
  // On action
661
- $optimizer.on('change', function(){
662
  optimizerAction(this.checked);
663
  });
664
 
@@ -674,34 +710,46 @@ var WPStaging = (function($)
674
  }
675
  };
676
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
677
  /**
678
  * Start Cloning Process
679
  * @type {Function}
680
  */
681
- that.startCloning = (function() {
 
 
 
 
682
  if ("wpstg_cloning" !== that.data.action)
683
  {
684
- console.log("check disk space");
685
- ajax(
686
- {
687
- action: "wpstg_check_disk_space",
688
- nonce: wpstg.nonce
689
- },
690
- function(response)
691
- {
692
- if (false !== response)
693
- {
694
- cache.get("#wpstg-clone-id-error").hide();
695
- return;
696
- }
697
-
698
- // Not enough disk space
699
- cache.get("#wpstg-clone-id-error").show();
700
- },
701
- "json",
702
- false
703
- );
704
-
705
  return;
706
  }
707
 
@@ -717,7 +765,9 @@ var WPStaging = (function($)
717
  cache.get("#wpstg-loader").show();
718
 
719
  // Clone Database
720
- setTimeout(function() {cloneDatabase();}, wpstg.cpuLoad);
 
 
721
  }
722
 
723
  // Step 1: Clone Database
@@ -734,20 +784,20 @@ var WPStaging = (function($)
734
  }
735
 
736
  setTimeout(
737
- function() {
738
- ajax(
739
- {
740
- action : "wpstg_clone_database",
741
- nonce : wpstg.nonce
742
- },
743
- function(response) {
744
  // Add percentage
745
- if ("undefined" !== typeof(response.percentage))
746
  {
747
  cache.get("#wpstg-db-progress").width(response.percentage + '%');
748
  }
749
  // Add Log
750
- if ("undefined" !== typeof(response.last_msg))
751
  {
752
  getLogs(response.last_msg);
753
  }
@@ -755,19 +805,23 @@ var WPStaging = (function($)
755
  // Continue clone DB
756
  if (false === response.status)
757
  {
758
- setTimeout(function() {cloneDatabase();}, wpstg.cpuLoad);
 
 
759
  }
760
  // Next Step
761
  else if (true === response.status)
762
  {
763
- console.log('prepareDirectories' + response.status);
764
- setTimeout(function() {prepareDirectories();}, wpstg.cpuLoad);
 
 
765
  }
766
  }
 
 
 
767
  );
768
- },
769
- 500
770
- );
771
  }
772
 
773
  // Step 2: Prepare Directories
@@ -784,28 +838,30 @@ var WPStaging = (function($)
784
  }
785
 
786
  setTimeout(
787
- function() {
788
- ajax(
789
- {
790
- action : "wpstg_clone_prepare_directories",
791
- nonce : wpstg.nonce
792
- },
793
- function(response) {
794
  // Add percentage
795
- if ("undefined" !== typeof(response.percentage))
796
  {
797
  cache.get("#wpstg-directories-progress").width(response.percentage + '%');
798
  }
799
 
800
  // Add Log
801
- if ("undefined" !== typeof(response.last_msg))
802
  {
803
  getLogs(response.last_msg);
804
  }
805
 
806
  if (false === response.status)
807
  {
808
- setTimeout(function() {prepareDirectories();}, wpstg.cpuLoad);
 
 
809
  }
810
  else if (true === response.status)
811
  {
@@ -813,10 +869,10 @@ var WPStaging = (function($)
813
  cloneFiles();
814
  }
815
  }
 
 
 
816
  );
817
- },
818
- 500
819
- );
820
  }
821
 
822
  // Step 3: Clone Files
@@ -833,32 +889,36 @@ var WPStaging = (function($)
833
  }
834
 
835
  ajax(
836
- {
837
- action : "wpstg_clone_files",
838
- nonce : wpstg.nonce
839
- },
840
- function(response) {
841
- // Add percentage
842
- if ("undefined" !== typeof(response.percentage))
843
- {
844
- cache.get("#wpstg-files-progress").width(response.percentage + '%');
845
- }
846
-
847
- // Add Log
848
- if ("undefined" !== typeof (response.last_msg))
849
  {
850
- getLogs(response.last_msg);
851
- }
 
 
 
 
 
 
 
852
 
853
- if (false === response.status)
854
- {
855
- setTimeout(function() {cloneFiles();}, wpstg.cpuLoad);
856
- }
857
- else if (true === response.status)
858
- {
859
- setTimeout(function() {replaceData();}, wpstg.cpuLoad);
860
- }
 
 
 
861
  }
 
 
 
 
 
 
 
862
  );
863
  }
864
 
@@ -876,32 +936,34 @@ var WPStaging = (function($)
876
  }
877
 
878
  ajax(
879
- {
880
- action : "wpstg_clone_replace_data",
881
- nonce : wpstg.nonce
882
- },
883
- function(response) {
884
- // Add percentage
885
- if ("undefined" !== typeof(response.percentage))
886
  {
887
- cache.get("#wpstg-links-progress").width(response.percentage + '%');
888
- }
889
-
890
- // Add Log
891
- if ("undefined" !== typeof (response.last_msg))
892
- {
893
- getLogs(response.last_msg);
894
- }
 
895
 
896
- if (false === response.status)
897
- {
898
- setTimeout(function() {replaceData();}, wpstg.cpuLoad);
899
- }
900
- else if (true === response.status)
901
- {
902
- finish();
903
- }
904
  }
 
 
 
 
 
 
 
 
 
 
 
 
905
  );
906
  }
907
 
@@ -920,43 +982,43 @@ var WPStaging = (function($)
920
  }
921
 
922
  ajax(
923
- {
924
- action : "wpstg_clone_finish",
925
- nonce : wpstg.nonce
926
- },
927
- function(response)
928
- {
929
- // Invalid response
930
- if ("object" !== typeof(response))
931
  {
932
- showError(
 
 
 
 
 
 
 
 
933
  "Couldn't finish the cloning process properly. " +
934
  "Your clone has been copied but failed to do clean up and " +
935
  "saving its records to the database." +
936
  "Please contact support and provide your logs."
937
- );
938
 
939
- return;
940
- }
941
 
942
- console.log("Cloning process finished");
943
 
944
- var $link1 = cache.get("#wpstg-clone-url-1");
945
- var $link = cache.get("#wpstg-clone-url");
946
 
947
- cache.get("#wpstg_staging_name").html(that.data.cloneID);
948
- cache.get("#wpstg-finished-result").show();
949
- cache.get("#wpstg-cancel-cloning").prop("disabled", true);
950
- $link1.attr("href", $link1.attr("href") + '/' + response.directoryName);
951
- $link1.append('/' + response.directoryName);
952
- $link.attr("href", $link.attr("href") + '/' + response.directoryName);
953
- cache.get("#wpstg-remove-clone").data("clone", that.data.cloneID);
954
 
955
- // Finished
956
- that.isFinished = true;
957
 
958
- finish();
959
- }
960
  );
961
  }
962
  });
@@ -999,7 +1061,7 @@ var WPStaging = (function($)
999
  * Initiation
1000
  * @type {Function}
1001
  */
1002
- that.init = (function() {
1003
  //console.log("Initiating WPStaging...");
1004
  loadOverview();
1005
  elements();
@@ -1012,11 +1074,13 @@ var WPStaging = (function($)
1012
  * Ajax call
1013
  * @type {ajax}
1014
  */
1015
- that.ajax = ajax;
 
 
1016
 
1017
  return that;
1018
  })(jQuery);
1019
 
1020
- jQuery(document).ready(function() {
1021
  WPStaging.init();
1022
  });
1
  "use strict";
2
 
3
+ var WPStaging = (function ($)
4
  {
5
+ var that = {
6
+ isCancelled: false,
7
+ isFinished: false,
8
+ getLogs: false
9
+ },
10
+ cache = {elements: []},
11
+ timeout, ajaxSpinner;
12
+ ajaxurl = ("undefined" !== typeof wpstg.ajaxurl) ? wpstg.ajaxurl : ajaxurl;
13
 
14
  /**
15
  * Get / Set Cache for Selector
16
  * @param {String} selector
17
  * @returns {*}
18
  */
19
+ cache.get = function (selector)
20
  {
21
  // It is already cached!
22
  if ($.inArray(selector, cache.elements) !== -1)
34
  * Refreshes given cache
35
  * @param {String} selector
36
  */
37
+ cache.refresh = function (selector)
38
  {
39
  selector.elements[selector] = jQuery(selector);
40
  };
43
  * Show and Log Error Message
44
  * @param {String} message
45
  */
46
+ var showError = function (message)
47
  {
48
  cache.get("#wpstg-try-again").css("display", "inline-block");
49
  cache.get("#wpstg-cancel-cloning").text("Reset");
50
  cache.get("#wpstg-cloning-result").text("Fail");
51
  cache.get("#wpstg-error-wrapper").show();
52
  cache.get("#wpstg-error-details")
53
+ .show()
54
+ .html(message);
55
 
56
  cache.get("#wpstg-loader").hide();
57
  };
59
  /**
60
  * Common Elements
61
  */
62
+ var elements = function ()
63
  {
64
+ var $workFlow = cache.get("#wpstg-workflow"),
65
+ isAllChecked = true,
66
+ urlSpinner = ajaxurl.replace("/admin-ajax.php", '') + "/images/spinner",
67
+ timer;
68
 
69
  if (2 < window.devicePixelRatio)
70
  {
76
  ajaxSpinner = "<img src=''" + urlSpinner + "' alt='' class='ajax-spinner general-spinner' />";
77
 
78
  $workFlow
79
+ // Check / Un-check Database Tables
80
+ .on("click", ".wpstg-button-unselect", function (e) {
81
+ e.preventDefault();
82
 
83
+ if (false === isAllChecked)
84
+ {
85
+ cache.get(".wpstg-db-table-checkboxes").prop("checked", true);
86
+ cache.get(".wpstg-button-unselect").text("Un-check All");
87
+ isAllChecked = true;
88
+ }
89
+ else
90
+ {
91
+ cache.get(".wpstg-db-table-checkboxes").prop("checked", false);
92
+ cache.get(".wpstg-button-unselect").text("Check All");
93
+ isAllChecked = false;
94
+ }
95
+ })
96
+ // Expand Directories
97
+ .on("click", ".wpstg-expand-dirs", function (e) {
98
+ e.preventDefault();
99
 
100
+ var $this = $(this);
101
 
102
+ if (!$this.hasClass("disabled"))
103
+ {
104
+ $this.siblings(".wpstg-subdir").slideToggle();
105
+ }
106
+ })
107
+ // When a Directory is Selected
108
+ .on("change", ".wpstg-check-dir", function () {
109
+ var $directory = $(this).parent(".wpstg-dir");
110
 
111
+ if (this.checked)
112
+ {
113
+ $directory.parents(".wpstg-dir").children(".wpstg-check-dir").prop("checked", true);
114
+ $directory.find(".wpstg-expand-dirs").removeClass("disabled");
115
+ $directory.find(".wpstg-subdir .wpstg-check-dir").prop("checked", true);
116
+ }
117
+ else
118
+ {
119
+ $directory.find(".wpstg-dir .wpstg-check-dir").prop("checked", false);
120
+ $directory.find(".wpstg-expand-dirs, .wpstg-check-subdirs").addClass("disabled");
121
+ $directory.find(".wpstg-check-subdirs").data("action", "check").text("check");
122
+ $directory.children(".wpstg-subdir").slideUp();
123
+ }
124
+ })
125
+ // Check the max length of the clone name and if the clone name already exists
126
+ .on("keyup", "#wpstg-new-clone-id", function () {
127
 
128
+ // This request was already sent, clear it up!
129
+ if ("number" === typeof (timer))
130
+ {
131
+ clearInterval(timer);
132
+ }
133
 
134
+ var cloneID = this.value;
135
 
136
+ timer = setTimeout(
137
+ function () {
138
+ ajax(
139
+ {
140
+ action: "wpstg_check_clone",
141
+ cloneID: cloneID
142
+ },
143
+ function (response)
 
 
 
 
 
 
 
 
144
  {
145
+ if (response.status === "success")
146
+ {
147
+ cache.get("#wpstg-new-clone-id").removeClass("wpstg-error-input");
148
+ cache.get("#wpstg-start-cloning").removeAttr("disabled");
149
+ cache.get("#wpstg-clone-id-error").text('').hide();
150
+ }
151
+ else
152
+ {
153
+ cache.get("#wpstg-new-clone-id").addClass("wpstg-error-input");
154
+ cache.get("#wpstg-start-cloning").prop("disabled", true);
155
+ cache.get("#wpstg-clone-id-error").text(response.message).show();
156
+ }
157
  }
158
+ );
159
+ },
160
+ 500
161
+ );
162
+ })
163
+ // Restart cloning process
164
+ .on("click", "#wpstg-start-cloning", function () {
165
+ that.isCancelled = false;
166
+ that.getLogs = false;
167
+ })
168
+ // Display logs
169
+ .on("click", "#wpstg-show-log-button", function (e) {
170
+ e.preventDefault();
171
+ var $logDetails = cache.get("#wpstg-log-details");
 
172
 
173
+ $logDetails.toggle();
174
 
175
+ logscroll();
176
 
177
+ that.getLogs = (false === that.getLogs);
178
+ });
179
 
180
  cloneActions();
181
  };
182
+
183
 
184
  /**
185
  * Clone actions
186
  */
187
+ var cloneActions = function ()
188
  {
189
  var $workFlow = cache.get("#wpstg-workflow");
190
 
191
  $workFlow
192
+ // Cancel cloning
193
+ .on("click", "#wpstg-cancel-cloning", function () {
194
+ if (!confirm("Are you sure you want to cancel cloning process?"))
195
+ {
196
+ return false;
197
+ }
198
 
199
+ var $this = $(this);
200
 
201
+ $("#wpstg-try-again, #wpstg-home-link").hide();
202
+ $this.prop("disabled", true);
203
 
204
+ that.isCancelled = true;
205
 
206
+ $("#wpstg-cloning-result").text("Please wait...this can take up a while.");
207
+ $("#wpstg-loader, #wpstg-show-log-button").hide();
208
 
209
+ $this.parent().append(ajaxSpinner);
210
 
211
+ cancelCloning();
212
+ })
213
+ // Delete clone - confirmation
214
+ .on("click", ".wpstg-remove-clone[data-clone]", function (e) {
215
+ e.preventDefault();
216
 
217
+ var $existingClones = cache.get("#wpstg-existing-clones");
218
 
219
+ $workFlow.removeClass('active');
 
 
220
 
221
+ cache.get("#wpstg-loader").show();
222
+
223
+ ajax(
224
+ {
225
+ action: "wpstg_confirm_delete_clone",
226
+ nonce: wpstg.nonce,
227
+ clone: $(this).data("clone")
228
+ },
229
+ function (response)
230
  {
231
  cache.get("#wpstg-removing-clone").html(response);
232
 
233
  $existingClones.children("img").remove();
234
+
235
  cache.get("#wpstg-loader").hide();
236
  },
237
+ "HTML"
238
+ );
239
+ })
240
+ // Delete clone - confirmed
241
+ .on("click", "#wpstg-remove-clone", function (e) {
242
+ e.preventDefault();
243
+
244
+ cache.get("#wpstg-removing-clone").addClass("loading");
245
+
246
+ cache.get("#wpstg-loader").show();
247
+
248
+ deleteClone($(this).data("clone"));
249
+ })
250
+ // Cancel deleting clone
251
+ .on("click", "#wpstg-cancel-removing", function (e) {
252
+ e.preventDefault();
253
+ $(".wpstg-clone").removeClass("active");
254
+ cache.get("#wpstg-removing-clone").html('');
255
+ })
256
+ // Edit
257
+ .on("click", ".wpstg-execute-clone", function (e) {
258
+ e.preventDefault();
259
+
260
+ var clone = $(this).data("clone");
261
+
262
+ $workFlow.addClass("loading");
263
+
264
+ ajax(
265
+ {
266
+ action: "wpstg_scanning",
267
+ clone: clone,
268
+ nonce: wpstg.nonce
269
+ },
270
+ function (response)
 
 
271
  {
272
  if (response.length < 1)
273
  {
277
  $workFlow.removeClass("loading").html(response);
278
 
279
  cache.get(".wpstg-current-step")
280
+ .removeClass("wpstg-current-step")
281
+ .next("li")
282
+ .addClass("wpstg-current-step");
283
  },
284
+ "HTML"
285
+ );
286
+ });
287
  };
288
 
289
  /**
293
  * @param {String} dataType
294
  * @param {Boolean} showErrors
295
  */
296
+ var ajax = function (data, callback, dataType, showErrors)
297
  {
298
+ if ("undefined" === typeof (dataType))
299
  {
300
  dataType = "json";
301
  }
306
  }
307
 
308
  $.ajax({
309
+ url: ajaxurl,
310
+ type: "POST",
311
+ dataType: dataType,
312
+ cache: false,
313
+ data: data,
314
+ error: function (xhr, textStatus, errorThrown) {
315
  console.log(xhr.status + ' ' + xhr.statusText + '---' + textStatus);
316
  console.log(textStatus);
317
 
321
  }
322
 
323
  showError(
324
+ "Fatal Unknown Error. This should not happen." +
325
+ "Please again. If this does not help, " +
326
+ "<a href='https://wordpress.org/support/plugin/wp-staging' target='_blank'>Open a ticket</a> " +
327
+ "in the WP Staging support forum."
328
+ );
 
329
  },
330
+ success: function (data) {
331
+ if ("function" === typeof (callback))
332
  {
333
  callback(data);
334
  }
335
  },
336
+ statusCode: {
337
+ 404: function () {
338
  showError("Something went wrong; can't find ajax request URL!");
339
  },
340
+ 500: function () {
341
  showError("Something went wrong; internal server error while processing the request!");
342
  }
343
  }
347
  /**
348
  * Next / Previous Step Clicks to Navigate Through Staging Job
349
  */
350
+ var stepButtons = function ()
351
  {
352
  var $workFlow = cache.get("#wpstg-workflow");
353
 
354
  $workFlow
355
+ // Next Button
356
+ .on("click", ".wpstg-next-step-link", function (e) {
357
+ e.preventDefault();
358
 
359
+ var $this = $(this),
360
+ isScan = false;
361
 
362
+ // Button is disabled
363
+ if ($this.attr("disabled"))
364
+ {
365
+ return false;
366
+ }
367
 
368
+ // Add loading overlay
369
+ $workFlow.addClass("loading");
370
 
371
+ // Prepare data
372
+ that.data = {
373
+ action: $this.data("action"),
374
+ nonce: wpstg.nonce
375
+ };
376
 
377
+ // Cloning data
378
+ getCloningData();
379
 
380
+ console.log(that.data);
381
 
382
+ isScan = ("wpstg_scanning" === that.action);
 
383
 
384
+ // Send ajax request
385
+ ajax(
386
+ that.data,
387
+ function (response) {
388
 
389
+ if (response.length < 1)
390
+ {
391
+ showError("Something went wrong, please try again");
392
+ }
393
 
394
+ // Styling of elements
395
+ $workFlow.removeClass("loading").html(response);
396
 
397
+ cache.get(".wpstg-current-step")
398
+ .removeClass("wpstg-current-step")
399
+ .next("li")
400
+ .addClass("wpstg-current-step");
401
 
402
+ // Start cloning
403
+ that.startCloning();
404
+ },
405
+ "HTML"
406
+ );
407
+ })
408
+ // Previous Button
409
+ .on("click", ".wpstg-prev-step-link", function (e) {
410
+ e.preventDefault();
411
+ loadOverview();
412
+ });
413
  };
414
 
415
  /**
416
  * Get Excluded (Unchecked) Database Tables
417
  * @returns {Array}
418
  */
419
+ var getExcludedTables = function ()
420
  {
421
  var excludedTables = [];
422
 
431
  * Get Included Directories
432
  * @returns {Array}
433
  */
434
+ var getIncludedDirectories = function ()
435
  {
436
  var includedDirectories = [];
437
 
450
  * Get Excluded Directories
451
  * @returns {Array}
452
  */
453
+ var getExcludedDirectories = function ()
454
  {
455
  var excludedDirectories = [];
456
 
465
  return excludedDirectories;
466
  };
467
 
468
+ /**
469
+ * Get Included Extra Directories
470
+ * @returns {Array}
471
+ */
472
+ var getIncludedExtraDirectories = function ()
473
+ {
474
+ var extraDirectories = [];
475
+
476
+ if (!$("#wpstg_extraDirectories").val()) {
477
+ return extraDirectories;
478
+ }
479
+
480
+ var extraDirectories = $("#wpstg_extraDirectories").val().split(/\r?\n/);
481
+ console.log(extraDirectories);
482
+
483
+ //excludedDirectories.push($this.val());
484
+
485
+ return extraDirectories;
486
+ };
487
+
488
+
489
+
490
  /**
491
  * Get Cloning Step Data
492
  */
493
+ var getCloningData = function ()
494
  {
495
  if ("wpstg_cloning" !== that.data.action)
496
  {
497
  return;
498
  }
499
 
500
+ that.data.cloneID = $("#wpstg-new-clone-id").val() || new Date().getTime().toString();
501
+ that.data.excludedTables = getExcludedTables();
502
+ that.data.includedDirectories = getIncludedDirectories();
503
+ that.data.excludedDirectories = getExcludedDirectories();
504
+ //that.data.extraDirectories = $("#wpstg_extraDirectories").val() || null;
505
+ that.data.extraDirectories = getIncludedExtraDirectories();
506
+ console.log(that.data);
507
+
508
  };
509
 
510
  /**
511
  * Loads Overview (first step) of Staging Job
512
  */
513
+ var loadOverview = function ()
514
  {
515
  var $workFlow = cache.get("#wpstg-workflow");
516
 
517
  $workFlow.addClass("loading");
518
 
519
  ajax(
 
 
 
 
 
 
 
520
  {
521
+ action: "wpstg_overview",
522
+ nonce: wpstg.nonce
523
+ },
524
+ function (response) {
525
 
526
+ if (response.length < 1)
527
+ {
528
+ showError("Something went wrong, please try again");
529
+ }
530
 
531
+ var $currentStep = cache.get(".wpstg-current-step");
 
532
 
533
+ // Styling of elements
534
+ $workFlow.removeClass("loading").html(response);
535
+
536
+ },
537
+ "HTML"
538
+ );
 
539
  };
540
 
541
  /**
542
  * Tabs
543
  */
544
+ var tabs = function ()
545
  {
546
+ cache.get("#wpstg-workflow").on("click", ".wpstg-tab-header", function (e) {
547
  e.preventDefault();
548
 
549
+ var $this = $(this),
550
+ $section = cache.get($this.data("id"));
551
 
552
  $this.toggleClass("expand");
553
 
568
  * Delete Clone
569
  * @param {String} clone
570
  */
571
+ var deleteClone = function (clone)
572
  {
573
+
574
  ajax(
 
 
 
 
 
 
 
 
 
 
575
  {
576
+ action: "wpstg_delete_clone",
577
+ clone: clone,
578
+ nonce: wpstg.nonce,
579
+ excludedTables: getExcludedTables(),
580
+ deleteDir: $("#deleteDirectory:checked").val()
581
+ },
582
+ function (response)
583
+ {
584
+ if (response) {
585
+ if ("undefined" !== typeof response.delete && response.delete === 'finished') {
586
 
587
+ cache.get("#wpstg-removing-clone").removeClass("loading").html('');
588
+ $(".wpstg-clone#" + clone).remove();
589
 
590
+ if ($(".wpstg-clone").length < 1)
591
+ {
592
+ cache.get("#wpstg-existing-clones").find("h3").text('');
593
+ }
594
+
595
+ cache.get("#wpstg-loader").hide();
596
+ return;
597
  }
 
 
598
  }
599
+ // continue
600
+ if (true !== response)
601
+ {
602
+ deleteClone(clone);
603
+ return;
604
+ }
605
+
606
+ }
607
  );
608
  };
609
 
610
  /**
611
  * Cancel Cloning Process
612
  */
613
+ var cancelCloning = function ()
614
  {
615
  if (true === that.isFinished)
616
  {
618
  }
619
 
620
  ajax(
 
 
 
 
 
 
 
 
621
  {
622
+ action: "wpstg_cancel_clone",
623
+ clone: that.data.cloneID,
624
+ nonce: wpstg.nonce
625
+ },
626
+ function (response)
627
+ {
628
+
629
+
630
+ if( response && "undefined" !== typeof(response.delete) && response.delete === "finished"){
631
  // Load overview
632
  loadOverview();
633
+ return;
634
+ }
635
+
636
+ if (true !== response)
637
+ {
638
+ // continue
639
+ cancelCloning();
640
+ return;
641
  }
642
+
643
+ // Load overview
644
+ loadOverview();
645
+ }
646
  );
647
  };
648
+
649
  /**
650
  * Scroll the window log to bottom
651
  * @returns void
652
  */
653
  var logscroll = function () {
654
  var $div = cache.get("#wpstg-log-details");
655
+ if ("undefined" !== typeof ($div[0])) {
656
  $div.scrollTop($div[0].scrollHeight);
657
  }
658
  }
664
  */
665
  var getLogs = function (log)
666
  {
 
 
 
667
  if (log != null && "undefined" !== typeof (log)) {
668
  if (log.constructor === Array) {
669
  $.each(log, function (index, value) {
670
+
671
  //console.log(index, value);
672
+ if (value.type === 'ERROR'){
673
+ cache.get("#wpstg-log-details").append('<span style="color:red;">[' + value.type + ']</span>-'+ '[' + value.date + '] ' + value.message + '</br>');
674
+ } else {
675
+ cache.get("#wpstg-log-details").append('[' + value.type + ']-'+ '[' + value.date + '] ' + value.message + '</br>');
676
+ }
677
  })
678
  } else {
679
+ cache.get("#wpstg-log-details").append('[' + log.type + ']-' + '[' + log.date + '] ' + log.message + '</br>');
680
  }
681
  }
682
  logscroll();
686
  /**
687
  * Optimizer
688
  */
689
+ var optimizer = function ()
690
  {
691
  var $optimizer = cache.get('input[name="wpstg_settings\[optimizer\]"]');
692
 
694
  optimizerAction($optimizer.is(':checked'));
695
 
696
  // On action
697
+ $optimizer.on('change', function () {
698
  optimizerAction(this.checked);
699
  });
700
 
710
  }
711
  };
712
 
713
+ var checkDiskSpace = function () {
714
+ cache.get("#wpstg-check-space").on("click", function (e) {
715
+ cache.get("#wpstg-loader").show();
716
+ console.log("check disk space");
717
+ ajax(
718
+ {
719
+ action: "wpstg_check_disk_space",
720
+ nonce: wpstg.nonce
721
+ },
722
+ function (response)
723
+ {
724
+ if (false === response)
725
+ {
726
+ cache.get("#wpstg-clone-id-error").text('Can not detect disk space').show();
727
+ cache.get("#wpstg-loader").hide();
728
+ return;
729
+ }
730
+
731
+ // Not enough disk space
732
+ cache.get("#wpstg-clone-id-error").text('Available free disk space ' + response.freespace + ' | Estimated necessary disk space: ' + response.usedspace).show();
733
+ cache.get("#wpstg-loader").hide();
734
+ },
735
+ "json",
736
+ false
737
+ );
738
+ });
739
+
740
+ }
741
+
742
  /**
743
  * Start Cloning Process
744
  * @type {Function}
745
  */
746
+ that.startCloning = (function () {
747
+
748
+ // Register function for checking disk space
749
+ checkDiskSpace();
750
+
751
  if ("wpstg_cloning" !== that.data.action)
752
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
753
  return;
754
  }
755
 
765
  cache.get("#wpstg-loader").show();
766
 
767
  // Clone Database
768
+ setTimeout(function () {
769
+ cloneDatabase();
770
+ }, wpstg.cpuLoad);
771
  }
772
 
773
  // Step 1: Clone Database
784
  }
785
 
786
  setTimeout(
787
+ function () {
788
+ ajax(
789
+ {
790
+ action: "wpstg_clone_database",
791
+ nonce: wpstg.nonce
792
+ },
793
+ function (response) {
794
  // Add percentage
795
+ if ("undefined" !== typeof (response.percentage))
796
  {
797
  cache.get("#wpstg-db-progress").width(response.percentage + '%');
798
  }
799
  // Add Log
800
+ if ("undefined" !== typeof (response.last_msg))
801
  {
802
  getLogs(response.last_msg);
803
  }
805
  // Continue clone DB
806
  if (false === response.status)
807
  {
808
+ setTimeout(function () {
809
+ cloneDatabase();
810
+ }, wpstg.cpuLoad);
811
  }
812
  // Next Step
813
  else if (true === response.status)
814
  {
815
+ //console.log('prepareDirectories ' + response.status);
816
+ setTimeout(function () {
817
+ prepareDirectories();
818
+ }, wpstg.cpuLoad);
819
  }
820
  }
821
+ );
822
+ },
823
+ 500
824
  );
 
 
 
825
  }
826
 
827
  // Step 2: Prepare Directories
838
  }
839
 
840
  setTimeout(
841
+ function () {
842
+ ajax(
843
+ {
844
+ action: "wpstg_clone_prepare_directories",
845
+ nonce: wpstg.nonce
846
+ },
847
+ function (response) {
848
  // Add percentage
849
+ if ("undefined" !== typeof (response.percentage))
850
  {
851
  cache.get("#wpstg-directories-progress").width(response.percentage + '%');
852
  }
853
 
854
  // Add Log
855
+ if ("undefined" !== typeof (response.last_msg))
856
  {
857
  getLogs(response.last_msg);
858
  }
859
 
860
  if (false === response.status)
861
  {
862
+ setTimeout(function () {
863
+ prepareDirectories();
864
+ }, wpstg.cpuLoad);
865
  }
866
  else if (true === response.status)
867
  {
869
  cloneFiles();
870
  }
871
  }
872
+ );
873
+ },
874
+ 500
875
  );
 
 
 
876
  }
877
 
878
  // Step 3: Clone Files
889
  }
890
 
891
  ajax(
 
 
 
 
 
 
 
 
 
 
 
 
 
892
  {
893
+ action: "wpstg_clone_files",
894
+ nonce: wpstg.nonce
895
+ },
896
+ function (response) {
897
+ // Add percentage
898
+ if ("undefined" !== typeof (response.percentage))
899
+ {
900
+ cache.get("#wpstg-files-progress").width(response.percentage + '%');
901
+ }
902
 
903
+ // Add Log
904
+ if ("undefined" !== typeof (response.last_msg))
905
+ {
906
+ getLogs(response.last_msg);
907
+ }
908
+
909
+ if (false === response.status)
910
+ {
911
+ setTimeout(function () {
912
+ cloneFiles();
913
+ }, wpstg.cpuLoad);
914
  }
915
+ else if (true === response.status)
916
+ {
917
+ setTimeout(function () {
918
+ replaceData();
919
+ }, wpstg.cpuLoad);
920
+ }
921
+ }
922
  );
923
  }
924
 
936
  }
937
 
938
  ajax(
 
 
 
 
 
 
 
939
  {
940
+ action: "wpstg_clone_replace_data",
941
+ nonce: wpstg.nonce
942
+ },
943
+ function (response) {
944
+ // Add percentage
945
+ if ("undefined" !== typeof (response.percentage))
946
+ {
947
+ cache.get("#wpstg-links-progress").width(response.percentage + '%');
948
+ }
949
 
950
+ // Add Log
951
+ if ("undefined" !== typeof (response.last_msg))
952
+ {
953
+ getLogs(response.last_msg);
 
 
 
 
954
  }
955
+
956
+ if (false === response.status)
957
+ {
958
+ setTimeout(function () {
959
+ replaceData();
960
+ }, wpstg.cpuLoad);
961
+ }
962
+ else if (true === response.status)
963
+ {
964
+ finish();
965
+ }
966
+ }
967
  );
968
  }
969
 
982
  }
983
 
984
  ajax(
 
 
 
 
 
 
 
 
985
  {
986
+ action: "wpstg_clone_finish",
987
+ nonce: wpstg.nonce
988
+ },
989
+ function (response)
990
+ {
991
+ // Invalid response
992
+ if ("object" !== typeof (response))
993
+ {
994
+ showError(
995
  "Couldn't finish the cloning process properly. " +
996
  "Your clone has been copied but failed to do clean up and " +
997
  "saving its records to the database." +
998
  "Please contact support and provide your logs."
999
+ );
1000
 
1001
+ return;
1002
+ }
1003
 
1004
+ console.log("Cloning process finished");
1005
 
1006
+ var $link1 = cache.get("#wpstg-clone-url-1");
1007
+ var $link = cache.get("#wpstg-clone-url");
1008
 
1009
+ cache.get("#wpstg_staging_name").html(that.data.cloneID);
1010
+ cache.get("#wpstg-finished-result").show();
1011
+ cache.get("#wpstg-cancel-cloning").prop("disabled", true);
1012
+ $link1.attr("href", $link1.attr("href") + '/' + response.directoryName);
1013
+ $link1.append('/' + response.directoryName);
1014
+ $link.attr("href", $link.attr("href") + '/' + response.directoryName);
1015
+ cache.get("#wpstg-remove-clone").data("clone", that.data.cloneID);
1016
 
1017
+ // Finished
1018
+ that.isFinished = true;
1019
 
1020
+ finish();
1021
+ }
1022
  );
1023
  }
1024
  });
1061
  * Initiation
1062
  * @type {Function}
1063
  */
1064
+ that.init = (function () {
1065
  //console.log("Initiating WPStaging...");
1066
  loadOverview();
1067
  elements();
1074
  * Ajax call
1075
  * @type {ajax}
1076
  */
1077
+ that.ajax = ajax;
1078
+ that.showError = showError;
1079
+ that.getLogs = getLogs;
1080
 
1081
  return that;
1082
  })(jQuery);
1083
 
1084
+ jQuery(document).ready(function () {
1085
  WPStaging.init();
1086
  });
apps/Backend/views/_includes/header.php CHANGED
@@ -3,7 +3,7 @@
3
  </span>
4
 
5
  <span class="wpstg-version">
6
- <?php if (\WPStaging\WPStaging::SLUG === "wp-staging-pro") echo "Pro" ?> Version <?php echo \WPStaging\WPStaging::VERSION ?>
7
  </span>
8
 
9
  <div class="wpstg-header">
3
  </span>
4
 
5
  <span class="wpstg-version">
6
+ <?php if (WPStaging\WPStaging::getSlug() === "wp-staging-pro") echo "Pro" ?> Version <?php echo \WPStaging\WPStaging::VERSION ?>
7
  </span>
8
 
9
  <div class="wpstg-header">
apps/Backend/views/_includes/messages/beta.php CHANGED
@@ -10,9 +10,9 @@
10
  <a href="https://wordpress.org/plugins/backwpup/" target="_blank">BackWPup</a>
11
  </p>
12
  <p>
13
- I am not responsible for any damages this plugin will cause to your site.
14
  <br>
15
- Do a full backup first!
16
  </p>
17
  <ul>
18
  <li>
10
  <a href="https://wordpress.org/plugins/backwpup/" target="_blank">BackWPup</a>
11
  </p>
12
  <p>
13
+ I am not responsible for any damages you do to your site;)
14
  <br>
15
+ Create a full backup first.
16
  </p>
17
  <ul>
18
  <li>
apps/Backend/views/_includes/messages/rating.php CHANGED
@@ -2,6 +2,8 @@
2
  <p>
3
  Awesome, you've been using <strong>WP Staging </strong> for more than 1 week.
4
  May I ask you to give it a <strong>5-star</strong> rating on Wordpress?
 
 
5
  </p>
6
 
7
  <p>
2
  <p>
3
  Awesome, you've been using <strong>WP Staging </strong> for more than 1 week.
4
  May I ask you to give it a <strong>5-star</strong> rating on Wordpress?
5
+ <br><br>
6
+ P.S. Looking for a way to copy plugins and theme files from staging to live site? Try out <a href="https://wp-staging.com" target="_blank">WP Staging Pro</a> <br>
7
  </p>
8
 
9
  <p>
apps/Backend/views/_includes/messages/wp-version-compatible-message.php CHANGED
@@ -6,7 +6,7 @@
6
  '<br/> As WP Staging is using crucial DB and file functions it\'s important that you are using a ' .
7
  'WP Staging version <br> which has been verified to be working with your WordPress version. ' .
8
  'You risk unexpected results up to data lose if you do not so. ' .
9
- '<p>Please look at <a href="%1$s" target="_blank">%1$s</a> for the latest WP Staging version.', 'wpstg'), 'https://wordpress.org/plugins/wp-staging/', get_bloginfo( 'version' )
10
  );
11
  ?>
12
  </p>
6
  '<br/> As WP Staging is using crucial DB and file functions it\'s important that you are using a ' .
7
  'WP Staging version <br> which has been verified to be working with your WordPress version. ' .
8
  'You risk unexpected results up to data lose if you do not so. ' .
9
+ '<p>Please look at <a href="%1$s" target="_blank">%1$s</a> for the latest WP Staging version.', 'wpstg'), 'https://wp-staging.com', get_bloginfo( 'version' )
10
  );
11
  ?>
12
  </p>
apps/Backend/views/clone/ajax/delete-confirmation.php CHANGED
@@ -70,7 +70,7 @@
70
  <label>
71
  <input id="deleteDirectory" type="checkbox" class="wpstg-check-dir" name="deleteDirectory" value="1" checked>
72
  <?php echo $clone->path; ?>
73
- <span class="wpstg-size-info"><?php echo $clone->size; ?></span>
74
  </label>
75
  </div>
76
  </div>
70
  <label>
71
  <input id="deleteDirectory" type="checkbox" class="wpstg-check-dir" name="deleteDirectory" value="1" checked>
72
  <?php echo $clone->path; ?>
73
+ <span class="wpstg-size-info"></span>
74
  </label>
75
  </div>
76
  </div>
apps/Backend/views/clone/ajax/scan.php CHANGED
@@ -1,5 +1,5 @@
1
  <label id="wpstg-clone-label" for="wpstg-new-clone">
2
- <?php echo __('Name your new site, e.g. <i>staging</i> or <i>development</i>:', 'wpstg')?>
3
  <input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if (null !== $options->current) echo " disabled='disabled'"?>>
4
  </label>
5
 
@@ -61,7 +61,7 @@
61
  <?php echo $scan->directoryListing()?>
62
 
63
  <h4 style="margin:10px 0 10px 0">
64
- <?php echo __("Extra Directories / Files", "wpstg")?>
65
  </h4>
66
 
67
  <textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:250px;"></textarea>
@@ -69,9 +69,8 @@
69
  <span>
70
  <?php
71
  echo __(
72
- "Add additional extra directories you'd like to clone to your staging site<br>".
73
- "You must write full path of the directory / file<br>".
74
- "Full path must start with " . $options->root,
75
  "wpstg"
76
  )
77
  ?>
@@ -81,7 +80,9 @@
81
  <p>
82
  <span>
83
  <?php
84
- echo __("Files will be copied into subfolder of: ", "wpstg") . $options->root
 
 
85
  ?>
86
  </span>
87
  </p>
@@ -113,4 +114,6 @@
113
  echo __("Start Cloning", "wpstg");
114
  }
115
  ?>
116
- </button>
 
 
1
  <label id="wpstg-clone-label" for="wpstg-new-clone">
2
+ <?php echo __('Staging Site Name:', 'wpstg')?>
3
  <input type="text" id="wpstg-new-clone-id" value="<?php echo $options->current; ?>"<?php if (null !== $options->current) echo " disabled='disabled'"?>>
4
  </label>
5
 
61
  <?php echo $scan->directoryListing()?>
62
 
63
  <h4 style="margin:10px 0 10px 0">
64
+ <?php echo __("Extra directories to copy", "wpstg")?>
65
  </h4>
66
 
67
  <textarea id="wpstg_extraDirectories" name="wpstg_extraDirectories" style="width:100%;height:250px;"></textarea>
69
  <span>
70
  <?php
71
  echo __(
72
+ "Enter one folder path per line.<br>".
73
+ "Folders must start with absolute path: " . $options->root,
 
74
  "wpstg"
75
  )
76
  ?>
80
  <p>
81
  <span>
82
  <?php
83
+ if (isset($options->clone)){
84
+ echo __("All files are copied into: ", "wpstg") . $options->root . $options->clone;
85
+ }
86
  ?>
87
  </span>
88
  </p>
114
  echo __("Start Cloning", "wpstg");
115
  }
116
  ?>
117
+ </button>
118
+
119
+ <a href="#" id="wpstg-check-space"><?php _e('Check Disk Space', 'wpstg'); ?></a>
apps/Backend/views/clone/ajax/start.php CHANGED
@@ -30,7 +30,7 @@
30
  <?php echo __("Cancel", "wpstg")?>
31
  </button>
32
 
33
- <button type="button" id="wpstg-show-log-button" class="button" data-clone="<?php echo $cloning->getOptions()->clone?>" style="margin-top: 5px;">
34
  <?php _e('Display working log', 'wpstg')?>
35
  </button>
36
 
30
  <?php echo __("Cancel", "wpstg")?>
31
  </button>
32
 
33
+ <button type="button" id="wpstg-show-log-button" class="button" data-clone="<?php echo $cloning->getOptions()->clone?>" style="margin-top: 5px;display:none;">
34
  <?php _e('Display working log', 'wpstg')?>
35
  </button>
36
 
apps/Backend/views/clone/index.php CHANGED
@@ -2,7 +2,7 @@
2
 
3
  <?php require_once($this->path . "views/_includes/header.php")?>
4
 
5
- <h2 class="nav-tab-wrapper"></h2>
6
 
7
  <?php
8
  do_action("wpstg_notifications");
2
 
3
  <?php require_once($this->path . "views/_includes/header.php")?>
4
 
5
+ <h2 class="wpstg-nav-tab-wrapper"></h2>
6
 
7
  <?php
8
  do_action("wpstg_notifications");
apps/Backend/views/clone/single-site/index.php CHANGED
@@ -16,4 +16,5 @@
16
  </li>
17
  </ul>
18
 
19
- <div id="wpstg-workflow"></div>
 
16
  </li>
17
  </ul>
18
 
19
+ <div id="wpstg-workflow"></div>
20
+ <div id="wpstg-sidebar"><a href="https://wp-staging.com/?utm_source=tryout&utm_medium=plugin&utm_campaign=tryout&utm_term=tryout" target="_new"><img src="<?php echo WPSTG_PLUGIN_URL . '/apps/Backend/public/img/wpstaging-banner200x400-tryout.gif'; ?>"></a></div>
apps/Backend/views/settings/index.php CHANGED
@@ -202,13 +202,13 @@
202
  </td>
203
  </tr>
204
  <!-- Deactivated -->
205
- <tr class="row" style="display: none;">
206
  <td class="row th">
207
  <div class="col-title">
208
  <?php echo $form->label("wpstg_settings[debugMode]")?>
209
  <span class="description">
210
  This will enable an extended debug mode which creates additional entries
211
- in <strong>wp-content/wp-staging/logs</strong>.
212
  Please enable this when we ask you to do so.
213
  </span>
214
  </div>
202
  </td>
203
  </tr>
204
  <!-- Deactivated -->
205
+ <tr class="row">
206
  <td class="row th">
207
  <div class="col-title">
208
  <?php echo $form->label("wpstg_settings[debugMode]")?>
209
  <span class="description">
210
  This will enable an extended debug mode which creates additional entries
211
+ in <strong>wp-content/uploads/wp-staging/logs/logfile.log</strong>.
212
  Please enable this when we ask you to do so.
213
  </span>
214
  </div>
apps/Backend/views/tools/index.php CHANGED
@@ -24,7 +24,7 @@
24
  ?>
25
  </ul>
26
 
27
- <h2 class="nav-tab-wrapper"></h2>
28
 
29
  <div class="metabox-holder">
30
  <?php require_once $this->path . "views/tools/tabs/" . $activeTab . ".php"?>
24
  ?>
25
  </ul>
26
 
27
+ <h2 class="wpstg-nav-tab-wrapper"></h2>
28
 
29
  <div class="metabox-holder">
30
  <?php require_once $this->path . "views/tools/tabs/" . $activeTab . ".php"?>
apps/Backend/views/welcome/welcome.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <div class="" id="wpstg-welcome">
2
+ <div style="border: 2px solid white;padding: 20px;margin-bottom:20px;">
3
+ <h2 class="wpstg-h2">
4
+ <span class="wpstg-heading-pro"><?php _e( 'WP Staging Pro', 'wpstg' ); ?></span><?php _e( ' - Copy Themes & Plugins from Staging to Live Site', 'wpstg' ); ?>
5
+ </h2>
6
+ <li><strong>Cloning</strong> - <?php _e( 'Create a clone of your website with a simple click', 'wpstg' ); ?></li>
7
+ <li><strong>Push Changes</strong> - <?php _e( 'Copy plugin and theme files from staging to live site', 'wpstg' ); ?></li>
8
+ <li><strong>Authentication</strong> - <?php _e( 'Staging Site is available to authenticated users only', 'wpstg' ); ?></li>
9
+ <li><strong>High Performance</strong> - <?php _e( 'Cloning process is fast and does not slow down website loading', 'wpstg' ); ?></li>
10
+ <li><strong>Secure</strong> - <?php _e( 'WP Staging is coded well for protection of your data', 'wpstg' ); ?></li>
11
+ <a href="http://wp-staging.com/?utm_source=wpstg&utm_medium=addon_page&utm_term=click-wpstaging-pro&utm_campaign=wpstaging" target="_blank" class="wpstg-button green">Buy WP Staging Pro</a>
12
+ <a href="<?php echo admin_url(); ?>admin.php?page=wpstg_clone" target="_self" style="margin-left:30px;">Skip - Start Cloning</a>
13
+ <div class="wpstg-footer"> <?php _e( 'Comes with our 30-day no questions asked money back guarantee', 'wpstg' ); ?></div>
14
+ </div>
15
+ </div>
apps/Core/Cron/Cron.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Chron relevant stuff
5
+ */
6
+
7
+ namespace WPStaging\Cron;
8
+
9
+ // No Direct Access
10
+ if( !defined( "WPINC" ) ) {
11
+ die;
12
+ }
13
+
14
+ class Cron {
15
+
16
+
17
+ public function __construct() {
18
+ add_filter( 'cron_schedules', array($this, 'add_new_intervals') );
19
+ }
20
+
21
+ /**
22
+ * Add new intervals for wp cron jobs
23
+ * @param type $schedules
24
+ * @return type
25
+ */
26
+ public function add_new_intervals( $schedules ) {
27
+ // add weekly and monthly intervals
28
+ $schedules['weekly'] = array(
29
+ 'interval' => 604800,
30
+ 'display' => __( 'Once Weekly' )
31
+ );
32
+
33
+ $schedules['monthly'] = array(
34
+ 'interval' => 2635200,
35
+ 'display' => __( 'Once a month' )
36
+ );
37
+
38
+ return $schedules;
39
+ }
40
+
41
+ public function schedule_event() {
42
+ if( !wp_next_scheduled( 'wpstg_weekly_event' ) ) {
43
+ wp_schedule_event( time(), 'weekly', 'wpstg_weekly_event' );
44
+ }
45
+ }
46
+ }
apps/Core/Utils/Cache.php CHANGED
@@ -70,7 +70,7 @@ class Cache
70
  // If cache directory doesn't exists, create it
71
  if (!is_dir($this->cacheDir) && !@mkdir($this->cacheDir, 0775, true))
72
  {
73
- throw new \Exception("Failed to create cache directory!");
74
  }
75
  }
76
 
70
  // If cache directory doesn't exists, create it
71
  if (!is_dir($this->cacheDir) && !@mkdir($this->cacheDir, 0775, true))
72
  {
73
+ throw new \Exception("Failed to create cache directory " . $this->cacheDir . '! Make sure folder permission is 755 and owner is correct. Should be www-data or similar.');
74
  }
75
  }
76
 
apps/Core/Utils/Logger.php CHANGED
@@ -24,6 +24,8 @@ class Logger
24
  const TYPE_WARNING = "WARNING";
25
 
26
  const TYPE_INFO = "INFO";
 
 
27
 
28
  /**
29
  * Log directory (full path)
@@ -98,7 +100,7 @@ class Logger
98
  * @param string $type
99
  */
100
  public function add($message, $type = self::TYPE_ERROR)
101
- {
102
  $this->messages[] = array(
103
  "type" => $type,
104
  "date" => date("Y/m/d H:i:s"),
24
  const TYPE_WARNING = "WARNING";
25
 
26
  const TYPE_INFO = "INFO";
27
+
28
+ const TYPE_DEBUG = "DEBUG";
29
 
30
  /**
31
  * Log directory (full path)
100
  * @param string $type
101
  */
102
  public function add($message, $type = self::TYPE_ERROR)
103
+ {
104
  $this->messages[] = array(
105
  "type" => $type,
106
  "date" => date("Y/m/d H:i:s"),
apps/Core/WPStaging.php CHANGED
@@ -1,10 +1,10 @@
1
  <?php
 
2
  namespace WPStaging;
3
 
4
  // No Direct Access
5
- if (!defined("WPINC"))
6
- {
7
- die;
8
  }
9
 
10
  // Ensure to include autoloader class
@@ -18,392 +18,408 @@ use WPStaging\Utils\Cache;
18
  use WPStaging\Utils\Loader;
19
  use WPStaging\Utils\Logger;
20
  use WPStaging\DI\InjectionAware;
 
21
 
22
  /**
23
  * Class WPStaging
24
  * @package WPStaging
25
  */
26
- final class WPStaging
27
- {
28
-
29
- /**
30
- * Plugin version
31
- */
32
- const VERSION = "2.0.1";
33
-
34
- /**
35
- * Plugin name
36
- */
37
- const NAME = "WP Staging";
38
-
39
- /**
40
- * Plugin slug
41
- */
42
- const SLUG = "wp-staging";
43
-
44
- /**
45
- * Compatible WP Version
46
- */
47
- const WP_COMPATIBLE = "4.7.4";
48
-
49
-
50
- /**
51
- * Services
52
- * @var array
53
- */
54
- private $services;
55
-
56
- /**
57
- * Singleton instance
58
- * @var WPStaging
59
- */
60
- private static $instance;
61
-
62
- /**
63
- * WPStaging constructor.
64
- */
65
- private function __construct()
66
- {
67
- $file = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . self::SLUG . ".php";
68
-
69
- // Activation Hook
70
- register_activation_hook($file, array($this, "onActivation"));
71
-
72
- $this->registerNamespaces();
73
- $this->loadLanguages();
74
- $this->loadDependencies();
75
- $this->defineHooks();
76
-
77
- // URL to apps folder
78
- $this->url = plugin_dir_url( dirname(__FILE__) );
79
-
80
- // URL to backend public folder folder
81
- $this->backend_url = plugin_dir_url( dirname(__FILE__) ) . "Backend/public/";
82
-
83
- // URL to frontend public folder folder
84
- $this->frontend_url = plugin_dir_url( dirname(__FILE__) ) . "Frontend/public/";
85
- }
86
-
87
- /**
88
- * Define Hooks
89
- */
90
- public function defineHooks()
91
- {
92
- $loader = $this->get("loader");
93
- $loader->addAction("admin_enqueue_scripts", $this, "enqueueElements", 100);
94
- $loader->addAction("wp_enqueue_scripts", $this, "enqueueElements", 100);
95
- }
96
-
97
- /**
98
- * Scripts and Styles
99
- * @param string $hook
100
- */
101
- public function enqueueElements($hook)
102
- {
103
-
104
- // Load this css file on frontend and backend on all pages if current site is a staging site
105
- if( $this->isStagingSite() ) {
106
- wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", $this->getVersion() );
107
- }
108
-
109
- $availablePages = array(
110
- "toplevel_page_wpstg_clone",
111
- "wp-staging_page_wpstg-settings",
112
- "wp-staging_page_wpstg-tools"
113
- );
114
-
115
- // Load these css and js files only on wp staging admin pages
116
- if (!in_array($hook, $availablePages) || !is_admin())
117
- {
118
- return;
119
- }
120
-
121
- // Load admin js files
122
- wp_enqueue_script(
123
- "wpstg-admin-script",
124
- $this->backend_url . "js/wpstg-admin.js",
125
- array("jquery"),
126
- $this->getVersion(),
127
- false
128
- );
129
-
130
- // Load admin css files
131
- wp_enqueue_style(
132
- "wpstg-admin",
133
- $this->backend_url . "css/wpstg-admin.css",
134
- $this->getVersion()
135
- );
136
-
137
- wp_localize_script("wpstg-admin-script", "wpstg", array(
138
- "nonce" => wp_create_nonce("wpstg_ajax_nonce"),
139
- "mu_plugin_confirmation" => __(
140
- "If confirmed we will install an additional WordPress 'Must Use' plugin. "
141
- . "This plugin will allow us to control which plugins are loaded during "
142
- . "WP Staging specific operations. Do you wish to continue?",
143
- "wpstg"
144
- ),
145
- "plugin_compatibility_settings_problem" => __(
146
- "A problem occurred when trying to change the plugin compatibility setting.",
147
- "wpstg"
148
- ),
149
- "saved" => __("Saved", "The settings were saved successfully", "wpstg"),
150
- "status" => __("Status", "Current request status", "wpstg"),
151
- "response" => __("Response", "The message the server responded with", "wpstg"),
152
- "blacklist_problem" => __(
153
- "A problem occurred when trying to add plugins to backlist.",
154
- "wpstg"
155
- ),
156
- "cpuLoad" => $this->getCPULoadSetting(),
157
- "settings" => (object) array() // TODO add settings?
158
- ));
159
- }
160
-
161
- /**
162
- * Method to be executed upon activation of the plugin
163
- */
164
- public function onActivation()
165
- {
166
-
167
- }
168
- /**
169
- * Caching and logging folder
170
- *
171
- * @return string
172
- */
173
- public static function getContentDir(){
174
- $wp_upload_dir = wp_upload_dir();
175
- $path = $wp_upload_dir['basedir'] . '/wp-staging';
176
- wp_mkdir_p( $path );
177
- return apply_filters( 'wpstg_get_upload_dir', $path . DIRECTORY_SEPARATOR );
178
- }
179
-
180
-
181
- /**
182
- * Register used namespaces
183
- */
184
- private function registerNamespaces()
185
- {
186
- $autoloader = new Autoloader();
187
- $this->set("autoloader", $autoloader);
188
-
189
- // Base directory
190
- $dir = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . "apps" . DIRECTORY_SEPARATOR;
191
-
192
- // Autoloader
193
- $autoloader->registerNamespaces(array(
194
- "WPStaging" => array(
195
- $dir,
196
- $dir . "Core" . DIRECTORY_SEPARATOR
197
- )
198
- ));
199
-
200
- // Register namespaces
201
- $autoloader->register();
202
- }
203
-
204
- /**
205
- * Get Instance
206
- * @return WPStaging
207
- */
208
- public static function getInstance()
209
- {
210
- if (null === static::$instance)
211
- {
212
- static::$instance = new static();
213
- }
214
-
215
- return static::$instance;
216
- }
217
-
218
- /**
219
- * Prevent cloning
220
- * @return void
221
- */
222
- private function __clone()
223
- {}
224
-
225
- /**
226
- * Prevent unserialization
227
- * @return void
228
- */
229
- private function __wakeup()
230
- {}
231
-
232
- /**
233
- * Load Dependencies
234
- */
235
- private function loadDependencies()
236
- {
237
- // Set loader
238
- $this->set("loader", new Loader());
239
-
240
- // Set cache
241
- $this->set("cache", new Cache());
242
-
243
- // Set logger
244
- $this->set("logger", new Logger());
245
-
246
- // Set settings
247
- $this->set("settings", new Settings());
248
-
249
- // Set Administrator
250
- if (is_admin())
251
- {
252
- new Administrator($this);
253
- }
254
- else
255
- {
256
- new Frontend($this);
257
- }
258
- }
259
-
260
- /**
261
- * Execute Plugin
262
- */
263
- public function run()
264
- {
265
- $this->get("loader")->run();
266
- }
267
-
268
- /**
269
- * Set a variable to DI with given name
270
- * @param string $name
271
- * @param mixed $variable
272
- * @return $this
273
- */
274
- public function set($name, $variable)
275
- {
276
- // It is a function
277
- if (is_callable($variable)) $variable = $variable();
278
-
279
- // Add it to services
280
- $this->services[$name] = $variable;
281
-
282
- return $this;
283
- }
284
-
285
- /**
286
- * Get given name index from DI
287
- * @param string $name
288
- * @return mixed|null
289
- */
290
- public function get($name)
291
- {
292
- return (isset($this->services[$name])) ? $this->services[$name] : null;
293
- }
294
-
295
- /**
296
- * @return string
297
- */
298
- public function getVersion()
299
- {
300
- return self::VERSION;
301
- }
302
-
303
- /**
304
- * @return string
305
- */
306
- public function getName()
307
- {
308
- return self::NAME;
309
- }
310
-
311
- /**
312
- * @return string
313
- */
314
- public function getSlug()
315
- {
316
- return self::SLUG;
317
- }
318
-
319
- /**
320
- * Get path to main plugin file
321
- * @return string
322
- */
323
- public function getPath(){
324
- return dirname(dirname(__FILE__));
325
- }
326
- /**
327
- * Get main plugin url
328
- * @return type
329
- */
330
- public function getUrl(){
331
- return plugin_dir_url(dirname(__FILE__));
332
- }
333
-
334
- /**
335
- * @return array|mixed|object
336
- */
337
- public function getCPULoadSetting()
338
- {
339
- $options = $this->get("settings");
340
- $setting = $options->getCpuLoad();
341
-
342
- switch ($setting)
343
- {
344
- case "high":
345
- $cpuLoad = 0;
346
- break;
347
-
348
- case "medium":
349
- $cpuLoad = 1000;
350
- break;
351
-
352
- case "low":
353
- $cpuLoad = 3000;
354
- break;
355
-
356
- case "default":
357
- default:
358
- $cpuLoad = 1000;
359
- }
360
-
361
- return $cpuLoad;
362
- }
363
-
364
- /**
365
- * Load language file
366
- */
367
- public function loadLanguages()
368
- {
369
- $languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR;
370
- $languagesDirectory.= "vars" . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
371
-
372
- // Set filter for plugins languages directory
373
- $languagesDirectory = apply_filters("wpstg_languages_directory", $languagesDirectory);
374
-
375
- // Traditional WP plugin locale filter
376
- $locale = apply_filters("plugin_locale", get_locale(), "wpstg");
377
- $moFile = sprintf('%1$s-%2$s.mo', "wpstg", $locale);
378
-
379
- // Setup paths to current locale file
380
- $moFileLocal = $languagesDirectory . $moFile;
381
- $moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wpstg" . DIRECTORY_SEPARATOR . $moFile;
382
-
383
- // Global file (/wp-content/languages/WPSTG)
384
- if (file_exists($moFileGlobal))
385
- {
386
- load_textdomain("wpstg", $moFileGlobal);
387
- }
388
- // Local file (/wp-content/plugins/wp-staging/languages/)
389
- elseif (file_exists($moFileLocal))
390
- {
391
- load_textdomain("wpstg", $moFileGlobal);
392
- }
393
- // Default file
394
- else
395
- {
396
- load_plugin_textdomain("wpstg", false, $languagesDirectory);
397
- }
398
- }
399
-
400
- /**
401
- * Check if it is a staging site
402
- * @return bool
403
- */
404
- private function isStagingSite()
405
- {
406
- return ("true" === get_option("wpstg_is_staging_site"));
407
- }
408
 
409
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  <?php
2
+
3
  namespace WPStaging;
4
 
5
  // No Direct Access
6
+ if( !defined( "WPINC" ) ) {
7
+ die;
 
8
  }
9
 
10
  // Ensure to include autoloader class
18
  use WPStaging\Utils\Loader;
19
  use WPStaging\Utils\Logger;
20
  use WPStaging\DI\InjectionAware;
21
+ use WPStaging\Cron\Cron;
22
 
23
  /**
24
  * Class WPStaging
25
  * @package WPStaging
26
  */
27
+ final class WPStaging {
28
+
29
+ /**
30
+ * Plugin version
31
+ */
32
+ const VERSION = "2.0.6";
33
+
34
+ /**
35
+ * Plugin name
36
+ */
37
+ const NAME = "WP Staging";
38
+
39
+ /**
40
+ * Plugin slug
41
+ */
42
+ const SLUG = "wp-staging";
43
+
44
+ /**
45
+ * Compatible WP Version
46
+ */
47
+ const WP_COMPATIBLE = "4.8";
48
+
49
+ /**
50
+ * Slug: Either wp-staging or wp-staging-pro
51
+ * @var string
52
+ */
53
+ public $slug;
54
+
55
+ /**
56
+ * Absolute plugin path
57
+ * @var string
58
+ */
59
+ public $pluginPath;
60
+
61
+ /**
62
+ * Services
63
+ * @var array
64
+ */
65
+ private $services;
66
+
67
+ /**
68
+ * Singleton instance
69
+ * @var WPStaging
70
+ */
71
+ private static $instance;
72
+
73
+ /**
74
+ * WPStaging constructor.
75
+ */
76
+ private function __construct() {
77
+
78
+ $file = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR . self::SLUG . ".php";
79
+
80
+ $this->registerMain();
81
+ $this->registerNamespaces();
82
+ $this->loadLanguages();
83
+ $this->loadDependencies();
84
+ $this->defineHooks();
85
+
86
+ // Licensing stuff be loaded in wpstg core to make cron hook available from frontpage
87
+ $this->licensing();
88
+
89
+ // Activation Hook
90
+ register_activation_hook( $file, array($this, "onActivation") );
91
+ }
92
+
93
+ /**
94
+ * Method to be executed upon activation of the plugin
95
+ */
96
+ public function onActivation() {
97
+ $Activation = new \WPStaging\Backend\Activation\Activation();
98
+ $Activation->install_dependancies();
99
+ }
100
+
101
+ public function registerMain() {
102
+ // Slug of the plugin
103
+ $this->slug = plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
104
+
105
+ // absolute path to the main plugin dir
106
+ $this->pluginPath = plugin_dir_path( dirname( dirname( __FILE__ ) ) );
107
+
108
+ // URL to apps folder
109
+ $this->url = plugin_dir_url( dirname( __FILE__ ) );
110
+
111
+ // URL to backend public folder folder
112
+ $this->backend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Backend/public/";
113
+
114
+ // URL to frontend public folder folder
115
+ $this->frontend_url = plugin_dir_url( dirname( __FILE__ ) ) . "Frontend/public/";
116
+ }
117
+
118
+ /**
119
+ * Define Hooks
120
+ */
121
+ public function defineHooks() {
122
+ $loader = $this->get( "loader" );
123
+ $loader->addAction( "admin_enqueue_scripts", $this, "enqueueElements", 100 );
124
+ $loader->addAction( "wp_enqueue_scripts", $this, "enqueueElements", 100 );
125
+ $this->addIntervals();
126
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
127
 
128
+ /**
129
+ * Add new cron time event "weekly"
130
+ */
131
+ public function addIntervals(){
132
+ $interval = new Cron();
133
+ }
134
+
135
+ /**
136
+ * Scripts and Styles
137
+ * @param string $hook
138
+ */
139
+ public function enqueueElements( $hook ) {
140
+
141
+ // Load this css file on frontend and backend on all pages if current site is a staging site
142
+ if( $this->isStagingSite() ) {
143
+ wp_enqueue_style( "wpstg-admin-bar", $this->backend_url . "css/wpstg-admin-bar.css", $this->getVersion() );
144
+ }
145
+
146
+ $availablePages = array(
147
+ "toplevel_page_wpstg_clone",
148
+ "wp-staging_page_wpstg-settings",
149
+ "wp-staging_page_wpstg-tools",
150
+ "wp-staging_page_wpstg-license",
151
+ "wp-staging_page_wpstg-welcome",
152
+ );
153
+
154
+ // Load these css and js files only on wp staging admin pages
155
+ if( !in_array( $hook, $availablePages ) || !is_admin() ) {
156
+ return;
157
+ }
158
+
159
+ // Load admin js files
160
+ wp_enqueue_script(
161
+ "wpstg-admin-script", $this->backend_url . "js/wpstg-admin.js", array("jquery"), $this->getVersion(), false
162
+ );
163
+
164
+ // Load admin css files
165
+ wp_enqueue_style(
166
+ "wpstg-admin", $this->backend_url . "css/wpstg-admin.css", $this->getVersion()
167
+ );
168
+
169
+ wp_localize_script( "wpstg-admin-script", "wpstg", array(
170
+ "ajaxurl" => admin_url( 'admin-ajax.php' ),
171
+ "nonce" => wp_create_nonce( "wpstg_ajax_nonce" ),
172
+ "mu_plugin_confirmation" => __(
173
+ "If confirmed we will install an additional WordPress 'Must Use' plugin. "
174
+ . "This plugin will allow us to control which plugins are loaded during "
175
+ . "WP Staging specific operations. Do you wish to continue?", "wpstg"
176
+ ),
177
+ "plugin_compatibility_settings_problem" => __(
178
+ "A problem occurred when trying to change the plugin compatibility setting.", "wpstg"
179
+ ),
180
+ "saved" => __( "Saved", "The settings were saved successfully", "wpstg" ),
181
+ "status" => __( "Status", "Current request status", "wpstg" ),
182
+ "response" => __( "Response", "The message the server responded with", "wpstg" ),
183
+ "blacklist_problem" => __(
184
+ "A problem occurred when trying to add plugins to backlist.", "wpstg"
185
+ ),
186
+ "cpuLoad" => $this->getCPULoadSetting(),
187
+ "settings" => ( object ) array() // TODO add settings?
188
+ ) );
189
+ }
190
+
191
+ /**
192
+ * Caching and logging folder
193
+ *
194
+ * @return string
195
+ */
196
+ public static function getContentDir() {
197
+ $wp_upload_dir = wp_upload_dir();
198
+ $path = $wp_upload_dir['basedir'] . '/wp-staging';
199
+ wp_mkdir_p( $path );
200
+ return apply_filters( 'wpstg_get_upload_dir', $path . DIRECTORY_SEPARATOR );
201
+ }
202
+
203
+ /**
204
+ * Register used namespaces
205
+ */
206
+ private function registerNamespaces() {
207
+ $autoloader = new Autoloader();
208
+ $this->set( "autoloader", $autoloader );
209
+
210
+ //wp_die($this->pluginPath . 'apps' . DIRECTORY_SEPARATOR);
211
+ // Autoloader
212
+ $autoloader->registerNamespaces( array(
213
+ "WPStaging" => array(
214
+ $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR,
215
+ $this->pluginPath . 'apps' . DIRECTORY_SEPARATOR . 'Core' . DIRECTORY_SEPARATOR,
216
+ )
217
+ ) );
218
+
219
+ // Register namespaces
220
+ $autoloader->register();
221
+ }
222
+
223
+ /**
224
+ * Get Instance
225
+ * @return WPStaging
226
+ */
227
+ public static function getInstance() {
228
+ if( null === static::$instance ) {
229
+ static::$instance = new static();
230
+ }
231
+
232
+ return static::$instance;
233
+ }
234
+
235
+ /**
236
+ * Prevent cloning
237
+ * @return void
238
+ */
239
+ private function __clone() {
240
+
241
+ }
242
+
243
+ /**
244
+ * Prevent unserialization
245
+ * @return void
246
+ */
247
+ private function __wakeup() {
248
+
249
+ }
250
+
251
+ /**
252
+ * Load Dependencies
253
+ */
254
+ private function loadDependencies() {
255
+ // Set loader
256
+ $this->set( "loader", new Loader() );
257
+
258
+ // Set cache
259
+ $this->set( "cache", new Cache() );
260
+
261
+ // Set logger
262
+ $this->set( "logger", new Logger() );
263
+
264
+ // Set settings
265
+ $this->set( "settings", new Settings() );
266
+
267
+ // Set Administrator
268
+ if( is_admin() ) {
269
+ new Administrator( $this );
270
+ } else {
271
+ new Frontend( $this );
272
+ }
273
+ }
274
+
275
+ /**
276
+ * Execute Plugin
277
+ */
278
+ public function run() {
279
+ $this->get( "loader" )->run();
280
+ }
281
+
282
+ /**
283
+ * Set a variable to DI with given name
284
+ * @param string $name
285
+ * @param mixed $variable
286
+ * @return $this
287
+ */
288
+ public function set( $name, $variable ) {
289
+ // It is a function
290
+ if( is_callable( $variable ) )
291
+ $variable = $variable();
292
+
293
+ // Add it to services
294
+ $this->services[$name] = $variable;
295
+
296
+ return $this;
297
+ }
298
+
299
+ /**
300
+ * Get given name index from DI
301
+ * @param string $name
302
+ * @return mixed|null
303
+ */
304
+ public function get( $name ) {
305
+ return (isset( $this->services[$name] )) ? $this->services[$name] : null;
306
+ }
307
+
308
+ /**
309
+ * @return string
310
+ */
311
+ public function getVersion() {
312
+ return self::VERSION;
313
+ }
314
+
315
+ /**
316
+ * @return string
317
+ */
318
+ public function getName() {
319
+ return self::NAME;
320
+ }
321
+
322
+ /**
323
+ * @return string
324
+ */
325
+ public static function getSlug() {
326
+ return plugin_basename( dirname( dirname( dirname( __FILE__ ) ) ) );
327
+ }
328
+
329
+ /**
330
+ * Get path to main plugin file
331
+ * @return string
332
+ */
333
+ public function getPath() {
334
+ return dirname( dirname( __FILE__ ) );
335
+ }
336
+
337
+ /**
338
+ * Get main plugin url
339
+ * @return type
340
+ */
341
+ public function getUrl() {
342
+ return plugin_dir_url( dirname( __FILE__ ) );
343
+ }
344
+
345
+ /**
346
+ * @return array|mixed|object
347
+ */
348
+ public function getCPULoadSetting() {
349
+ $options = $this->get( "settings" );
350
+ $setting = $options->getCpuLoad();
351
+
352
+ switch ( $setting ) {
353
+ case "high":
354
+ $cpuLoad = 0;
355
+ break;
356
+
357
+ case "medium":
358
+ $cpuLoad = 1000;
359
+ break;
360
+
361
+ case "low":
362
+ $cpuLoad = 3000;
363
+ break;
364
+
365
+ case "default":
366
+ default:
367
+ $cpuLoad = 1000;
368
+ }
369
+
370
+ return $cpuLoad;
371
+ }
372
+
373
+ /**
374
+ * Load language file
375
+ */
376
+ public function loadLanguages() {
377
+ $languagesDirectory = WP_PLUGIN_DIR . DIRECTORY_SEPARATOR . self::SLUG . DIRECTORY_SEPARATOR;
378
+ $languagesDirectory.= "vars" . DIRECTORY_SEPARATOR . "languages" . DIRECTORY_SEPARATOR;
379
+
380
+ // Set filter for plugins languages directory
381
+ $languagesDirectory = apply_filters( "wpstg_languages_directory", $languagesDirectory );
382
+
383
+ // Traditional WP plugin locale filter
384
+ $locale = apply_filters( "plugin_locale", get_locale(), "wpstg" );
385
+ $moFile = sprintf( '%1$s-%2$s.mo', "wpstg", $locale );
386
+
387
+ // Setup paths to current locale file
388
+ $moFileLocal = $languagesDirectory . $moFile;
389
+ $moFileGlobal = WP_LANG_DIR . DIRECTORY_SEPARATOR . "wpstg" . DIRECTORY_SEPARATOR . $moFile;
390
+
391
+ // Global file (/wp-content/languages/WPSTG)
392
+ if( file_exists( $moFileGlobal ) ) {
393
+ load_textdomain( "wpstg", $moFileGlobal );
394
+ }
395
+ // Local file (/wp-content/plugins/wp-staging/languages/)
396
+ elseif( file_exists( $moFileLocal ) ) {
397
+ load_textdomain( "wpstg", $moFileGlobal );
398
+ }
399
+ // Default file
400
+ else {
401
+ load_plugin_textdomain( "wpstg", false, $languagesDirectory );
402
+ }
403
+ }
404
+
405
+ /**
406
+ * Check if it is a staging site
407
+ * @return bool
408
+ */
409
+ private function isStagingSite() {
410
+ return ("true" === get_option( "wpstg_is_staging_site" ));
411
+ }
412
+
413
+ /**
414
+ * Initialize licensing functions
415
+ * @return boolean
416
+ */
417
+ private function licensing() {
418
+ // Add licensing stuff if class exists
419
+ if( class_exists( 'WPStaging\Backend\Pro\Licensing\Licensing' ) ) {
420
+ $licensing = new Backend\Pro\Licensing\Licensing();
421
+ }
422
+ return false;
423
+ }
424
+
425
+ }
apps/Frontend/Frontend.php CHANGED
@@ -35,7 +35,6 @@ class Frontend extends InjectionAware
35
 
36
  $loader->addAction("init", $this, "checkPermissions");
37
  $loader->addFilter("wp_before_admin_bar_render", $this, "changeSiteName");
38
- //$loader->addAction("wp_enqueue_scripts", $this, "enqueueElements", 10);
39
  }
40
 
41
  /**
35
 
36
  $loader->addAction("init", $this, "checkPermissions");
37
  $loader->addFilter("wp_before_admin_bar_render", $this, "changeSiteName");
 
38
  }
39
 
40
  /**
readme.txt CHANGED
@@ -1,251 +1,235 @@
1
- === WP Staging - DB & File Duplicator & Migration ===
2
-
3
- Author URL: https://wordpress.org/plugins/wp-staging
4
- Plugin URL: https://wordpress.org/plugins/wp-staging
5
- Contributors: ReneHermi, WP-Staging
6
- Donate link: https://wordpress.org/plugins/wp-staging
7
- License: GPLv2 or later
8
- 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.7
12
- Stable tag: 2.0.1
13
-
14
- A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
15
-
16
- == Description ==
17
-
18
- <strong>This cloning and staging plugin is well tested but still work in progress! <br>
19
- If you find a bug please open a ticket in the [support request](https://wordpress.org/support/plugin/wp-staging/ "support forum"). Any issues will be fixed asap!
20
- </strong>
21
- <br /><br />
22
- <strong>Note: </strong> This plugin is not able to push back your changes to the live site at the moment!
23
- Please let us know your most requested feature and use our quick poll. It only takes one minute of your time:
24
- [Start the Poll](https://docs.google.com/forms/d/e/1FAIpQLScZ-dO5WffV3xObn16LwG05tr1HrADD_8L4wbTxPHqoPssVcg/viewform?c=0&w=1&usp=mail_form_link "wp staging poll")
25
- <br /> <br />
26
-
27
-
28
- <blockquote>
29
- <h4> WP Staging for WordPress Migration </h4>
30
- This duplicator plugin allows you to create an staging or development environment in seconds* <br /> <br />
31
- It creates a file clone of your website into a subfolder of your current WordPress installation with an entire copy of your database.
32
- This sounds pretty simple and yes it is! All the hard time consumptive database and file copy stuff including url replacements is done in the background.
33
- <br /> <br />
34
- I created this plugin because all other solutions are way too complex, overloaded with dozens of options or having server requirements which are not available on most shared hosting solutions.
35
- All these reasons prevent user from testing new plugins and updates first before installing them on their live website, so its time to release a plugin which has the potential to be merged into everyone´s wordpress workflow.
36
- <br /> <br />
37
- <p><small><em>* Time of creation depends on size of your database and file size</em></small></p>
38
- </blockquote>
39
-
40
- WP Staging helps you to prevent your website from being broken or unavailable because of installing untested plugin updates!
41
-
42
- [youtube https://www.youtube.com/watch?v=Ye3fC6cdB3A]
43
-
44
- = Main Features =
45
-
46
- * <strong>Easy: </strong> Staging migration applicable for everyone. No configuration needed!
47
- * <strong>Fast: </strong> Migration process lasts only a few seconds or minutes, depending on the site's size and server I/O power
48
- * <strong>Safe: </strong> Access to staging site is granted for administrators only.
49
- <br /><br />
50
- <strong>More safe:</strong>
51
- <br>
52
- * Admin bar reflects that you are working on a staging site
53
- * Extensive logging if duplication and migration process fails.
54
-
55
- = What does not work or is not tested when running wordpress migration? =
56
-
57
- * Wordpress migration of wordpress multisites (not tested)
58
- * WordPress duplicating process on windows server (not tested but will probably work)
59
- Edit: Duplication on windows server seems to be working well: [Read more](https://wordpress.org/support/topic/wont-copy-files?replies=5 "Read more")
60
-
61
-
62
- <strong>Change your workflow of updating themes and plugins data:</strong>
63
-
64
- 1. Use WP Staging for migration of a production website to a clone site for staging purposes
65
- 2. Customize theme, configuration and plugins or install new plugins
66
- 3. Test everything on your staging site first
67
- 4. Everything running as expected? You are on the save side for migration of all these modifications to your production site!
68
-
69
-
70
- <h3> Why should i use a staging website? </h3>
71
-
72
- Plugin updates and theme customizations should be tested on a staging platform first. Its recommended to have the staging platform on the same server where the production website is located.
73
- When you run a plugin update or plan to install a new one, it is a necessary task to check first the modifications on a clone of your production website.
74
- This makes sure that any modifications is working on your website without throwing unexpected errors or preventing your site from loading. (Better known as the wordpress blank page error)
75
-
76
- Testing a plugin update before installing it in live environment isn´t done very often by most user because existing staging solutions are too complex and need a lot of time to create a
77
- up-to-date copy of your website.
78
-
79
- Some people are also afraid of installing plugins updates because they follow the rule "never touch a running system" with having in mind that untested updates are increasing the risk of breaking their site.
80
- I totally understand this and i am guilty as well here, but unfortunately this leads to one of the main reasons why WordPress installations are often outdated, not updated at all and unsecure due to this non-update behavior.
81
-
82
- <strong> I think its time to change this, so i created "WP Staging" for WordPress migration of staging sites</strong>
83
-
84
- <h3> Can´t i just use my local wordpress development copy for testing like xampp / lampp? </h3>
85
-
86
- Nope! If your local hardware and software environment is not a 100% exact clone of your production server there is NO guarantee that every aspect
87
- of your local copy is working on your live website exactely as you would expect it.
88
- There are some obvious things like differences in the config of php and the server you are running but even such non obvious settings like the amount of ram or the
89
- the cpu performance can lead to unexpected results on your production website.
90
- There are dozens of other possible cause of failure which can not be handled well when you are testing your changes on a local staging platform.
91
-
92
- This is were WP Staging steps in... Site cloning and staging site creation simplified!
93
-
94
- <h3>I just want to migrate the database from one installation to another</h3>
95
- If you want to migrate your local database to a already existing production site you can use a tool like WP Migrate DB.
96
- WP Staging is only for creating a staging site with latest data from your production site. So it goes the opposite way of WP Migrate DB.
97
- Both tools are excellent cooperating eachother.
98
-
99
- <h3>What are the benefits compared to a plugin like Duplicator?</h3>
100
- At first, i love the [Duplicator plugin](https://wordpress.org/plugins/duplicator/ "Duplicator plugin"). Duplicator is a great tool for migrating from development site to production one or from production site to development one.
101
- The downside is that Duplicator needs adjustments, manually interventions and prerequirements for this. Duplicator also needs some skills to be able to create a development / staging site, where WP Staging does not need more than a click from you.
102
- However, Duplicator is best placed to be a tool for first-time creation of your production site. This is something where it is very handy and powerful.
103
-
104
- So, if you have created a local or webhosted development site and you need to migrate this site the first time to your production domain than you are doing nothing wrong with using
105
- the Duplicator plugin! If you need all you latest production data like posts, updated plugins, theme data and styles in a testing environment than i recommend to use WP Staging instead!
106
-
107
- = I need you feedback =
108
- This plugin has been done in hundreds of hours to work on even the smallest shared webhosting package but i am limited in testing this only on a handful of different server so i need your help:
109
- Please open a [support request](https://wordpress.org/support/plugin/wp-staging/ "support request") and describe your problem exactely. In wp-content/wp-staging/logs you find extended logfiles. Have a look at them and let me know the error-thrown lines.
110
-
111
-
112
- = Important =
113
-
114
- Per default the staging site will have permalinks disabled because the staging site will be cloned into a subfolder and regular permalinks are not working
115
- without doing changes to your .htaccess or nginx.conf.
116
- In the majority of cases this is abolutely fine for a staging platform and you still will be able to test new plugins and do some theme changes on your staging platform.
117
- If you need the same permalink stucture on your staging platform as you have in your prodcution website you have to create a custom .htaccess for apache webserver
118
- or to adjust your nginx.conf.
119
-
120
-
121
- = How to install and setup? =
122
- Install it via the admin dashboard and to 'Plugins', click 'Add New' and search the plugins for 'Staging'. Install the plugin with 'Install Now'.
123
- After installation goto the settings page 'Staging' and do your adjustments there.
124
-
125
-
126
- == Frequently Asked Questions ==
127
-
128
-
129
- == Official Site ==
130
-
131
-
132
- == Installation ==
133
- 1. Download the file "wp-staging" , unzip and place it in your wp-content/plugins/wp-staging folder. You can alternatively upload and install it via the WordPress plugin backend.
134
- 2. Activate the plugin through the 'Plugins' menu in WordPress.
135
- 3. Start Plugins->Staging
136
-
137
- == Screenshots ==
138
-
139
- 1. Step 1. Create new WordPress staging site
140
- 2. Step 2. Scanning your website for files and database tables
141
- 3. Step 3. Wordpress Staging site creation in progress
142
- 4. Finish!
143
-
144
- == Changelog ==
145
-
146
- = 1.1.1 =
147
- * Fix: Change rating url
148
-
149
- = 1.1.0 =
150
- * New: Tested up to WP 4.6
151
- * New: Create a poll and ask what feature is most required
152
-
153
- = 1.0.9 =
154
- * Fix: Undefined WPSTG() warning
155
- * Fix: Change compatibility version to wp 4.5.3
156
-
157
- = 1.0.8 =
158
- * Tested up to WP 4.5.2
159
-
160
- = 1.0.7 =
161
- * Fix: Activation hook is not fired and staging site is not working properly
162
- * Performance: Increase default query copy limit to 1000
163
-
164
- = 1.0.6 =
165
- * Fix: Uninstalling plugin throwing error
166
- * Fix: Error permission admin notice although permission issues are correct
167
-
168
-
169
- = 1.0.5 =
170
- * New: Tested up to WP 4.5
171
- * Fix: Download system log not working
172
- * Fix: Click on Optimizer "Select all | none | invert" links leads to jumping
173
- * Tweak: Make clear that unselecting a checkbox will exlude table or file from copy process
174
- * Tweak: Remove unnecessary text
175
- * Tweak: Change beta notice in dashboard. WP Staging is stable
176
- * Tweak: Change twitter handle to @wpstg
177
-
178
- = 1.0.3 =
179
- * Fix: Missing const MASHFS_VERSION
180
- * Fix: Remove error "table XY has been created, BUT inserting rows failed."
181
- * Fix: Not tested up to 4.4.2 message shown although it's tested up to WP 4.4.2
182
- * New: Disable either free or pro version and does not allow to have both version enabled at the same time
183
-
184
- = 1.0.2 =
185
- * Tweak: Change setting description of uninstall option
186
- * Tweak: Lower tags in readme.txt
187
-
188
- = 1.0.1 =
189
- * New: Orange colored admin bar on staging site for better visualization and comparision between production live site and staging site
190
- * Tweak: Remove contact link on multisite notification
191
-
192
- = 1.0.0 =
193
- * Fix: Do not follow symlinks during file copy process
194
- * Fix: css error
195
- * Fix: Show "not-compatible" notice only when blog version is higher than plugin tested version.
196
- * Fix: undefined var $size
197
- * Fix: Check if $path is null before writing to remaining_files.json
198
- * Fix: $db_helper undefined message
199
- * Fix: Skip non utf8 encoded files during copying process
200
-
201
- = 0.9.9 =
202
- * Fix: Use back ticks for table names to prevent copy errors when table names are containing hyphens or similar special characters
203
- * New: Load option to reduce cpu load and to lower the risk of killed ajax calls because of security flooding mechanism (Prevent 405 errors: not allowed)
204
- * Tweak: Load non minified js file when WPSTG debug mode is enabled
205
-
206
- = 0.9.8 =
207
- * New: Tested up to WP 4.4
208
- * New: New debug mode in settings
209
- * Tweak: Check if url's in staging's wp-config.php needs a replacement and do so.
210
- * Fix: Prevent fatal error and end of copying process. Make sure files are writable before trying to copy them
211
-
212
- = 0.9.7 =
213
- * Fix: Change backend link to https://wordpress.org/plugins/wp-staging/ when using an outdated version of the plugin
214
- * New: Tested up to WP 4.3.1
215
-
216
- = 0.9.6 =
217
- * New: Show notice when there is not enough disk space for a clone
218
- * Fix: PHP Error on 32bit systems: "disk_free_space(): Value too large for defined data type"
219
- * Fix: Copying process of larges files gets interupted sometimes due undefined variable
220
- * Fix: Define width and height for the system info export formular
221
- * Fix: Cannot redeclare deleteDirectory()
222
-
223
- = 0.9.5 =
224
- * Fix: Option for cloning sites which are moved into a subdirectory was not working on several systems
225
- * New: WordPress Migration tested up to WP 4.3
226
-
227
- = 0.9.4 =
228
- * Fix: Large files are copied partly
229
- * Fix: js error xhr.statusText not defined
230
- * New: Option for cloning sites which are moved into a subdirectory. Read more: https://codex.wordpress.org/Giving_WordPress_Its_Own_Directory
231
- * New: Create an alternative copy method for large files
232
- * New: Add new author WP-Staging to the readme.txt and to the wordpress repository
233
-
234
- = 0.9.3 =
235
- * Fix: Rating container is not shown because of wrong wordpress option name
236
- * Tweak: Change color of the rating links
237
-
238
- = 0.9.2 =
239
- * Fix: A conflict with the plugin WP Migrate DB (Pro)
240
- * Fix: Limit the staging name to maximum of 16 characters for migration process
241
-
242
- = 0.9.1 =
243
- * Fix: Change search and replace function for table wp_options when running migration. This prevented on some sites the moving of serialized theme data
244
-
245
- = 0.9 =
246
- * New: Release
247
-
248
- == Upgrade Notice ==
249
-
250
- = 1.1.0 =
251
- 1.1.0 <strong>Compatible up to WP 4.6</strong>
1
+ === WP Staging - DB & File Duplicator & Migration ===
2
+
3
+ Author URL: https://wordpress.org/plugins/wp-staging
4
+ Plugin URL: https://wordpress.org/plugins/wp-staging
5
+ Contributors: ReneHermi, WP-Staging
6
+ Donate link: https://wordpress.org/plugins/wp-staging
7
+ License: GPLv2 or later
8
+ License URI: http://www.gnu.org/licenses/gpl-2.0.html
9
+ Tags: staging, duplication, cloning, clone, migration, sandbox, test site, testing, backup, post, admin, administration, duplicate posts
10
+ Requires at least: 3.6+
11
+ Tested up to: 4.8
12
+ Stable tag: 2.0.6
13
+
14
+ A duplicator plugin! Clone, duplicate and migrate live sites to independent staging and development sites that are available only to administrators.
15
+
16
+ == Description ==
17
+
18
+ <strong>This cloning and staging plugin is well tested but work in progress. <br><br>
19
+ If you find any issue, please open a [support ticket](https://wp-staging.com/support/ "support ticket").
20
+ </strong>
21
+ <br /><br />
22
+ <strong>Note: </strong> For pushing plugins and theme files to live site, check out [https://wp-staging.com/](https://wp-staging.com/ "WP Staging Pro")
23
+ <br /><br />
24
+ <blockquote>
25
+ <h4> WP Staging for WordPress Migration </h4>
26
+ This duplicator plugin allows you to create an staging or development environment in seconds* <br /> <br />
27
+ It creates a clone of your website into a subfolder of your main WordPress installation including an entire copy of your database.
28
+ This sounds pretty simple and yes it is! All the hard time-consumptive database and file copying stuff including url replacements is done in the background.
29
+ <br /> <br />
30
+ I created this plugin because all other solutions are way too complex, overloaded with dozens of options or having server requirements which are not available on most shared hosting solutions.
31
+ All these reasons prevent user from testing new plugins and updates first before installing them on their live website, so its time to release a plugin which has the potential to be merged into everyone´s wordpress workflow.
32
+ <br /><br />
33
+ <p><small><em>* Time of creation depends on size of your database and file size</em></small></p>
34
+ </blockquote>
35
+
36
+ WP Staging helps you to prevent your website from being broken or unavailable because of installing untested plugin updates!
37
+
38
+ [youtube https://www.youtube.com/watch?v=Ye3fC6cdB3A]
39
+
40
+ = Main Features =
41
+
42
+ * <strong>Easy: </strong> Staging migration applicable for everyone. No configuration needed!
43
+ * <strong>Fast: </strong> Migration process lasts only a few seconds or minutes, depending on the site's size and server I/O power
44
+ * <strong>Safe: </strong> Access to staging site is granted for administrators only.
45
+ <br /><br />
46
+ <strong>More safe:</strong>
47
+ <br>
48
+ * Admin bar reflects that you are working on a staging site
49
+ * Extensive logging if duplication and migration process fails.
50
+
51
+ = What does not work or is not tested when running wordpress migration? =
52
+
53
+ * Wordpress migration of wordpress multisites (not tested)
54
+ * WordPress duplicating process on windows server (not tested but will probably work)
55
+ Edit: Duplication on windows server seems to be working well: [Read more](https://wordpress.org/support/topic/wont-copy-files?replies=5 "Read more")
56
+
57
+
58
+ <strong>Change your workflow of updating themes and plugins data:</strong>
59
+
60
+ 1. Use WP Staging for migration of a production website to a clone site for staging purposes
61
+ 2. Customize theme, configuration and plugins or install new plugins
62
+ 3. Test everything on your staging site first
63
+ 4. Everything running as expected? You are on the save side for migration of all these modifications to your production site!
64
+
65
+
66
+ <h3> Why should i use a staging website? </h3>
67
+
68
+ Plugin updates and theme customizations should be tested on a staging platform first. Its recommended to have the staging platform on the same server where the production website is located.
69
+ When you run a plugin update or plan to install a new one, it is a necessary task to check first the modifications on a clone of your production website.
70
+ This makes sure that any modifications is working on your website without throwing unexpected errors or preventing your site from loading. (Better known as the wordpress blank page error)
71
+
72
+ Testing a plugin update before installing it in live environment isn´t done very often by most user because existing staging solutions are too complex and need a lot of time to create a
73
+ up-to-date copy of your website.
74
+
75
+ Some people are also afraid of installing plugins updates because they follow the rule "never touch a running system" with having in mind that untested updates are increasing the risk of breaking their site.
76
+ I totally understand this and i am guilty as well here, but unfortunately this leads to one of the main reasons why WordPress installations are often outdated, not updated at all and unsecure due to this non-update behavior.
77
+
78
+ <strong> I think its time to change this, so i created "WP Staging" for WordPress migration of staging sites</strong>
79
+
80
+ <h3> Can´t i just use my local wordpress development copy for testing like xampp / lampp? </h3>
81
+
82
+ Nope! If your local hardware and software environment is not a 100% exact clone of your production server there is NO guarantee that every aspect
83
+ of your local copy is working on your live website exactely as you would expect it.
84
+ There are some obvious things like differences in the config of php and the server you are running but even such non obvious settings like the amount of ram or the
85
+ the cpu performance can lead to unexpected results on your production website.
86
+ There are dozens of other possible cause of failure which can not be handled well when you are testing your changes on a local staging platform.
87
+
88
+ This is were WP Staging steps in... Site cloning and staging site creation simplified!
89
+
90
+ <h3>I just want to migrate the database from one installation to another</h3>
91
+ If you want to migrate your local database to a already existing production site you can use a tool like WP Migrate DB.
92
+ WP Staging is only for creating a staging site with latest data from your production site. So it goes the opposite way of WP Migrate DB.
93
+ Both tools are excellent cooperating eachother.
94
+
95
+ <h3>What are the benefits compared to a plugin like Duplicator?</h3>
96
+ At first, i love the [Duplicator plugin](https://wordpress.org/plugins/duplicator/ "Duplicator plugin"). Duplicator is a great tool for migrating from development site to production one or from production site to development one.
97
+ The downside is that Duplicator needs adjustments, manually interventions and prerequirements for this. Duplicator also needs some skills to be able to create a development / staging site, where WP Staging does not need more than a click from you.
98
+ However, Duplicator is best placed to be a tool for first-time creation of your production site. This is something where it is very handy and powerful.
99
+
100
+ So, if you have created a local or webhosted development site and you need to migrate this site the first time to your production domain than you are doing nothing wrong with using
101
+ the Duplicator plugin! If you need all you latest production data like posts, updated plugins, theme data and styles in a testing environment than i recommend to use WP Staging instead!
102
+
103
+ = I need you feedback =
104
+ This plugin has been done in hundreds of hours to work on even the smallest shared webhosting package but i am limited in testing this only on a handful of different server so i need your help:
105
+ Please open a [support request](https://wordpress.org/support/plugin/wp-staging/ "support request") and describe your problem exactely. In wp-content/wp-staging/logs you find extended logfiles. Have a look at them and let me know the error-thrown lines.
106
+
107
+
108
+ = Important =
109
+
110
+ Per default the staging site will have permalinks disabled because the staging site will be cloned into a subfolder and regular permalinks are not working
111
+ without doing changes to your .htaccess or nginx.conf.
112
+ In the majority of cases this is abolutely fine for a staging platform and you still will be able to test new plugins and do some theme changes on your staging platform.
113
+ If you need the same permalink stucture on your staging platform as you have in your prodcution website you have to create a custom .htaccess for apache webserver
114
+ or to adjust your nginx.conf.
115
+
116
+
117
+ = How to install and setup? =
118
+ Install it via the admin dashboard and to 'Plugins', click 'Add New' and search the plugins for 'Staging'. Install the plugin with 'Install Now'.
119
+ After installation goto the settings page 'Staging' and do your adjustments there.
120
+
121
+
122
+ == Frequently Asked Questions ==
123
+
124
+
125
+ == Official Site ==
126
+ https://wp-staging.com
127
+
128
+ == Installation ==
129
+ 1. Download the file "wp-staging" , unzip and place it in your wp-content/plugins/wp-staging folder. You can alternatively upload and install it via the WordPress plugin backend.
130
+ 2. Activate the plugin through the 'Plugins' menu in WordPress.
131
+ 3. Start Plugins->Staging
132
+
133
+ == Screenshots ==
134
+
135
+ 1. Step 1. Create new WordPress staging site
136
+ 2. Step 2. Scanning your website for files and database tables
137
+ 3. Step 3. Wordpress Staging site creation in progress
138
+ 4. Finish!
139
+
140
+ == Changelog ==
141
+
142
+
143
+
144
+ = 2.0.6 =
145
+ * Fix: Cancel Cloning button not working
146
+ * Fix: Limit max execution time to a maximum of 30sec to prevent high memory consumption and script timeouts
147
+
148
+
149
+ = 2.0.5 =
150
+ * New: Major version - Complete rewrite of the code base
151
+ * New: Batch processing allows to clone even huge sites without any timeouts
152
+ * New: Preparation for WP QUADS PRO with ability to copy file changes back to live site
153
+ * New: Bypass (broken) third party plugins during wp staging related ajax requests to prevent processing errors. Use a mu plugin for this.
154
+
155
+ = 1.1.6 =
156
+ * New: Add download link to WP Staging Beta Version 2.0.1
157
+
158
+ = 1.1.5 =
159
+ * Fix: Admin notice is throwing a false positive write permission error
160
+ * New: Move log folder to wp-content/uploads/wp-staging/logs
161
+ * New: Tested up to WP 4.7.3
162
+
163
+ = 1.1.4 =
164
+ * Fix: Fatal error Unsupported operand types
165
+
166
+ = 1.1.3 =
167
+ * New: Tested up to wp 4.7.2
168
+ * Fix: Arrows in drop down for folder selection are distorted
169
+ * Tweak: Show working log as default to make debugging easier
170
+
171
+ = 1.1.2 =
172
+ * Fix: Settings are not deleted when plugin is removed
173
+ * Fix: Staging site is available for non administrators
174
+
175
+ = 1.1.1 =
176
+ * Fix: Change rating url
177
+
178
+ = 1.1.0 =
179
+ * New: Tested up to WP 4.6
180
+ * New: Create a poll and ask what feature is most required
181
+
182
+ = 1.0.9 =
183
+ * Fix: Undefined WPSTG() warning
184
+ * Fix: Change compatibility version to wp 4.5.3
185
+
186
+ = 1.0.8 =
187
+ * Tested up to WP 4.5.2
188
+
189
+ = 1.0.7 =
190
+ * Fix: Activation hook is not fired and staging site is not working properly
191
+ * Performance: Increase default query copy limit to 1000
192
+
193
+ = 1.0.6 =
194
+ * Fix: Uninstalling plugin throwing error
195
+ * Fix: Error permission admin notice although permission issues are correct
196
+
197
+
198
+ = 1.0.5 =
199
+ * New: Tested up to WP 4.5
200
+ * Fix: Download system log not working
201
+ * Fix: Click on Optimizer "Select all | none | invert" links leads to jumping
202
+ * Tweak: Make clear that unselecting a checkbox will exlude table or file from copy process
203
+ * Tweak: Remove unnecessary text
204
+ * Tweak: Change beta notice in dashboard. WP Staging is stable
205
+ * Tweak: Change twitter handle to @wpstg
206
+
207
+ = 1.0.3 =
208
+ * Fix: Missing const MASHFS_VERSION
209
+ * Fix: Remove error "table XY has been created, BUT inserting rows failed."
210
+ * Fix: Not tested up to 4.4.2 message shown although it's tested up to WP 4.4.2
211
+ * New: Disable either free or pro version and does not allow to have both version enabled at the same time
212
+
213
+ = 1.0.2 =
214
+ * Tweak: Change setting description of uninstall option
215
+ * Tweak: Lower tags in readme.txt
216
+
217
+ = 1.0.1 =
218
+ * New: Orange colored admin bar on staging site for better visualization and comparision between production live site and staging site
219
+ * Tweak: Remove contact link on multisite notification
220
+
221
+ = 1.0.0 =
222
+ * Fix: Do not follow symlinks during file copy process
223
+ * Fix: css error
224
+ * Fix: Show "not-compatible" notice only when blog version is higher than plugin tested version.
225
+ * Fix: undefined var $size
226
+ * Fix: Check if $path is null before writing to remaining_files.json
227
+ * Fix: $db_helper undefined message
228
+ * Fix: Skip non utf8 encoded files during copying process
229
+
230
+ Complete changelog: [https://wp-staging.com/changelog.txt](https://wp-staging.com/changelog.txt)
231
+
232
+ == Upgrade Notice ==
233
+
234
+ = 2.0.2 =
235
+ 2.0.2 * New: Batch processing allows to clone even huge sites without any timeouts
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
uninstall.php CHANGED
@@ -1,39 +1,89 @@
1
- <?php
2
-
3
- /**
4
- * Uninstall WP-Staging
5
- *
6
- * @package WPSTG
7
- * @subpackage Uninstall
8
- * @copyright Copyright (c) 2015, René Hermenau
9
- * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
10
- * @since 0.9.0
11
- */
12
- // No direct access
13
- if( !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
14
- exit;
15
- }
16
-
17
- // Get options
18
- $options = json_decode( json_encode( get_option( "wpstg_settings", array() ) ) );
19
-
20
- // No need to delete
21
- if( isset( $options->unInstallOnDelete ) && '1' === $options->unInstallOnDelete ) {
22
- // Delete options
23
- delete_option( "wpstg_version_upgraded_from" );
24
- delete_option( "wpstg_version" );
25
- delete_option( "wpstg_installDate" );
26
- delete_option( "wpstg_firsttime" );
27
- delete_option( "wpstg_is_staging_site" );
28
- delete_option( "wpstg_settings" );
29
- delete_option( "wpstg_existing_clones" );
30
- // Old wpstg 1.3 options for admin notices
31
- delete_option( "wpstg_start_poll" );
32
- delete_option( "wpstg_hide_beta" );
33
- delete_option( "wpstg_RatingDiv" );
34
- // New ones
35
- delete_option( "wpstg_poll" );
36
- delete_option( "wpstg_rating" );
37
- delete_option( "wpstg_beta" );
38
- }
39
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ namespace WPStaging\Backend;
4
+
5
+ use WPStaging\Backend\Optimizer\Optimizer;
6
+
7
+ /**
8
+ * Uninstall WP-Staging
9
+ *
10
+ * @package WPSTG
11
+ * @subpackage Uninstall
12
+ * @copyright Copyright (c) 2015, René Hermenau
13
+ * @license http://opensource.org/licenses/gpl-2.0.php GNU Public License
14
+ * @since 0.9.0
15
+ */
16
+ // No direct access
17
+ if( !defined( 'WP_UNINSTALL_PLUGIN' ) ) {
18
+ exit;
19
+ }
20
+
21
+ class uninstall {
22
+
23
+ public function __construct() {
24
+
25
+ // Plugin Folder Path
26
+ if( !defined( 'WPSTG_PLUGIN_DIR' ) ) {
27
+ define( 'WPSTG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
28
+ }
29
+
30
+ /**
31
+ * Path to main WP Staging class
32
+ * Make sure to not redeclare class in case free version has been installed previosly
33
+ */
34
+ if( !class_exists( 'WPStaging\WPStaging' ) ) {
35
+ require_once plugin_dir_path( __FILE__ ) . "apps/Core/WPStaging.php";
36
+ }
37
+ $wpStaging = \WPStaging\WPStaging::getInstance();
38
+
39
+ // Delete our must use plugin
40
+ $this->deleteMuPlugin();
41
+
42
+ $this->init();
43
+ }
44
+
45
+ private function init() {
46
+ $options = json_decode( json_encode( get_option( "wpstg_settings", array() ) ) );
47
+
48
+ if( isset( $options->unInstallOnDelete ) && '1' === $options->unInstallOnDelete ) {
49
+ // Delete options
50
+ delete_option( "wpstg_version_upgraded_from" );
51
+ delete_option( "wpstg_version" );
52
+ delete_option( "wpstg_installDate" );
53
+ delete_option( "wpstg_firsttime" );
54
+ delete_option( "wpstg_is_staging_site" );
55
+ delete_option( "wpstg_settings" );
56
+
57
+ /* Do not delete these fields without actually deleting the staging site
58
+ * @create a delete routine which deletes the staging sites first
59
+ */
60
+ //delete_option( "wpstg_existing_clones" );
61
+ //delete_option( "wpstg_existing_clones_beta" );
62
+
63
+ // Old wpstg 1.3 options for admin notices
64
+ delete_option( "wpstg_start_poll" );
65
+ delete_option( "wpstg_hide_beta" );
66
+ delete_option( "wpstg_RatingDiv" );
67
+
68
+ // New 2.x options for admin notices
69
+ delete_option( "wpstg_poll" );
70
+ delete_option( "wpstg_rating" );
71
+ delete_option( "wpstg_beta" );
72
+
73
+ // Delete events
74
+ wp_clear_scheduled_hook( 'wpstg_weekly_event' );
75
+
76
+ }
77
+ }
78
+
79
+ /**
80
+ * delete MuPlugin
81
+ */
82
+ private function deleteMuPlugin() {
83
+ $optimizer = new Optimizer;
84
+ $optimizer->unstallOptimizer();
85
+ }
86
+
87
+ }
88
+
89
+ new uninstall();
wp-staging.php CHANGED
@@ -1,56 +1,80 @@
1
- <?php
2
-
3
- /**
4
- * Plugin Name: WP Staging
5
- * Plugin URI: wordpress.org/plugins/wp-staging
6
- * Description: Create a staging clone site for testing & developing
7
- * Author: WP-Staging, René Hermenau, Ilgıt Yıldırım
8
- * Author URI: https://wordpress.org/plugins/wp-staging
9
- * Version: 2.0.1
10
- * Text Domain: wpstg
11
- * Domain Path: /languages/
12
-
13
- *
14
- * WP-Staging is free software: you can redistribute it and/or modify
15
- * it under the terms of the GNU General Public License as published by
16
- * the Free Software Foundation, either version 2 of the License, or
17
- * any later version.
18
- *
19
- * WP-Staging is distributed in the hope that it will be useful,
20
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
- * GNU General Public License for more details.
23
- *
24
- * You should have received a copy of the GNU General Public License
25
- * along with Staging. If not, see <http://www.gnu.org/licenses/>.
26
- *
27
- * @package WPSTG
28
- * @category Core
29
- * @author René Hermenau, Ilgıt Yıldırım
30
- */
31
-
32
- // No Direct Access
33
- if (!defined("WPINC"))
34
- {
35
- die;
36
- }
37
-
38
- require_once plugin_dir_path(__FILE__) . "apps/Core/WPStaging.php";
39
-
40
- $wpStaging = \WPStaging\WPStaging::getInstance();
41
-
42
- // Load WP globals into WPStaging
43
- if (isset($wpdb))
44
- {
45
- $wpStaging->set("wpdb", $wpdb);
46
- }
47
-
48
-
49
- if (isset($wp_filter))
50
- {
51
- $wpStaging->set("wp_filter", function() use(&$wp_filter) {
52
- return $wp_filter;
53
- });
54
- }
55
-
56
- $wpStaging->run();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Plugin Name: WP Staging
5
+ * Plugin URI: https://wordpress.org/plugins/wp-staging
6
+ * Description: Create a staging clone site for testing & developing
7
+ * Author: WP-Staging, René Hermenau, Ilgıt Yıldırım
8
+ * Author URI: https://wordpress.org/plugins/wp-staging
9
+ * Version: 2.0.6
10
+ * Text Domain: wpstg
11
+ * Domain Path: /languages/
12
+
13
+ *
14
+ * WP-Staging is free software: you can redistribute it and/or modify
15
+ * it under the terms of the GNU General Public License as published by
16
+ * the Free Software Foundation, either version 2 of the License, or
17
+ * any later version.
18
+ *
19
+ * WP-Staging is distributed in the hope that it will be useful,
20
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22
+ * GNU General Public License for more details.
23
+ *
24
+ * You should have received a copy of the GNU General Public License
25
+ * along with Staging. If not, see <http://www.gnu.org/licenses/>.
26
+ *
27
+ * @package WPSTG
28
+ * @category Core
29
+ * @author René Hermenau, Ilgıt Yıldırım
30
+ */
31
+
32
+ // No Direct Access
33
+ if (!defined("WPINC"))
34
+ {
35
+ die;
36
+ }
37
+
38
+ // Plugin Folder Path
39
+ if( !defined( 'WPSTG_PLUGIN_DIR' ) ) {
40
+ define( 'WPSTG_PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
41
+ }
42
+ // Plugin Folder URL
43
+ if( !defined( 'WPSTG_PLUGIN_URL' ) ) {
44
+ define( 'WPSTG_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
45
+ }
46
+
47
+ //require_once WPSTG_PLUGIN_DIR . 'apps/Backend/Install/install.php';
48
+
49
+ /**
50
+ * Path to main WP Staging class
51
+ * Make sure to not redeclare class in case free version has been installed previosly
52
+ */
53
+ if (!class_exists( 'WPStaging\WPStaging' )){
54
+ require_once plugin_dir_path(__FILE__) . "apps/Core/WPStaging.php";
55
+ }
56
+
57
+ $wpStaging = \WPStaging\WPStaging::getInstance();
58
+
59
+ /**
60
+ * Load a few important WP globals into WPStaging class to make them available via dependancy injection
61
+ */
62
+
63
+ // Wordpress DB Object
64
+ if (isset($wpdb))
65
+ {
66
+ $wpStaging->set("wpdb", $wpdb);
67
+ }
68
+
69
+ // WordPress Filter Object
70
+ if (isset($wp_filter))
71
+ {
72
+ $wpStaging->set("wp_filter", function() use(&$wp_filter) {
73
+ return $wp_filter;
74
+ });
75
+ }
76
+
77
+ /**
78
+ * Inititalize WPStaging
79
+ */
80
+ $wpStaging->run();