Version Description
- Feat: Show creator user name of staging site
- Enh: Show notice if sending mails are disabled
- Enh: Show message and stop execution if php version is lower than 5.5
- Enh: Abort cloning process if table already exists in external database
- Fix: Can not update database credentials in staging sites wp-config.php under rare circumstances
- Fix: During the update process if options table was not selected it didn't get skipped
- Fix: Error if WP is lower than 4.6
- Fix: Can not delete entire staging site on error
- Fix: Activating pro version does not properly disable free version
Download this release
Release Info
Developer | ReneHermi |
Plugin | WP Staging – DB & File Duplicator & Migration |
Version | 2.8.1 |
Comparing to | |
See all releases |
Code changes from version 2.8.0 to 2.8.1
- Backend/Administrator.php +99 -132
- Backend/Modules/Jobs/Cleaners/WpContentCleaner.php +136 -0
- Backend/Modules/Jobs/Cloning.php +12 -3
- Backend/Modules/Jobs/Database.php +17 -2
- Backend/Modules/Jobs/Delete.php +12 -5
- Backend/Modules/Jobs/Files.php +74 -15
- Backend/Modules/Jobs/Finish.php +2 -2
- Backend/Modules/Jobs/Job.php +8 -2
- Backend/Modules/Jobs/Multisite/Files.php +66 -42
- Backend/Modules/Jobs/Multisite/Finish.php +4 -3
- Backend/Modules/Jobs/Updating.php +15 -1
- Backend/Notices/BooleanNotice.php +48 -0
- Backend/Notices/DisabledCacheNotice.php +4 -27
- Backend/Notices/Notices.php +56 -2
- Backend/Optimizer/Optimizer.php +3 -1
- Backend/Optimizer/wp-staging-optimizer.php +12 -12
- Backend/Upgrade/Upgrade.php +0 -6
- Backend/public/css/wpstg-admin.css +34 -14
- Backend/public/js/wpstg-admin-beta.js +1 -1
- Backend/public/js/wpstg-admin-poll.js +1 -1
- Backend/public/js/wpstg-admin.js +27 -7
- Backend/views/clone/ajax/external-database.php +26 -15
- Backend/views/clone/ajax/mail-setting.php +13 -14
- Backend/views/clone/ajax/scan.php +19 -3
- Backend/views/clone/ajax/single-overview.php +12 -3
- Backend/views/clone/ajax/start.php +6 -0
- Backend/views/clone/ajax/update.php +6 -0
- Backend/views/notices/directory-listing-could-not-be-prevented.php +14 -0
- Backend/views/settings/main-settings.php +33 -427
- Backend/views/settings/tabs/general.php +401 -0
- Backend/views/settings/tabs/mail-settings.php +20 -0
- Backend/views/tools/index.php +28 -28
- Bootstrap/V1/Requirements/WpstgFreeRequirements.php +0 -183
- Bootstrap/V1/Requirements/WpstgProRequirements.php +0 -40
- Bootstrap/V1/Requirements/WpstgRequirements.php +0 -36
- Bootstrap/V1/WpstgBootstrap.php +0 -61
- Component/Job/AbstractJob.php +0 -3
- Component/Job/AbstractQueueJob.php +30 -44
- Component/Job/QueueJobDto.php +2 -2
- Component/Task/Filesystem/DirectoryScannerRequestDto.php +6 -6
- Component/Task/Filesystem/DirectoryScannerTask.php +29 -22
- Component/Task/Filesystem/FileScannerRequestDto.php +22 -7
- Component/Task/Filesystem/FileScannerTask.php +20 -19
- Core/Cron/Cron.php +10 -5
- Core/Utils/Cache.php +10 -10
- Core/Utils/Filesystem.php +0 -56
- Core/Utils/Htaccess.php +1 -1
- Core/Utils/IISWebConfig.php +1 -1
- Core/Utils/Logger.php +7 -12
- Core/Utils/RobotsTxt.php +1 -1
- Core/Utils/functions.php +0 -61
- Core/Utils/requirements-check.php +0 -211
- Core/WPStaging.php +67 -20
- Entity/DatabaseSettings.php +0 -54
- Entity/FilesystemSettings.php +0 -93
- Entity/Settings.php +0 -289
- Framework/Adapter/Directory.php +5 -12
- Framework/CloningProcess/Data/DBCloningService.php +12 -8
- Framework/CloningProcess/Data/UpdateStagingOptionsTable.php +1 -1
- Framework/CloningProcess/Data/UpdateWpConfigTablePrefix.php +3 -2
- Framework/CloningProcess/Database/DatabaseCloningService.php +14 -1
- Framework/DI/Container.php +48 -0
- Framework/Filesystem/DirectoryListing.php +172 -0
- Framework/Filesystem/DirectoryScanner.php +44 -117
- Framework/Filesystem/DirectoryScannerControl.php +146 -0
- Framework/Filesystem/DirectoryService.php +0 -65
- Framework/Filesystem/FileScanner.php +73 -105
- Framework/Filesystem/FileScannerControl.php +126 -0
- Framework/Filesystem/FileService.php +0 -115
- Framework/Filesystem/Filesystem.php +354 -16
- Framework/Filesystem/Permissions.php +35 -0
- Framework/Filesystem/WpUploadsFolderSymlinker.php +3 -20
- Framework/Mails/Report/Report.php +10 -3
- Framework/Security/Auth.php +67 -0
- Framework/Staging/FirstRun.php +12 -2
- Framework/Traits/BenchmarkTrait.php +42 -0
- Framework/Traits/HydrateTrait.php +11 -2
- Framework/Traits/ResourceTrait.php +36 -39
- Framework/Traits/TimerTrait.php +1 -4
- Framework/Utils/Cache/AbstractCache.php +4 -1
- Framework/Utils/Cache/Cache.php +0 -1
- Framework/Utils/FileSystem.php +0 -57
- Framework/Utils/WpDefaultDirectories.php +44 -2
- Repository/SettingsRepository.php +0 -43
- _init.php +0 -57
- Bootstrap/autoloader.php → autoloader.php +3 -7
- bootstrap.php +73 -0
- constants.php +0 -25
- constantsFree.php +10 -0
- freeBootstrap.php +59 -0
- install.php +25 -71
- readme.txt +36 -23
- runtimeRequirements.php +79 -0
- template/.gitkeep +0 -0
- template/Component/Backend/Snapshot/listing.php +0 -102
- uninstall.php +1 -0
- vendor_wpstg/autoload/src.php +8 -9
- wp-staging.php +15 -46
Backend/Administrator.php
CHANGED
@@ -7,10 +7,13 @@ if (!defined("WPINC")) {
|
|
7 |
die;
|
8 |
}
|
9 |
|
|
|
10 |
use WPStaging\Framework\Database\DbInfo;
|
|
|
11 |
use WPStaging\Framework\Security\AccessToken;
|
12 |
use WPStaging\Framework\Security\Capabilities;
|
13 |
-
use WPStaging\
|
|
|
14 |
use WPStaging\Backend\Modules\Jobs\Cancel;
|
15 |
use WPStaging\Backend\Modules\Jobs\CancelUpdate;
|
16 |
use WPStaging\Backend\Modules\Jobs\Cloning;
|
@@ -27,9 +30,8 @@ use WPStaging\Backend\Modules\Views\Forms\Settings as FormSettings;
|
|
27 |
use WPStaging\Backend\Activation;
|
28 |
use WPStaging\Backend\Feedback;
|
29 |
use WPStaging\Backend\Pro\Modules\Jobs\Processing;
|
|
|
30 |
use WPStaging\Pro\Database\CompareExternalDatabase;
|
31 |
-
use WPStaging\Framework\Mails\Report\Report;
|
32 |
-
use WPStaging\Framework\Security\Nonce;
|
33 |
|
34 |
/**
|
35 |
* Class Administrator
|
@@ -60,19 +62,9 @@ class Administrator
|
|
60 |
private $url;
|
61 |
|
62 |
/**
|
63 |
-
* @var
|
64 |
-
*/
|
65 |
-
private $accessToken;
|
66 |
-
|
67 |
-
/**
|
68 |
-
* @var Capabilities
|
69 |
*/
|
70 |
-
private $
|
71 |
-
|
72 |
-
/**
|
73 |
-
* @var Nonce
|
74 |
-
*/
|
75 |
-
private $nonce;
|
76 |
|
77 |
/**
|
78 |
* @var array
|
@@ -86,9 +78,7 @@ class Administrator
|
|
86 |
public function __construct()
|
87 |
{
|
88 |
// Todo: Inject using DI
|
89 |
-
$this->
|
90 |
-
$this->capabilities = new Capabilities;
|
91 |
-
$this->nonce = new Nonce;
|
92 |
|
93 |
$this->defineHooks();
|
94 |
|
@@ -107,7 +97,7 @@ class Administrator
|
|
107 |
*/
|
108 |
public function loadMeta()
|
109 |
{
|
110 |
-
$run = new
|
111 |
}
|
112 |
|
113 |
/**
|
@@ -305,18 +295,15 @@ class Administrator
|
|
305 |
public function getSettingsPage()
|
306 |
{
|
307 |
// Tabs
|
308 |
-
$tabs = new Tabs([
|
309 |
"general" => __("General", "wp-staging")
|
310 |
-
]);
|
311 |
-
|
312 |
|
313 |
WPStaging::getInstance()
|
314 |
// Set tabs
|
315 |
->set("tabs", $tabs)
|
316 |
// Forms
|
317 |
-
->set("forms", new FormSettings($tabs))
|
318 |
-
;
|
319 |
-
|
320 |
|
321 |
require_once "{$this->path}views/settings/main-settings.php";
|
322 |
}
|
@@ -435,7 +422,7 @@ class Administrator
|
|
435 |
ignore_user_abort(true);
|
436 |
|
437 |
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
|
438 |
-
if (!in_array("set_time_limit", explode(',', ini_get("disable_functions")))
|
439 |
set_time_limit(0);
|
440 |
}
|
441 |
|
@@ -484,15 +471,9 @@ class Administrator
|
|
484 |
/**
|
485 |
* @return bool Whether the current request is considered to be authenticated.
|
486 |
*/
|
487 |
-
private function isAuthenticated()
|
488 |
-
|
489 |
-
|
490 |
-
$this->nonce->requestHasValidNonce(Nonce::WPSTG_NONCE)
|
491 |
-
) {
|
492 |
-
return true;
|
493 |
-
} else {
|
494 |
-
return $this->accessToken->requestHasValidToken();
|
495 |
-
}
|
496 |
}
|
497 |
|
498 |
/**
|
@@ -500,8 +481,8 @@ class Administrator
|
|
500 |
*/
|
501 |
public function ajaxRestart()
|
502 |
{
|
503 |
-
if (
|
504 |
-
return
|
505 |
}
|
506 |
|
507 |
$process = new ProcessLock();
|
@@ -513,8 +494,8 @@ class Administrator
|
|
513 |
*/
|
514 |
public function ajaxOverview()
|
515 |
{
|
516 |
-
if (
|
517 |
-
return
|
518 |
}
|
519 |
|
520 |
// Existing clones
|
@@ -538,8 +519,8 @@ class Administrator
|
|
538 |
*/
|
539 |
public function ajaxCloneScan()
|
540 |
{
|
541 |
-
if (
|
542 |
-
return
|
543 |
}
|
544 |
|
545 |
// Check first if there is already a process running
|
@@ -565,8 +546,8 @@ class Administrator
|
|
565 |
*/
|
566 |
public function ajaxCheckCloneName()
|
567 |
{
|
568 |
-
if (
|
569 |
-
return
|
570 |
}
|
571 |
|
572 |
$cloneName = sanitize_key($_POST["cloneID"]);
|
@@ -601,14 +582,14 @@ class Administrator
|
|
601 |
*/
|
602 |
public function ajaxUpdateProcess()
|
603 |
{
|
604 |
-
if (
|
605 |
-
return
|
606 |
}
|
607 |
|
608 |
$cloning = new Updating();
|
609 |
|
610 |
if (!$cloning->save()) {
|
611 |
-
wp_die('
|
612 |
}
|
613 |
|
614 |
require_once "{$this->path}views/clone/ajax/update.php";
|
@@ -622,7 +603,7 @@ class Administrator
|
|
622 |
public function ajaxStartClone()
|
623 |
{
|
624 |
if (!$this->isAuthenticated()) {
|
625 |
-
return
|
626 |
}
|
627 |
|
628 |
// Check first if there is already a process running
|
@@ -645,17 +626,11 @@ class Administrator
|
|
645 |
*/
|
646 |
public function ajaxCloneDatabase()
|
647 |
{
|
648 |
-
if (
|
649 |
-
return
|
650 |
}
|
651 |
|
652 |
-
|
653 |
-
|
654 |
-
// Uncomment these lines to test different error codes
|
655 |
-
//http_response_code(504);
|
656 |
-
//wp_send_json( '<html><body><head></head><body>test</body></html>' );
|
657 |
-
|
658 |
-
wp_send_json($cloning->start());
|
659 |
}
|
660 |
|
661 |
/**
|
@@ -663,13 +638,11 @@ class Administrator
|
|
663 |
*/
|
664 |
public function ajaxPrepareDirectories()
|
665 |
{
|
666 |
-
if (
|
667 |
-
return
|
668 |
}
|
669 |
|
670 |
-
|
671 |
-
|
672 |
-
wp_send_json($cloning->start());
|
673 |
}
|
674 |
|
675 |
/**
|
@@ -677,13 +650,11 @@ class Administrator
|
|
677 |
*/
|
678 |
public function ajaxCopyFiles()
|
679 |
{
|
680 |
-
if (
|
681 |
-
return
|
682 |
}
|
683 |
|
684 |
-
|
685 |
-
|
686 |
-
wp_send_json($cloning->start());
|
687 |
}
|
688 |
|
689 |
/**
|
@@ -691,13 +662,11 @@ class Administrator
|
|
691 |
*/
|
692 |
public function ajaxReplaceData()
|
693 |
{
|
694 |
-
if (
|
695 |
-
return
|
696 |
}
|
697 |
|
698 |
-
|
699 |
-
|
700 |
-
wp_send_json($cloning->start());
|
701 |
}
|
702 |
|
703 |
/**
|
@@ -705,13 +674,11 @@ class Administrator
|
|
705 |
*/
|
706 |
public function ajaxFinish()
|
707 |
{
|
708 |
-
if (
|
709 |
-
return
|
710 |
}
|
711 |
|
712 |
-
|
713 |
-
|
714 |
-
wp_send_json($cloning->start());
|
715 |
}
|
716 |
|
717 |
/**
|
@@ -720,10 +687,11 @@ class Administrator
|
|
720 |
public function ajaxDeleteConfirmation()
|
721 |
{
|
722 |
if (!$this->isAuthenticated()) {
|
723 |
-
return
|
724 |
}
|
725 |
|
726 |
$delete = new Delete();
|
|
|
727 |
$isDatabaseConnected = $delete->setData();
|
728 |
|
729 |
$clone = $delete->getClone();
|
@@ -740,13 +708,11 @@ class Administrator
|
|
740 |
*/
|
741 |
public function ajaxDeleteClone()
|
742 |
{
|
743 |
-
if (
|
744 |
-
return
|
745 |
}
|
746 |
|
747 |
-
|
748 |
-
|
749 |
-
wp_send_json($delete->start());
|
750 |
}
|
751 |
|
752 |
/**
|
@@ -754,13 +720,11 @@ class Administrator
|
|
754 |
*/
|
755 |
public function ajaxCancelClone()
|
756 |
{
|
757 |
-
if (
|
758 |
-
return
|
759 |
}
|
760 |
|
761 |
-
|
762 |
-
|
763 |
-
wp_send_json($cancel->start());
|
764 |
}
|
765 |
|
766 |
/**
|
@@ -768,12 +732,11 @@ class Administrator
|
|
768 |
*/
|
769 |
public function ajaxCancelUpdate()
|
770 |
{
|
771 |
-
if (
|
772 |
-
return
|
773 |
}
|
774 |
|
775 |
-
|
776 |
-
wp_send_json($cancel->start());
|
777 |
}
|
778 |
|
779 |
/**
|
@@ -781,45 +744,40 @@ class Administrator
|
|
781 |
*/
|
782 |
public function messages()
|
783 |
{
|
784 |
-
|
785 |
-
|
786 |
-
$run = $notice->messages();
|
787 |
}
|
788 |
|
789 |
/**
|
790 |
* Ajax Hide Poll
|
791 |
* @todo check if this is being used, remove otherwise.
|
792 |
-
* @return mixed boolean | json
|
793 |
*/
|
794 |
public function ajaxHidePoll()
|
795 |
{
|
796 |
if (update_option("wpstg_poll", "no") !== false) {
|
797 |
wp_send_json(true);
|
798 |
}
|
799 |
-
|
|
|
800 |
}
|
801 |
|
802 |
/**
|
803 |
* Ajax Hide Rating
|
804 |
*
|
805 |
* Runs when the user dismisses the notice to rate the plugin.
|
806 |
-
*
|
807 |
-
* @return mixed bool | json
|
808 |
*/
|
809 |
public function ajaxHideRating()
|
810 |
{
|
811 |
if (update_option("wpstg_rating", "no") !== false) {
|
812 |
wp_send_json(true);
|
813 |
}
|
814 |
-
|
|
|
815 |
}
|
816 |
|
817 |
/**
|
818 |
* Ajax Hide Rating and show it again after one week
|
819 |
*
|
820 |
* Runs when the user chooses to rate the plugin later.
|
821 |
-
*
|
822 |
-
* @return mixed bool | json
|
823 |
*/
|
824 |
public function ajaxHideLaterRating()
|
825 |
{
|
@@ -827,7 +785,8 @@ class Administrator
|
|
827 |
if (update_option('wpstg_rating', $date) !== false) {
|
828 |
wp_send_json(true);
|
829 |
}
|
830 |
-
|
|
|
831 |
}
|
832 |
|
833 |
/**
|
@@ -840,14 +799,15 @@ class Administrator
|
|
840 |
|
841 |
/**
|
842 |
* Ajax Hide Cache Notice shown on staging site
|
843 |
-
* @return mixed boolean | json
|
844 |
*/
|
845 |
public function ajaxHideCacheNotice()
|
846 |
{
|
|
|
847 |
if ((new DisabledCacheNotice())->disable() !== false) {
|
848 |
wp_send_json(true);
|
849 |
}
|
850 |
-
|
|
|
851 |
}
|
852 |
|
853 |
/**
|
@@ -855,12 +815,11 @@ class Administrator
|
|
855 |
*/
|
856 |
public function ajaxLogs()
|
857 |
{
|
858 |
-
if (
|
859 |
-
return
|
860 |
}
|
861 |
|
862 |
-
|
863 |
-
wp_send_json($logs->start());
|
864 |
}
|
865 |
|
866 |
/**
|
@@ -868,7 +827,7 @@ class Administrator
|
|
868 |
*/
|
869 |
public function ajaxCheckFreeSpace()
|
870 |
{
|
871 |
-
if (
|
872 |
return false;
|
873 |
}
|
874 |
|
@@ -881,8 +840,8 @@ class Administrator
|
|
881 |
*/
|
882 |
public function ajaxEditCloneData()
|
883 |
{
|
884 |
-
if (
|
885 |
-
return
|
886 |
}
|
887 |
|
888 |
$listOfClones = get_option("wpstg_existing_clones_beta", []);
|
@@ -901,8 +860,8 @@ class Administrator
|
|
901 |
*/
|
902 |
public function ajaxSaveCloneData()
|
903 |
{
|
904 |
-
if (
|
905 |
-
return
|
906 |
}
|
907 |
|
908 |
$listOfClones = get_option("wpstg_existing_clones_beta", []);
|
@@ -913,21 +872,21 @@ class Administrator
|
|
913 |
}
|
914 |
|
915 |
// Use directory name as new array key to maintain existing structure
|
916 |
-
$keys
|
917 |
$keys[array_search($_POST["clone"], $keys)] = $_POST["directoryName"];
|
918 |
-
$listOfClones
|
919 |
|
920 |
$cloneId = $_POST["directoryName"];
|
921 |
|
922 |
-
$listOfClones[$cloneId]["directoryName"]
|
923 |
-
$listOfClones[$cloneId]["path"]
|
924 |
-
$listOfClones[$cloneId]["url"]
|
925 |
-
$listOfClones[$cloneId]["prefix"]
|
926 |
-
$listOfClones[$cloneId]["databaseUser"]
|
927 |
$listOfClones[$cloneId]["databasePassword"] = stripslashes($_POST["externalDBPassword"]);
|
928 |
$listOfClones[$cloneId]["databaseDatabase"] = stripslashes($_POST["externalDBDatabase"]);
|
929 |
-
$listOfClones[$cloneId]["databaseServer"]
|
930 |
-
$listOfClones[$cloneId]["databasePrefix"]
|
931 |
|
932 |
update_option("wpstg_existing_clones_beta", $listOfClones);
|
933 |
|
@@ -947,7 +906,7 @@ class Administrator
|
|
947 |
*/
|
948 |
public function ajaxPushScan()
|
949 |
{
|
950 |
-
if (
|
951 |
return false;
|
952 |
}
|
953 |
|
@@ -973,7 +932,7 @@ class Administrator
|
|
973 |
*/
|
974 |
public function ajaxPushProcessing()
|
975 |
{
|
976 |
-
if (
|
977 |
return false;
|
978 |
}
|
979 |
|
@@ -982,8 +941,7 @@ class Administrator
|
|
982 |
}
|
983 |
|
984 |
// Start the process
|
985 |
-
|
986 |
-
wp_send_json($processing->start());
|
987 |
}
|
988 |
|
989 |
/**
|
@@ -991,7 +949,6 @@ class Administrator
|
|
991 |
*/
|
992 |
public function getLicensePage()
|
993 |
{
|
994 |
-
|
995 |
// Get license data
|
996 |
$license = get_option('wpstg_license_status');
|
997 |
|
@@ -1004,8 +961,8 @@ class Administrator
|
|
1004 |
*/
|
1005 |
public function ajaxSendReport($args = [])
|
1006 |
{
|
1007 |
-
if (
|
1008 |
-
return
|
1009 |
}
|
1010 |
|
1011 |
// Set params
|
@@ -1058,7 +1015,7 @@ class Administrator
|
|
1058 |
public function ajaxDatabaseConnect()
|
1059 |
{
|
1060 |
if (!$this->isAuthenticated()) {
|
1061 |
-
return
|
1062 |
}
|
1063 |
|
1064 |
$args = $_POST;
|
@@ -1066,15 +1023,25 @@ class Administrator
|
|
1066 |
$password = !empty($args['databasePassword']) ? $args['databasePassword'] : '';
|
1067 |
$database = !empty($args['databaseDatabase']) ? $args['databaseDatabase'] : '';
|
1068 |
$server = !empty($args['databaseServer']) ? $args['databaseServer'] : 'localhost';
|
|
|
1069 |
|
1070 |
$dbInfo = new DbInfo($server, $user, stripslashes($password), $database);
|
|
|
1071 |
$error = $dbInfo->getError();
|
|
|
1072 |
// Can not connect to mysql database
|
1073 |
if ($error !== null) {
|
1074 |
echo json_encode(['success' => 'false', 'errors' => $error]);
|
1075 |
exit;
|
1076 |
}
|
1077 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1078 |
echo json_encode(['success' => 'true']);
|
1079 |
exit;
|
1080 |
}
|
@@ -1085,11 +1052,11 @@ class Administrator
|
|
1085 |
public function ajaxDatabaseVerification()
|
1086 |
{
|
1087 |
if (!$this->isAuthenticated()) {
|
1088 |
-
return
|
1089 |
}
|
1090 |
|
1091 |
if (!$this->isPro()) {
|
1092 |
-
return
|
1093 |
}
|
1094 |
|
1095 |
$user = !empty($_POST['databaseUser']) ? $_POST['databaseUser'] : '';
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
+
use WPStaging\Core\WPStaging;
|
11 |
use WPStaging\Framework\Database\DbInfo;
|
12 |
+
use WPStaging\Framework\Security\Auth;
|
13 |
use WPStaging\Framework\Security\AccessToken;
|
14 |
use WPStaging\Framework\Security\Capabilities;
|
15 |
+
use WPStaging\Framework\Security\Nonce;
|
16 |
+
use WPStaging\Framework\Mails\Report\Report;
|
17 |
use WPStaging\Backend\Modules\Jobs\Cancel;
|
18 |
use WPStaging\Backend\Modules\Jobs\CancelUpdate;
|
19 |
use WPStaging\Backend\Modules\Jobs\Cloning;
|
30 |
use WPStaging\Backend\Activation;
|
31 |
use WPStaging\Backend\Feedback;
|
32 |
use WPStaging\Backend\Pro\Modules\Jobs\Processing;
|
33 |
+
use WPStaging\Backend\Pluginmeta\Pluginmeta;
|
34 |
use WPStaging\Pro\Database\CompareExternalDatabase;
|
|
|
|
|
35 |
|
36 |
/**
|
37 |
* Class Administrator
|
62 |
private $url;
|
63 |
|
64 |
/**
|
65 |
+
* @var Auth
|
|
|
|
|
|
|
|
|
|
|
66 |
*/
|
67 |
+
private $auth;
|
|
|
|
|
|
|
|
|
|
|
68 |
|
69 |
/**
|
70 |
* @var array
|
78 |
public function __construct()
|
79 |
{
|
80 |
// Todo: Inject using DI
|
81 |
+
$this->auth = new Auth(new Capabilities, new AccessToken, new Nonce);
|
|
|
|
|
82 |
|
83 |
$this->defineHooks();
|
84 |
|
97 |
*/
|
98 |
public function loadMeta()
|
99 |
{
|
100 |
+
$run = new Pluginmeta();
|
101 |
}
|
102 |
|
103 |
/**
|
295 |
public function getSettingsPage()
|
296 |
{
|
297 |
// Tabs
|
298 |
+
$tabs = new Tabs(apply_filters('wpstg_main_settings_tabs', [
|
299 |
"general" => __("General", "wp-staging")
|
300 |
+
]));
|
|
|
301 |
|
302 |
WPStaging::getInstance()
|
303 |
// Set tabs
|
304 |
->set("tabs", $tabs)
|
305 |
// Forms
|
306 |
+
->set("forms", new FormSettings($tabs));
|
|
|
|
|
307 |
|
308 |
require_once "{$this->path}views/settings/main-settings.php";
|
309 |
}
|
422 |
ignore_user_abort(true);
|
423 |
|
424 |
// phpcs:ignore PHPCompatibility.IniDirectives.RemovedIniDirectives.safe_modeDeprecatedRemoved
|
425 |
+
if (!in_array("set_time_limit", explode(',', ini_get("disable_functions")))) {
|
426 |
set_time_limit(0);
|
427 |
}
|
428 |
|
471 |
/**
|
472 |
* @return bool Whether the current request is considered to be authenticated.
|
473 |
*/
|
474 |
+
private function isAuthenticated()
|
475 |
+
{
|
476 |
+
return $this->auth->isValid();
|
|
|
|
|
|
|
|
|
|
|
|
|
477 |
}
|
478 |
|
479 |
/**
|
481 |
*/
|
482 |
public function ajaxRestart()
|
483 |
{
|
484 |
+
if (!$this->isAuthenticated()) {
|
485 |
+
return;
|
486 |
}
|
487 |
|
488 |
$process = new ProcessLock();
|
494 |
*/
|
495 |
public function ajaxOverview()
|
496 |
{
|
497 |
+
if (!$this->isAuthenticated()) {
|
498 |
+
return;
|
499 |
}
|
500 |
|
501 |
// Existing clones
|
519 |
*/
|
520 |
public function ajaxCloneScan()
|
521 |
{
|
522 |
+
if (!$this->isAuthenticated()) {
|
523 |
+
return;
|
524 |
}
|
525 |
|
526 |
// Check first if there is already a process running
|
546 |
*/
|
547 |
public function ajaxCheckCloneName()
|
548 |
{
|
549 |
+
if (!$this->isAuthenticated()) {
|
550 |
+
return;
|
551 |
}
|
552 |
|
553 |
$cloneName = sanitize_key($_POST["cloneID"]);
|
582 |
*/
|
583 |
public function ajaxUpdateProcess()
|
584 |
{
|
585 |
+
if (!$this->isAuthenticated()) {
|
586 |
+
return;
|
587 |
}
|
588 |
|
589 |
$cloning = new Updating();
|
590 |
|
591 |
if (!$cloning->save()) {
|
592 |
+
wp_die('Can not save clone data');
|
593 |
}
|
594 |
|
595 |
require_once "{$this->path}views/clone/ajax/update.php";
|
603 |
public function ajaxStartClone()
|
604 |
{
|
605 |
if (!$this->isAuthenticated()) {
|
606 |
+
return;
|
607 |
}
|
608 |
|
609 |
// Check first if there is already a process running
|
626 |
*/
|
627 |
public function ajaxCloneDatabase()
|
628 |
{
|
629 |
+
if (!$this->isAuthenticated()) {
|
630 |
+
return;
|
631 |
}
|
632 |
|
633 |
+
wp_send_json((new Cloning)->start());
|
|
|
|
|
|
|
|
|
|
|
|
|
634 |
}
|
635 |
|
636 |
/**
|
638 |
*/
|
639 |
public function ajaxPrepareDirectories()
|
640 |
{
|
641 |
+
if (!$this->isAuthenticated()) {
|
642 |
+
return;
|
643 |
}
|
644 |
|
645 |
+
wp_send_json((new Cloning)->start());
|
|
|
|
|
646 |
}
|
647 |
|
648 |
/**
|
650 |
*/
|
651 |
public function ajaxCopyFiles()
|
652 |
{
|
653 |
+
if (!$this->isAuthenticated()) {
|
654 |
+
return;
|
655 |
}
|
656 |
|
657 |
+
wp_send_json((new Cloning)->start());
|
|
|
|
|
658 |
}
|
659 |
|
660 |
/**
|
662 |
*/
|
663 |
public function ajaxReplaceData()
|
664 |
{
|
665 |
+
if (!$this->isAuthenticated()) {
|
666 |
+
return;
|
667 |
}
|
668 |
|
669 |
+
wp_send_json((new Cloning)->start());
|
|
|
|
|
670 |
}
|
671 |
|
672 |
/**
|
674 |
*/
|
675 |
public function ajaxFinish()
|
676 |
{
|
677 |
+
if (!$this->isAuthenticated()) {
|
678 |
+
return;
|
679 |
}
|
680 |
|
681 |
+
wp_send_json((new Cloning)->start());
|
|
|
|
|
682 |
}
|
683 |
|
684 |
/**
|
687 |
public function ajaxDeleteConfirmation()
|
688 |
{
|
689 |
if (!$this->isAuthenticated()) {
|
690 |
+
return;
|
691 |
}
|
692 |
|
693 |
$delete = new Delete();
|
694 |
+
|
695 |
$isDatabaseConnected = $delete->setData();
|
696 |
|
697 |
$clone = $delete->getClone();
|
708 |
*/
|
709 |
public function ajaxDeleteClone()
|
710 |
{
|
711 |
+
if (!$this->isAuthenticated()) {
|
712 |
+
return;
|
713 |
}
|
714 |
|
715 |
+
wp_send_json((new Delete)->start());
|
|
|
|
|
716 |
}
|
717 |
|
718 |
/**
|
720 |
*/
|
721 |
public function ajaxCancelClone()
|
722 |
{
|
723 |
+
if (!$this->isAuthenticated()) {
|
724 |
+
return;
|
725 |
}
|
726 |
|
727 |
+
wp_send_json((new Cancel)->start());
|
|
|
|
|
728 |
}
|
729 |
|
730 |
/**
|
732 |
*/
|
733 |
public function ajaxCancelUpdate()
|
734 |
{
|
735 |
+
if (!$this->isAuthenticated()) {
|
736 |
+
return;
|
737 |
}
|
738 |
|
739 |
+
wp_send_json((new CancelUpdate)->start());
|
|
|
740 |
}
|
741 |
|
742 |
/**
|
744 |
*/
|
745 |
public function messages()
|
746 |
{
|
747 |
+
(new Notices($this->path, $this->url))->messages();
|
|
|
|
|
748 |
}
|
749 |
|
750 |
/**
|
751 |
* Ajax Hide Poll
|
752 |
* @todo check if this is being used, remove otherwise.
|
|
|
753 |
*/
|
754 |
public function ajaxHidePoll()
|
755 |
{
|
756 |
if (update_option("wpstg_poll", "no") !== false) {
|
757 |
wp_send_json(true);
|
758 |
}
|
759 |
+
|
760 |
+
wp_send_json(null);
|
761 |
}
|
762 |
|
763 |
/**
|
764 |
* Ajax Hide Rating
|
765 |
*
|
766 |
* Runs when the user dismisses the notice to rate the plugin.
|
|
|
|
|
767 |
*/
|
768 |
public function ajaxHideRating()
|
769 |
{
|
770 |
if (update_option("wpstg_rating", "no") !== false) {
|
771 |
wp_send_json(true);
|
772 |
}
|
773 |
+
|
774 |
+
wp_send_json(null);
|
775 |
}
|
776 |
|
777 |
/**
|
778 |
* Ajax Hide Rating and show it again after one week
|
779 |
*
|
780 |
* Runs when the user chooses to rate the plugin later.
|
|
|
|
|
781 |
*/
|
782 |
public function ajaxHideLaterRating()
|
783 |
{
|
785 |
if (update_option('wpstg_rating', $date) !== false) {
|
786 |
wp_send_json(true);
|
787 |
}
|
788 |
+
|
789 |
+
wp_send_json(false);
|
790 |
}
|
791 |
|
792 |
/**
|
799 |
|
800 |
/**
|
801 |
* Ajax Hide Cache Notice shown on staging site
|
|
|
802 |
*/
|
803 |
public function ajaxHideCacheNotice()
|
804 |
{
|
805 |
+
// @todo inject with dependency injection
|
806 |
if ((new DisabledCacheNotice())->disable() !== false) {
|
807 |
wp_send_json(true);
|
808 |
}
|
809 |
+
|
810 |
+
wp_send_json(null);
|
811 |
}
|
812 |
|
813 |
/**
|
815 |
*/
|
816 |
public function ajaxLogs()
|
817 |
{
|
818 |
+
if (!$this->isAuthenticated()) {
|
819 |
+
return;
|
820 |
}
|
821 |
|
822 |
+
wp_send_json((new Logs)->start());
|
|
|
823 |
}
|
824 |
|
825 |
/**
|
827 |
*/
|
828 |
public function ajaxCheckFreeSpace()
|
829 |
{
|
830 |
+
if (!$this->isAuthenticated()) {
|
831 |
return false;
|
832 |
}
|
833 |
|
840 |
*/
|
841 |
public function ajaxEditCloneData()
|
842 |
{
|
843 |
+
if (!$this->isAuthenticated()) {
|
844 |
+
return;
|
845 |
}
|
846 |
|
847 |
$listOfClones = get_option("wpstg_existing_clones_beta", []);
|
860 |
*/
|
861 |
public function ajaxSaveCloneData()
|
862 |
{
|
863 |
+
if (!$this->isAuthenticated()) {
|
864 |
+
return;
|
865 |
}
|
866 |
|
867 |
$listOfClones = get_option("wpstg_existing_clones_beta", []);
|
872 |
}
|
873 |
|
874 |
// Use directory name as new array key to maintain existing structure
|
875 |
+
$keys = array_keys($listOfClones);
|
876 |
$keys[array_search($_POST["clone"], $keys)] = $_POST["directoryName"];
|
877 |
+
$listOfClones = array_combine($keys, $listOfClones);
|
878 |
|
879 |
$cloneId = $_POST["directoryName"];
|
880 |
|
881 |
+
$listOfClones[$cloneId]["directoryName"] = stripslashes($_POST["directoryName"]);
|
882 |
+
$listOfClones[$cloneId]["path"] = stripslashes($_POST["path"]);
|
883 |
+
$listOfClones[$cloneId]["url"] = stripslashes($_POST["url"]);
|
884 |
+
$listOfClones[$cloneId]["prefix"] = stripslashes($_POST["prefix"]);
|
885 |
+
$listOfClones[$cloneId]["databaseUser"] = stripslashes($_POST["externalDBUser"]);
|
886 |
$listOfClones[$cloneId]["databasePassword"] = stripslashes($_POST["externalDBPassword"]);
|
887 |
$listOfClones[$cloneId]["databaseDatabase"] = stripslashes($_POST["externalDBDatabase"]);
|
888 |
+
$listOfClones[$cloneId]["databaseServer"] = stripslashes($_POST["externalDBHost"]);
|
889 |
+
$listOfClones[$cloneId]["databasePrefix"] = stripslashes($_POST["externalDBPrefix"]);
|
890 |
|
891 |
update_option("wpstg_existing_clones_beta", $listOfClones);
|
892 |
|
906 |
*/
|
907 |
public function ajaxPushScan()
|
908 |
{
|
909 |
+
if (!$this->isAuthenticated()) {
|
910 |
return false;
|
911 |
}
|
912 |
|
932 |
*/
|
933 |
public function ajaxPushProcessing()
|
934 |
{
|
935 |
+
if (!$this->isAuthenticated()) {
|
936 |
return false;
|
937 |
}
|
938 |
|
941 |
}
|
942 |
|
943 |
// Start the process
|
944 |
+
wp_send_json((new Processing)->start());
|
|
|
945 |
}
|
946 |
|
947 |
/**
|
949 |
*/
|
950 |
public function getLicensePage()
|
951 |
{
|
|
|
952 |
// Get license data
|
953 |
$license = get_option('wpstg_license_status');
|
954 |
|
961 |
*/
|
962 |
public function ajaxSendReport($args = [])
|
963 |
{
|
964 |
+
if (!$this->isAuthenticated()) {
|
965 |
+
return;
|
966 |
}
|
967 |
|
968 |
// Set params
|
1015 |
public function ajaxDatabaseConnect()
|
1016 |
{
|
1017 |
if (!$this->isAuthenticated()) {
|
1018 |
+
return;
|
1019 |
}
|
1020 |
|
1021 |
$args = $_POST;
|
1023 |
$password = !empty($args['databasePassword']) ? $args['databasePassword'] : '';
|
1024 |
$database = !empty($args['databaseDatabase']) ? $args['databaseDatabase'] : '';
|
1025 |
$server = !empty($args['databaseServer']) ? $args['databaseServer'] : 'localhost';
|
1026 |
+
$prefix = !empty($args['databasePrefix']) ? $args['databasePrefix'] : 'wp_';
|
1027 |
|
1028 |
$dbInfo = new DbInfo($server, $user, stripslashes($password), $database);
|
1029 |
+
$wpdb = $dbInfo->connect();
|
1030 |
$error = $dbInfo->getError();
|
1031 |
+
|
1032 |
// Can not connect to mysql database
|
1033 |
if ($error !== null) {
|
1034 |
echo json_encode(['success' => 'false', 'errors' => $error]);
|
1035 |
exit;
|
1036 |
}
|
1037 |
|
1038 |
+
// Check if any table with provided prefix already exist
|
1039 |
+
$existingTables = $wpdb->get_var($wpdb->prepare("SHOW TABLES LIKE %s", $prefix . '%'));
|
1040 |
+
if ($existingTables !== null) {
|
1041 |
+
echo json_encode(['success' => 'false', 'errors' => 'Tables with prefix ' . $prefix . ' already exist in database. Select another prefix.']);
|
1042 |
+
exit;
|
1043 |
+
}
|
1044 |
+
|
1045 |
echo json_encode(['success' => 'true']);
|
1046 |
exit;
|
1047 |
}
|
1052 |
public function ajaxDatabaseVerification()
|
1053 |
{
|
1054 |
if (!$this->isAuthenticated()) {
|
1055 |
+
return;
|
1056 |
}
|
1057 |
|
1058 |
if (!$this->isPro()) {
|
1059 |
+
return;
|
1060 |
}
|
1061 |
|
1062 |
$user = !empty($_POST['databaseUser']) ? $_POST['databaseUser'] : '';
|
Backend/Modules/Jobs/Cleaners/WpContentCleaner.php
ADDED
@@ -0,0 +1,136 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Backend\Modules\Jobs\Cleaners;
|
4 |
+
|
5 |
+
use WPStaging\Backend\Modules\Jobs\Files;
|
6 |
+
use WPStaging\Framework\Utils\WpDefaultDirectories;
|
7 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
8 |
+
use WPStaging\Core\Utils\Logger;
|
9 |
+
|
10 |
+
/**
|
11 |
+
* This class is used to delete all uploads, themes and plugins
|
12 |
+
* Currently it is used during push process
|
13 |
+
* It will delete uploads, themes and plugins according to the options user selected.
|
14 |
+
*/
|
15 |
+
class WpContentCleaner
|
16 |
+
{
|
17 |
+
/**
|
18 |
+
* @var array
|
19 |
+
*/
|
20 |
+
private $logs = [];
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @var Object
|
24 |
+
*/
|
25 |
+
private $job;
|
26 |
+
|
27 |
+
/**
|
28 |
+
* @param Files $job
|
29 |
+
*/
|
30 |
+
public function __construct($job)
|
31 |
+
{
|
32 |
+
$this->job = $job;
|
33 |
+
}
|
34 |
+
|
35 |
+
/**
|
36 |
+
* Return logs of this cleaning process
|
37 |
+
* @return array
|
38 |
+
*/
|
39 |
+
public function getLogs()
|
40 |
+
{
|
41 |
+
return $this->logs;
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Remove Plugins/Themes/Uploads according to option selected
|
46 |
+
* $directory param used in this method is mainly for mocking purpose but,
|
47 |
+
* can also be used to give path of staging site
|
48 |
+
* @param string $directory Root directory of target WordPress Installation
|
49 |
+
* @return bool
|
50 |
+
*
|
51 |
+
* @todo update for clone when clone is network after merging that PR
|
52 |
+
*/
|
53 |
+
public function tryCleanWpContent($directory)
|
54 |
+
{
|
55 |
+
$options = $this->job->getOptions();
|
56 |
+
|
57 |
+
if ($options->statusContentCleaner === 'finished' || $options->statusContentCleaner === 'skipped') {
|
58 |
+
return true;
|
59 |
+
}
|
60 |
+
|
61 |
+
// Skip cleaning if staging site is broken and not complete
|
62 |
+
if (!is_dir($directory)) {
|
63 |
+
return true;
|
64 |
+
}
|
65 |
+
|
66 |
+
$wpDirectories = new WpDefaultDirectories();
|
67 |
+
$directory = trailingslashit($directory);
|
68 |
+
$paths = [];
|
69 |
+
if ($options->deleteUploadsFolder && !$options->backupUploadsFolder && $options->statusContentCleaner = 'pending') {
|
70 |
+
$paths[] = trailingslashit($directory . $wpDirectories->getRelativeUploadPath());
|
71 |
+
}
|
72 |
+
|
73 |
+
if ($options->deletePluginsAndThemes) {
|
74 |
+
$paths[] = trailingslashit($directory . $wpDirectories->getRelativeThemePath());
|
75 |
+
$paths[] = trailingslashit($directory . $wpDirectories->getRelativePluginPath());
|
76 |
+
}
|
77 |
+
|
78 |
+
if (count($paths) === 0) {
|
79 |
+
$options->statusContentCleaner = 'skipped';
|
80 |
+
$this->job->saveOptions($options);
|
81 |
+
return true;
|
82 |
+
}
|
83 |
+
|
84 |
+
if ($options->statusContentCleaner === 'pending') {
|
85 |
+
$this->logs[] = [
|
86 |
+
"msg" => __("Files: Cleaning up directories: Plugins, Themes, Uploads!", "wp-staging"),
|
87 |
+
"type" => Logger::TYPE_INFO
|
88 |
+
];
|
89 |
+
|
90 |
+
$options->statusContentCleaner = 'cleaning';
|
91 |
+
$this->job->saveOptions($options);
|
92 |
+
}
|
93 |
+
|
94 |
+
$excludePaths = [
|
95 |
+
"wp-staging",
|
96 |
+
"wp-staging-1",
|
97 |
+
"wp-staging-pro",
|
98 |
+
"wp-staging-pro-1",
|
99 |
+
"wp-staging-dev",
|
100 |
+
'cache',
|
101 |
+
'wps-hide-login',
|
102 |
+
'wp-staging-hooks',
|
103 |
+
];
|
104 |
+
$fs = (new Filesystem())
|
105 |
+
->setShouldStop([$this->job, 'isOverThreshold'])
|
106 |
+
->setExcludePaths($excludePaths)
|
107 |
+
->setRecursive();
|
108 |
+
try {
|
109 |
+
if (!$fs->deletePaths($paths)) {
|
110 |
+
return false;
|
111 |
+
}
|
112 |
+
} catch (\RuntimeException $ex) {
|
113 |
+
$this->logs[] = [
|
114 |
+
"msg" => sprintf(__("Files: Error - %s. Content cleaning.", "wp-staging"), $ex->getMessage()),
|
115 |
+
"type" => Logger::TYPE_ERROR
|
116 |
+
];
|
117 |
+
return false;
|
118 |
+
}
|
119 |
+
|
120 |
+
$options->statusContentCleaner = 'finished';
|
121 |
+
$this->job->saveOptions($options);
|
122 |
+
if (!$options->deletePluginsAndThemes) {
|
123 |
+
$this->logs[] = [
|
124 |
+
"msg" => __("Files: Skipped cleaning Plugins and Themes directories!", "wp-staging"),
|
125 |
+
"type" => Logger::TYPE_INFO
|
126 |
+
];
|
127 |
+
}
|
128 |
+
|
129 |
+
$this->logs[] = [
|
130 |
+
"msg" => __("Files: Finished cleaning!", "wp-staging"),
|
131 |
+
"type" => Logger::TYPE_INFO
|
132 |
+
];
|
133 |
+
|
134 |
+
return true;
|
135 |
+
}
|
136 |
+
}
|
Backend/Modules/Jobs/Cloning.php
CHANGED
@@ -168,7 +168,12 @@ class Cloning extends Job
|
|
168 |
$this->options->cloneHostname = trim($_POST["cloneHostname"]);
|
169 |
}
|
170 |
|
171 |
-
|
|
|
|
|
|
|
|
|
|
|
172 |
|
173 |
$this->options->destinationHostname = $this->getDestinationHostname();
|
174 |
$this->options->destinationDir = $this->getDestinationDir();
|
@@ -179,6 +184,9 @@ class Cloning extends Job
|
|
179 |
// Process lock state
|
180 |
$this->options->isRunning = true;
|
181 |
|
|
|
|
|
|
|
182 |
// Save Clone data
|
183 |
$this->saveClone();
|
184 |
|
@@ -216,8 +224,9 @@ class Cloning extends Job
|
|
216 |
"databaseDatabase" => $this->options->databaseDatabase,
|
217 |
"databaseServer" => $this->options->databaseServer,
|
218 |
"databasePrefix" => $this->options->databasePrefix,
|
219 |
-
"
|
220 |
-
"uploadsSymlinked" => (bool)$this->options->uploadsSymlinked
|
|
|
221 |
];
|
222 |
|
223 |
if (update_option("wpstg_existing_clones_beta", $this->options->existingClones) === false) {
|
168 |
$this->options->cloneHostname = trim($_POST["cloneHostname"]);
|
169 |
}
|
170 |
|
171 |
+
// Make sure it is always enabled for free version
|
172 |
+
$this->options->emailsAllowed = true;
|
173 |
+
if (defined('WPSTGPRO_VERSION')) {
|
174 |
+
$this->options->emailsAllowed = apply_filters('wpstg_cloning_email_allowed',
|
175 |
+
isset($_POST['emailsAllowed']) && $_POST['emailsAllowed'] !== "false");
|
176 |
+
}
|
177 |
|
178 |
$this->options->destinationHostname = $this->getDestinationHostname();
|
179 |
$this->options->destinationDir = $this->getDestinationDir();
|
184 |
// Process lock state
|
185 |
$this->options->isRunning = true;
|
186 |
|
187 |
+
// id of the user creating the clone
|
188 |
+
$this->options->ownerId = get_current_user_id();
|
189 |
+
|
190 |
// Save Clone data
|
191 |
$this->saveClone();
|
192 |
|
224 |
"databaseDatabase" => $this->options->databaseDatabase,
|
225 |
"databaseServer" => $this->options->databaseServer,
|
226 |
"databasePrefix" => $this->options->databasePrefix,
|
227 |
+
"emailsAllowed" => (bool)$this->options->emailsAllowed,
|
228 |
+
"uploadsSymlinked" => (bool)$this->options->uploadsSymlinked,
|
229 |
+
"ownerId" => $this->options->ownerId,
|
230 |
];
|
231 |
|
232 |
if (update_option("wpstg_existing_clones_beta", $this->options->existingClones) === false) {
|
Backend/Modules/Jobs/Database.php
CHANGED
@@ -104,7 +104,7 @@ class Database extends CloningProcess
|
|
104 |
* @param string $name
|
105 |
* @return bool
|
106 |
*/
|
107 |
-
private function
|
108 |
{
|
109 |
$old = $this->stagingDb->get_var($this->stagingDb->prepare("SHOW TABLES LIKE %s", $name));
|
110 |
return (
|
@@ -115,6 +115,16 @@ class Database extends CloningProcess
|
|
115 |
);
|
116 |
}
|
117 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
118 |
/**
|
119 |
* Finish the step
|
120 |
*/
|
@@ -193,7 +203,12 @@ class Database extends CloningProcess
|
|
193 |
}
|
194 |
}
|
195 |
|
196 |
-
if ($this->
|
|
|
|
|
|
|
|
|
|
|
197 |
$this->databaseCloningService->dropTable($newTableName);
|
198 |
}
|
199 |
|
104 |
* @param string $name
|
105 |
* @return bool
|
106 |
*/
|
107 |
+
private function isTableExist($name)
|
108 |
{
|
109 |
$old = $this->stagingDb->get_var($this->stagingDb->prepare("SHOW TABLES LIKE %s", $name));
|
110 |
return (
|
115 |
);
|
116 |
}
|
117 |
|
118 |
+
/**
|
119 |
+
* Check if table already exists and the main job is not updating
|
120 |
+
* @param string $name
|
121 |
+
* @return bool
|
122 |
+
*/
|
123 |
+
private function shouldAbortIfTableExist($name)
|
124 |
+
{
|
125 |
+
return isset($this->options->mainJob) && $this->options->mainJob !== 'updating' && $this->isTableExist($name);
|
126 |
+
}
|
127 |
+
|
128 |
/**
|
129 |
* Finish the step
|
130 |
*/
|
203 |
}
|
204 |
}
|
205 |
|
206 |
+
if ($this->shouldAbortIfTableExist($newTableName)) {
|
207 |
+
$this->returnException(sprintf(__("Can not proceed. Tables beginning with the prefix '%s' already exist in the database. Choose another table prefix and try again.", "wp-staging"), $this->getStagingPrefix()));
|
208 |
+
return true;
|
209 |
+
}
|
210 |
+
|
211 |
+
if ($this->isTableExist($newTableName)) {
|
212 |
$this->databaseCloningService->dropTable($newTableName);
|
213 |
}
|
214 |
|
Backend/Modules/Jobs/Delete.php
CHANGED
@@ -390,23 +390,30 @@ class Delete extends Job {
|
|
390 |
return;
|
391 |
}
|
392 |
|
|
|
|
|
|
|
393 |
if ($this->isNotEmpty($this->deleteDir)) {
|
394 |
$fs = (new Filesystem())
|
395 |
->setShouldStop([$this, 'isOverThreshold'])
|
396 |
->setRecursive();
|
397 |
-
|
398 |
-
|
|
|
|
|
|
|
|
|
|
|
399 |
}
|
400 |
}
|
401 |
|
402 |
// Throw fatal error if the folder has still not been deleted and there are files in it
|
403 |
if ($this->isNotEmpty($this->deleteDir)) {
|
404 |
-
$clone = (string) $this->clone->path;
|
405 |
$response = [
|
406 |
'job' => 'delete',
|
407 |
'status' => true,
|
408 |
-
'delete' =>
|
409 |
-
'message' =>
|
410 |
'error' => true,
|
411 |
];
|
412 |
wp_die(json_encode($response));
|
390 |
return;
|
391 |
}
|
392 |
|
393 |
+
$clone = (string)$this->clone->path;
|
394 |
+
$errorMessage = __(sprintf("Could not delete the entire staging site. The folder %s still exists and is not empty. <br/> Try to empty this folder manually by using FTP or file manager plugin and then try to delete again the staging site here.<br/> If this happens again please contact us at support@wp-staging.com", $clone), "wp-staging");
|
395 |
+
$deleteStatus = "finished";
|
396 |
if ($this->isNotEmpty($this->deleteDir)) {
|
397 |
$fs = (new Filesystem())
|
398 |
->setShouldStop([$this, 'isOverThreshold'])
|
399 |
->setRecursive();
|
400 |
+
try {
|
401 |
+
if (!$fs->deleteNew($this->deleteDir)) {
|
402 |
+
return;
|
403 |
+
}
|
404 |
+
} catch (\RuntimeException $ex) {
|
405 |
+
$errorMessage = $ex->getMessage();
|
406 |
+
$deleteStatus = "unfinished";
|
407 |
}
|
408 |
}
|
409 |
|
410 |
// Throw fatal error if the folder has still not been deleted and there are files in it
|
411 |
if ($this->isNotEmpty($this->deleteDir)) {
|
|
|
412 |
$response = [
|
413 |
'job' => 'delete',
|
414 |
'status' => true,
|
415 |
+
'delete' => $deleteStatus,
|
416 |
+
'message' => $errorMessage,
|
417 |
'error' => true,
|
418 |
];
|
419 |
wp_die(json_encode($response));
|
Backend/Modules/Jobs/Files.php
CHANGED
@@ -3,11 +3,13 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
use SplFileObject;
|
6 |
-
use WPStaging\
|
7 |
use WPStaging\Core\Utils\Logger;
|
|
|
|
|
|
|
8 |
use WPStaging\Framework\Filesystem\WpUploadsFolderSymlinker;
|
9 |
use WPStaging\Framework\Utils\WpDefaultDirectories;
|
10 |
-
|
11 |
/**
|
12 |
* Class Files
|
13 |
*
|
@@ -37,11 +39,19 @@ class Files extends JobExecutable
|
|
37 |
*/
|
38 |
private $destination;
|
39 |
|
|
|
|
|
|
|
|
|
|
|
40 |
/**
|
41 |
* Initialization
|
42 |
*/
|
43 |
public function initialize()
|
44 |
{
|
|
|
|
|
|
|
45 |
$this->destination = $this->options->destinationDir;
|
46 |
|
47 |
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
@@ -51,13 +61,12 @@ class Files extends JobExecutable
|
|
51 |
}
|
52 |
|
53 |
// Informational logs
|
54 |
-
if ($this->options->currentStep
|
55 |
$this->log("Copying files...");
|
56 |
}
|
57 |
|
58 |
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
59 |
$this->maxFilesPerRun = $this->settings->fileLimit;
|
60 |
-
//$this->maxFilesPerRun = ($this->settings->cpuLoad === 'low') ? 50 : 1;
|
61 |
}
|
62 |
|
63 |
/**
|
@@ -67,6 +76,8 @@ class Files extends JobExecutable
|
|
67 |
protected function calculateTotalSteps()
|
68 |
{
|
69 |
$this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
|
|
|
|
|
70 |
}
|
71 |
|
72 |
/**
|
@@ -84,6 +95,12 @@ class Files extends JobExecutable
|
|
84 |
return false;
|
85 |
}
|
86 |
|
|
|
|
|
|
|
|
|
|
|
|
|
87 |
// Get files and copy'em
|
88 |
if (!$this->getFilesAndCopy()) {
|
89 |
$this->prepareResponse(false, false);
|
@@ -97,12 +114,50 @@ class Files extends JobExecutable
|
|
97 |
return true;
|
98 |
}
|
99 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
100 |
/**
|
101 |
* Get files and copy
|
102 |
* @return bool
|
103 |
*/
|
104 |
private function getFilesAndCopy()
|
105 |
{
|
|
|
|
|
|
|
|
|
|
|
106 |
// Over limits threshold
|
107 |
if ($this->isOverThreshold()) {
|
108 |
// Prepare response and save current progress
|
@@ -112,7 +167,6 @@ class Files extends JobExecutable
|
|
112 |
}
|
113 |
|
114 |
// Go to last copied line and than to next one
|
115 |
-
//if ($this->options->copiedFiles != 0) {
|
116 |
if (isset($this->options->copiedFiles) && $this->options->copiedFiles != 0) {
|
117 |
$this->file->seek($this->options->copiedFiles - 1);
|
118 |
}
|
@@ -151,6 +205,11 @@ class Files extends JobExecutable
|
|
151 |
*/
|
152 |
private function symlinkUploadFolder()
|
153 |
{
|
|
|
|
|
|
|
|
|
|
|
154 |
if (!$this->options->uploadsSymlinked) {
|
155 |
$this->log("Skipped symlinking Wp Uploads Folder");
|
156 |
return true;
|
@@ -184,7 +243,7 @@ class Files extends JobExecutable
|
|
184 |
*/
|
185 |
private function copyFile($file)
|
186 |
{
|
187 |
-
$file = trim(
|
188 |
|
189 |
$file = wpstg_replace_windows_directory_separator($file);
|
190 |
|
@@ -247,7 +306,7 @@ class Files extends JobExecutable
|
|
247 |
}
|
248 |
|
249 |
// Set file permissions
|
250 |
-
@chmod($destination,
|
251 |
|
252 |
$this->setDirPermissions($destination);
|
253 |
|
@@ -289,14 +348,14 @@ class Files extends JobExecutable
|
|
289 |
|
290 |
/**
|
291 |
* Set directory permissions
|
292 |
-
* @param
|
293 |
* @return boolean
|
294 |
*/
|
295 |
private function setDirPermissions($file)
|
296 |
{
|
297 |
$dir = dirname($file);
|
298 |
if (is_dir($dir)) {
|
299 |
-
@chmod($dir,
|
300 |
}
|
301 |
return false;
|
302 |
}
|
@@ -310,12 +369,12 @@ class Files extends JobExecutable
|
|
310 |
private function getDestination($file)
|
311 |
{
|
312 |
$file = wpstg_replace_windows_directory_separator($file);
|
313 |
-
$rootPath = wpstg_replace_windows_directory_separator(
|
314 |
$relativePath = str_replace($rootPath, null, $file);
|
315 |
$destinationPath = $this->destination . $relativePath;
|
316 |
$destinationDirectory = dirname($destinationPath);
|
317 |
|
318 |
-
if (!is_dir($destinationDirectory) && !mkdir($destinationDirectory
|
319 |
$this->log("Files: Can not create directory {$destinationDirectory}. Possible write permission error!", Logger::TYPE_ERROR);
|
320 |
return false;
|
321 |
}
|
@@ -332,8 +391,8 @@ class Files extends JobExecutable
|
|
332 |
*/
|
333 |
private function copyBig($src, $dst, $buffersize)
|
334 |
{
|
335 |
-
$src = fopen($src, '
|
336 |
-
$dest = fopen($dst, '
|
337 |
|
338 |
if (!$src || !$dest) {
|
339 |
return false;
|
@@ -380,13 +439,13 @@ class Files extends JobExecutable
|
|
380 |
);
|
381 |
}
|
382 |
|
383 |
-
if ((new
|
384 |
return true;
|
385 |
}
|
386 |
|
387 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
388 |
// because if the updating process fails, the staging site would not be accessable any longer
|
389 |
-
if (isset($this->options->mainJob) && $this->options->mainJob
|
390 |
&& stripos(strrev($file), strrev("wp-config.php")) === 0) {
|
391 |
return true;
|
392 |
}
|
3 |
namespace WPStaging\Backend\Modules\Jobs;
|
4 |
|
5 |
use SplFileObject;
|
6 |
+
use WPStaging\Backend\Modules\Jobs\Cleaners\WpContentCleaner;
|
7 |
use WPStaging\Core\Utils\Logger;
|
8 |
+
use WPStaging\Core\WPStaging;
|
9 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
10 |
+
use WPStaging\Framework\Filesystem\Permissions;
|
11 |
use WPStaging\Framework\Filesystem\WpUploadsFolderSymlinker;
|
12 |
use WPStaging\Framework\Utils\WpDefaultDirectories;
|
|
|
13 |
/**
|
14 |
* Class Files
|
15 |
*
|
39 |
*/
|
40 |
private $destination;
|
41 |
|
42 |
+
/**
|
43 |
+
* @var Permissions
|
44 |
+
*/
|
45 |
+
private $permissions;
|
46 |
+
|
47 |
/**
|
48 |
* Initialization
|
49 |
*/
|
50 |
public function initialize()
|
51 |
{
|
52 |
+
|
53 |
+
$this->permissions = new Permissions();
|
54 |
+
|
55 |
$this->destination = $this->options->destinationDir;
|
56 |
|
57 |
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
61 |
}
|
62 |
|
63 |
// Informational logs
|
64 |
+
if ($this->options->currentStep === 1) {
|
65 |
$this->log("Copying files...");
|
66 |
}
|
67 |
|
68 |
$this->settings->batchSize = $this->settings->batchSize * 1000000;
|
69 |
$this->maxFilesPerRun = $this->settings->fileLimit;
|
|
|
70 |
}
|
71 |
|
72 |
/**
|
76 |
protected function calculateTotalSteps()
|
77 |
{
|
78 |
$this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
|
79 |
+
// Add an extra step for cleaning content in themes, plugins and uploads dir
|
80 |
+
$this->options->totalSteps++;
|
81 |
}
|
82 |
|
83 |
/**
|
95 |
return false;
|
96 |
}
|
97 |
|
98 |
+
// Cleaning wp-content directories: uploads, themes and plugins
|
99 |
+
if (!$this->cleanWpContent()) {
|
100 |
+
$this->prepareResponse(false, false);
|
101 |
+
return false;
|
102 |
+
}
|
103 |
+
|
104 |
// Get files and copy'em
|
105 |
if (!$this->getFilesAndCopy()) {
|
106 |
$this->prepareResponse(false, false);
|
114 |
return true;
|
115 |
}
|
116 |
|
117 |
+
/**
|
118 |
+
* @return bool
|
119 |
+
*/
|
120 |
+
private function cleanWpContent()
|
121 |
+
{
|
122 |
+
if ($this->options->mainJob !== 'updating') {
|
123 |
+
return true;
|
124 |
+
}
|
125 |
+
|
126 |
+
if ($this->options->currentStep !== 0) {
|
127 |
+
return true;
|
128 |
+
}
|
129 |
+
|
130 |
+
// @todo inject using DI if possible
|
131 |
+
$contentCleaner = new WpContentCleaner($this);
|
132 |
+
|
133 |
+
$result = $contentCleaner->tryCleanWpContent($this->destination);
|
134 |
+
foreach ($contentCleaner->getLogs() as $log) {
|
135 |
+
if ($log['type'] === Logger::TYPE_ERROR) {
|
136 |
+
$this->log($log['msg'], $log['type']);
|
137 |
+
$this->returnException($log['msg']);
|
138 |
+
} else {
|
139 |
+
$this->log($log['msg'], $log['type']);
|
140 |
+
}
|
141 |
+
}
|
142 |
+
|
143 |
+
if (!$result) {
|
144 |
+
return false;
|
145 |
+
}
|
146 |
+
|
147 |
+
return true;
|
148 |
+
}
|
149 |
+
|
150 |
/**
|
151 |
* Get files and copy
|
152 |
* @return bool
|
153 |
*/
|
154 |
private function getFilesAndCopy()
|
155 |
{
|
156 |
+
// dont do this step if step is 0
|
157 |
+
if ($this->options->currentStep === 0) {
|
158 |
+
return true;
|
159 |
+
}
|
160 |
+
|
161 |
// Over limits threshold
|
162 |
if ($this->isOverThreshold()) {
|
163 |
// Prepare response and save current progress
|
167 |
}
|
168 |
|
169 |
// Go to last copied line and than to next one
|
|
|
170 |
if (isset($this->options->copiedFiles) && $this->options->copiedFiles != 0) {
|
171 |
$this->file->seek($this->options->copiedFiles - 1);
|
172 |
}
|
205 |
*/
|
206 |
private function symlinkUploadFolder()
|
207 |
{
|
208 |
+
// Don't symlink if the site is updated because the folder or symlink already exists
|
209 |
+
if ($this->options->mainJob === 'updating') {
|
210 |
+
return true;
|
211 |
+
}
|
212 |
+
|
213 |
if (!$this->options->uploadsSymlinked) {
|
214 |
$this->log("Skipped symlinking Wp Uploads Folder");
|
215 |
return true;
|
243 |
*/
|
244 |
private function copyFile($file)
|
245 |
{
|
246 |
+
$file = trim(WPStaging::getWPpath() . $file);
|
247 |
|
248 |
$file = wpstg_replace_windows_directory_separator($file);
|
249 |
|
306 |
}
|
307 |
|
308 |
// Set file permissions
|
309 |
+
@chmod($destination, $this->permissions->getFilesOctal());
|
310 |
|
311 |
$this->setDirPermissions($destination);
|
312 |
|
348 |
|
349 |
/**
|
350 |
* Set directory permissions
|
351 |
+
* @param string $file
|
352 |
* @return boolean
|
353 |
*/
|
354 |
private function setDirPermissions($file)
|
355 |
{
|
356 |
$dir = dirname($file);
|
357 |
if (is_dir($dir)) {
|
358 |
+
@chmod($dir, $this->permissions->getDirectoryOctal());
|
359 |
}
|
360 |
return false;
|
361 |
}
|
369 |
private function getDestination($file)
|
370 |
{
|
371 |
$file = wpstg_replace_windows_directory_separator($file);
|
372 |
+
$rootPath = wpstg_replace_windows_directory_separator(WPStaging::getWPpath());
|
373 |
$relativePath = str_replace($rootPath, null, $file);
|
374 |
$destinationPath = $this->destination . $relativePath;
|
375 |
$destinationDirectory = dirname($destinationPath);
|
376 |
|
377 |
+
if (!is_dir($destinationDirectory) && !(new Filesystem)->mkdir($destinationDirectory) && !is_dir($destinationDirectory)) {
|
378 |
$this->log("Files: Can not create directory {$destinationDirectory}. Possible write permission error!", Logger::TYPE_ERROR);
|
379 |
return false;
|
380 |
}
|
391 |
*/
|
392 |
private function copyBig($src, $dst, $buffersize)
|
393 |
{
|
394 |
+
$src = fopen($src, 'rb');
|
395 |
+
$dest = fopen($dst, 'wb');
|
396 |
|
397 |
if (!$src || !$dest) {
|
398 |
return false;
|
439 |
);
|
440 |
}
|
441 |
|
442 |
+
if ((new Filesystem)->isFilenameExcluded($file, $excludedFiles)) {
|
443 |
return true;
|
444 |
}
|
445 |
|
446 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
447 |
// because if the updating process fails, the staging site would not be accessable any longer
|
448 |
+
if (isset($this->options->mainJob) && $this->options->mainJob === "updating"
|
449 |
&& stripos(strrev($file), strrev("wp-config.php")) === 0) {
|
450 |
return true;
|
451 |
}
|
Backend/Modules/Jobs/Finish.php
CHANGED
@@ -80,7 +80,7 @@ class Finish extends Job {
|
|
80 |
$this->options->existingClones[$this->options->clone]['datetime'] = time();
|
81 |
$this->options->existingClones[$this->options->clone]['status'] = 'finished';
|
82 |
$this->options->existingClones[$this->options->clone]['prefix'] = $this->options->prefix;
|
83 |
-
$this->options->existingClones[$this->options->clone]['
|
84 |
$this->options->existingClones[$this->options->clone]['uploadsSymlinked'] = (bool) $this->options->uploadsSymlinked;
|
85 |
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
86 |
$this->log( "Finish: The job finished!" );
|
@@ -108,7 +108,7 @@ class Finish extends Job {
|
|
108 |
"databaseDatabase" => $this->options->databaseDatabase,
|
109 |
"databaseServer" => $this->options->databaseServer,
|
110 |
"databasePrefix" => $this->options->databasePrefix,
|
111 |
-
"
|
112 |
"uploadsSymlinked" => (bool) $this->options->uploadsSymlinked
|
113 |
];
|
114 |
|
80 |
$this->options->existingClones[$this->options->clone]['datetime'] = time();
|
81 |
$this->options->existingClones[$this->options->clone]['status'] = 'finished';
|
82 |
$this->options->existingClones[$this->options->clone]['prefix'] = $this->options->prefix;
|
83 |
+
$this->options->existingClones[$this->options->clone]['emailsAllowed'] = (bool) $this->options->emailsAllowed;
|
84 |
$this->options->existingClones[$this->options->clone]['uploadsSymlinked'] = (bool) $this->options->uploadsSymlinked;
|
85 |
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
86 |
$this->log( "Finish: The job finished!" );
|
108 |
"databaseDatabase" => $this->options->databaseDatabase,
|
109 |
"databaseServer" => $this->options->databaseServer,
|
110 |
"databasePrefix" => $this->options->databasePrefix,
|
111 |
+
"emailsAllowed" => (bool) $this->options->emailsAllowed,
|
112 |
"uploadsSymlinked" => (bool) $this->options->uploadsSymlinked
|
113 |
];
|
114 |
|
Backend/Modules/Jobs/Job.php
CHANGED
@@ -186,7 +186,13 @@ abstract class Job implements JobInterface
|
|
186 |
public function __destruct()
|
187 |
{
|
188 |
// Commit logs
|
189 |
-
$this->logger
|
|
|
|
|
|
|
|
|
|
|
|
|
190 |
}
|
191 |
|
192 |
/**
|
@@ -238,7 +244,7 @@ abstract class Job implements JobInterface
|
|
238 |
* @param null|array|object $options
|
239 |
* @return bool
|
240 |
*/
|
241 |
-
|
242 |
{
|
243 |
// Get default options
|
244 |
if ($options === null) {
|
186 |
public function __destruct()
|
187 |
{
|
188 |
// Commit logs
|
189 |
+
if ($this->logger instanceof Logger) {
|
190 |
+
$this->logger->commit();
|
191 |
+
} else {
|
192 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
193 |
+
error_log('Tried to commit log, but $this->logger was not a logger. May be a __destruct problem.');
|
194 |
+
}
|
195 |
+
}
|
196 |
}
|
197 |
|
198 |
/**
|
244 |
* @param null|array|object $options
|
245 |
* @return bool
|
246 |
*/
|
247 |
+
public function saveOptions($options = null)
|
248 |
{
|
249 |
// Get default options
|
250 |
if ($options === null) {
|
Backend/Modules/Jobs/Multisite/Files.php
CHANGED
@@ -3,9 +3,12 @@
|
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
6 |
-
use WPStaging\
|
7 |
use WPStaging\Core\Utils\Logger;
|
|
|
|
|
8 |
use WPStaging\Framework\Filesystem\WpUploadsFolderSymlinker;
|
|
|
9 |
|
10 |
/**
|
11 |
* Class Files
|
@@ -31,15 +34,18 @@ class Files extends JobExecutable
|
|
31 |
private $destination;
|
32 |
|
33 |
/**
|
34 |
-
* @var
|
35 |
*/
|
36 |
-
private $
|
|
|
37 |
|
38 |
/**
|
39 |
* Initialization
|
40 |
*/
|
41 |
public function initialize()
|
42 |
{
|
|
|
|
|
43 |
$this->destination = $this->options->destinationDir;
|
44 |
|
45 |
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
@@ -49,7 +55,7 @@ class Files extends JobExecutable
|
|
49 |
}
|
50 |
|
51 |
// Informational logs
|
52 |
-
if ($this->options->currentStep
|
53 |
$this->log("Copying files...");
|
54 |
}
|
55 |
|
@@ -64,6 +70,8 @@ class Files extends JobExecutable
|
|
64 |
protected function calculateTotalSteps()
|
65 |
{
|
66 |
$this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
|
|
|
|
|
67 |
}
|
68 |
|
69 |
/**
|
@@ -81,6 +89,12 @@ class Files extends JobExecutable
|
|
81 |
return false;
|
82 |
}
|
83 |
|
|
|
|
|
|
|
|
|
|
|
|
|
84 |
// Get files and copy'em
|
85 |
if (!$this->getFilesAndCopy()) {
|
86 |
$this->prepareResponse(false, false);
|
@@ -94,12 +108,50 @@ class Files extends JobExecutable
|
|
94 |
return true;
|
95 |
}
|
96 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
/**
|
98 |
* Get files and copy
|
99 |
* @return bool
|
100 |
*/
|
101 |
private function getFilesAndCopy()
|
102 |
{
|
|
|
|
|
|
|
|
|
|
|
103 |
// Over limits threshold
|
104 |
if ($this->isOverThreshold()) {
|
105 |
// Prepare response and save current progress
|
@@ -148,10 +200,8 @@ class Files extends JobExecutable
|
|
148 |
*/
|
149 |
private function symlinkUploadFolder()
|
150 |
{
|
151 |
-
|
152 |
// Don't symlink if the site is updated because the folder or symlink already exists
|
153 |
-
if($this->options->mainJob === 'updating')
|
154 |
-
{
|
155 |
return true;
|
156 |
}
|
157 |
|
@@ -186,7 +236,7 @@ class Files extends JobExecutable
|
|
186 |
*/
|
187 |
private function copyFile($file)
|
188 |
{
|
189 |
-
$file = trim(
|
190 |
|
191 |
$file = wpstg_replace_windows_directory_separator($file);
|
192 |
|
@@ -259,7 +309,7 @@ class Files extends JobExecutable
|
|
259 |
}
|
260 |
|
261 |
// Set file permissions
|
262 |
-
@chmod($destination,
|
263 |
|
264 |
$this->setDirPermissions($destination);
|
265 |
|
@@ -275,7 +325,7 @@ class Files extends JobExecutable
|
|
275 |
{
|
276 |
$dir = dirname($file);
|
277 |
if (is_dir($dir)) {
|
278 |
-
@chmod($dir,
|
279 |
}
|
280 |
return false;
|
281 |
}
|
@@ -289,12 +339,12 @@ class Files extends JobExecutable
|
|
289 |
private function getDestination($file)
|
290 |
{
|
291 |
$file = wpstg_replace_windows_directory_separator($file);
|
292 |
-
$rootPath = wpstg_replace_windows_directory_separator(
|
293 |
$relativePath = str_replace($rootPath, null, $file);
|
294 |
$destinationPath = $this->destination . $relativePath;
|
295 |
$destinationDirectory = dirname($destinationPath);
|
296 |
|
297 |
-
if (!is_dir($destinationDirectory) &&
|
298 |
$this->log(
|
299 |
"Files: Can not create directory {$destinationDirectory}",
|
300 |
Logger::TYPE_ERROR
|
@@ -305,32 +355,6 @@ class Files extends JobExecutable
|
|
305 |
return $this->sanitizeDirectorySeparator($destinationPath);
|
306 |
}
|
307 |
|
308 |
-
/**
|
309 |
-
* Replace relative path of file if its located in multisite upload folder
|
310 |
-
* wp-content/uploads/sites/SITEID or old wordpress structure wp-content/blogs.dir/SITEID/files
|
311 |
-
* @return boolean
|
312 |
-
*/
|
313 |
-
private function getMultisiteUploadFolder($file)
|
314 |
-
{
|
315 |
-
// Check first which method is used
|
316 |
-
$uploads = wp_upload_dir();
|
317 |
-
$basedir = $uploads['basedir'];
|
318 |
-
|
319 |
-
if (strpos($basedir, 'blogs.dir') === false) {
|
320 |
-
// Since WP 3.5
|
321 |
-
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads' . DIRECTORY_SEPARATOR . 'sites' . DIRECTORY_SEPARATOR . get_current_blog_id();
|
322 |
-
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
323 |
-
$uploadsFolder = str_replace($search, $replace, $file);
|
324 |
-
} else {
|
325 |
-
// old blog structure
|
326 |
-
$search = 'wp-content' . DIRECTORY_SEPARATOR . 'blogs.dir' . DIRECTORY_SEPARATOR . get_current_blog_id() . DIRECTORY_SEPARATOR . 'files';
|
327 |
-
$replace = 'wp-content' . DIRECTORY_SEPARATOR . 'uploads';
|
328 |
-
$uploadsFolder = str_replace($search, $replace, $file);
|
329 |
-
}
|
330 |
-
|
331 |
-
return $uploadsFolder;
|
332 |
-
}
|
333 |
-
|
334 |
/**
|
335 |
* Copy bigger files than $this->settings->batchSize
|
336 |
* @param string $src
|
@@ -340,8 +364,8 @@ class Files extends JobExecutable
|
|
340 |
*/
|
341 |
private function copyBig($src, $dst, $buffersize)
|
342 |
{
|
343 |
-
$src = fopen($src, '
|
344 |
-
$dest = fopen($dst, '
|
345 |
|
346 |
if (!$src || !$dest) {
|
347 |
return false;
|
@@ -388,13 +412,13 @@ class Files extends JobExecutable
|
|
388 |
);
|
389 |
}
|
390 |
|
391 |
-
if ((new
|
392 |
return true;
|
393 |
}
|
394 |
|
395 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
396 |
// because if the updating process fails, the staging site would not be accessable any longer
|
397 |
-
if (isset($this->options->mainJob) && $this->options->mainJob
|
398 |
&& stripos(strrev($file), strrev("wp-config.php")) === 0) {
|
399 |
return true;
|
400 |
}
|
3 |
namespace WPStaging\Backend\Modules\Jobs\Multisite;
|
4 |
|
5 |
use WPStaging\Backend\Modules\Jobs\JobExecutable;
|
6 |
+
use WPStaging\Backend\Modules\Jobs\Cleaners\WpContentCleaner;
|
7 |
use WPStaging\Core\Utils\Logger;
|
8 |
+
use WPStaging\Core\WPStaging;
|
9 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
10 |
use WPStaging\Framework\Filesystem\WpUploadsFolderSymlinker;
|
11 |
+
use WPStaging\Framework\Filesystem\Permissions;
|
12 |
|
13 |
/**
|
14 |
* Class Files
|
34 |
private $destination;
|
35 |
|
36 |
/**
|
37 |
+
* @var Permissions
|
38 |
*/
|
39 |
+
private $permissions;
|
40 |
+
|
41 |
|
42 |
/**
|
43 |
* Initialization
|
44 |
*/
|
45 |
public function initialize()
|
46 |
{
|
47 |
+
$this->permissions = new Permissions();
|
48 |
+
|
49 |
$this->destination = $this->options->destinationDir;
|
50 |
|
51 |
$filePath = $this->cache->getCacheDir() . "files_to_copy." . $this->cache->getCacheExtension();
|
55 |
}
|
56 |
|
57 |
// Informational logs
|
58 |
+
if ($this->options->currentStep === 1) {
|
59 |
$this->log("Copying files...");
|
60 |
}
|
61 |
|
70 |
protected function calculateTotalSteps()
|
71 |
{
|
72 |
$this->options->totalSteps = ceil($this->options->totalFiles / $this->maxFilesPerRun);
|
73 |
+
// Add an extra step for cleaning content in themes, plugins and uploads dir
|
74 |
+
$this->options->totalSteps++;
|
75 |
}
|
76 |
|
77 |
/**
|
89 |
return false;
|
90 |
}
|
91 |
|
92 |
+
// Cleaning wp-content directories: uploads, themes and plugins
|
93 |
+
if (!$this->cleanWpContent()) {
|
94 |
+
$this->prepareResponse(false, false);
|
95 |
+
return false;
|
96 |
+
}
|
97 |
+
|
98 |
// Get files and copy'em
|
99 |
if (!$this->getFilesAndCopy()) {
|
100 |
$this->prepareResponse(false, false);
|
108 |
return true;
|
109 |
}
|
110 |
|
111 |
+
/**
|
112 |
+
* @return bool
|
113 |
+
*/
|
114 |
+
private function cleanWpContent()
|
115 |
+
{
|
116 |
+
if ($this->options->mainJob !== 'updating') {
|
117 |
+
return true;
|
118 |
+
}
|
119 |
+
|
120 |
+
if ($this->options->currentStep !== 0) {
|
121 |
+
return true;
|
122 |
+
}
|
123 |
+
|
124 |
+
// @todo inject using DI if possible
|
125 |
+
$contentCleaner = new WpContentCleaner($this);
|
126 |
+
|
127 |
+
$result = $contentCleaner->tryCleanWpContent($this->destination);
|
128 |
+
foreach ($contentCleaner->getLogs() as $log) {
|
129 |
+
if ($log['type'] === Logger::TYPE_ERROR) {
|
130 |
+
$this->log($log['msg'], $log['type']);
|
131 |
+
$this->returnException($log['msg']);
|
132 |
+
} else {
|
133 |
+
$this->debugLog($log['msg'], $log['type']);
|
134 |
+
}
|
135 |
+
}
|
136 |
+
|
137 |
+
if (!$result) {
|
138 |
+
return false;
|
139 |
+
}
|
140 |
+
|
141 |
+
return true;
|
142 |
+
}
|
143 |
+
|
144 |
/**
|
145 |
* Get files and copy
|
146 |
* @return bool
|
147 |
*/
|
148 |
private function getFilesAndCopy()
|
149 |
{
|
150 |
+
// dont do this step if step is 0
|
151 |
+
if ($this->options->currentStep === 0) {
|
152 |
+
return true;
|
153 |
+
}
|
154 |
+
|
155 |
// Over limits threshold
|
156 |
if ($this->isOverThreshold()) {
|
157 |
// Prepare response and save current progress
|
200 |
*/
|
201 |
private function symlinkUploadFolder()
|
202 |
{
|
|
|
203 |
// Don't symlink if the site is updated because the folder or symlink already exists
|
204 |
+
if ($this->options->mainJob === 'updating') {
|
|
|
205 |
return true;
|
206 |
}
|
207 |
|
236 |
*/
|
237 |
private function copyFile($file)
|
238 |
{
|
239 |
+
$file = trim(WPStaging::getWPpath() . $file);
|
240 |
|
241 |
$file = wpstg_replace_windows_directory_separator($file);
|
242 |
|
309 |
}
|
310 |
|
311 |
// Set file permissions
|
312 |
+
@chmod($destination, $this->permissions->getFilesOctal());
|
313 |
|
314 |
$this->setDirPermissions($destination);
|
315 |
|
325 |
{
|
326 |
$dir = dirname($file);
|
327 |
if (is_dir($dir)) {
|
328 |
+
@chmod($dir, $this->permissions->getDirectoryOctal());
|
329 |
}
|
330 |
return false;
|
331 |
}
|
339 |
private function getDestination($file)
|
340 |
{
|
341 |
$file = wpstg_replace_windows_directory_separator($file);
|
342 |
+
$rootPath = wpstg_replace_windows_directory_separator(WPStaging::getWPpath());
|
343 |
$relativePath = str_replace($rootPath, null, $file);
|
344 |
$destinationPath = $this->destination . $relativePath;
|
345 |
$destinationDirectory = dirname($destinationPath);
|
346 |
|
347 |
+
if (!is_dir($destinationDirectory) && !(new Filesystem)->mkdir($destinationDirectory)) {
|
348 |
$this->log(
|
349 |
"Files: Can not create directory {$destinationDirectory}",
|
350 |
Logger::TYPE_ERROR
|
355 |
return $this->sanitizeDirectorySeparator($destinationPath);
|
356 |
}
|
357 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
358 |
/**
|
359 |
* Copy bigger files than $this->settings->batchSize
|
360 |
* @param string $src
|
364 |
*/
|
365 |
private function copyBig($src, $dst, $buffersize)
|
366 |
{
|
367 |
+
$src = fopen($src, 'rb');
|
368 |
+
$dest = fopen($dst, 'wb');
|
369 |
|
370 |
if (!$src || !$dest) {
|
371 |
return false;
|
412 |
);
|
413 |
}
|
414 |
|
415 |
+
if ((new Filesystem)->isFilenameExcluded($file, $excludedFiles)) {
|
416 |
return true;
|
417 |
}
|
418 |
|
419 |
// Do not copy wp-config.php if the clone gets updated. This is for security purposes,
|
420 |
// because if the updating process fails, the staging site would not be accessable any longer
|
421 |
+
if (isset($this->options->mainJob) && $this->options->mainJob === "updating"
|
422 |
&& stripos(strrev($file), strrev("wp-config.php")) === 0) {
|
423 |
return true;
|
424 |
}
|
Backend/Modules/Jobs/Multisite/Finish.php
CHANGED
@@ -80,7 +80,8 @@ class Finish extends Job {
|
|
80 |
$this->options->existingClones[$this->options->clone]['url'] = $this->getDestinationUrl();
|
81 |
$this->options->existingClones[$this->options->clone]['status'] = 'finished';
|
82 |
$this->options->existingClones[$this->options->clone]['prefix'] = $this->options->prefix;
|
83 |
-
$this->options->existingClones[$this->options->clone]['
|
|
|
84 |
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
85 |
$this->log( "Finish: The job finished!" );
|
86 |
return true;
|
@@ -103,8 +104,8 @@ class Finish extends Job {
|
|
103 |
"databaseDatabase" => $this->options->databaseDatabase,
|
104 |
"databaseServer" => $this->options->databaseServer,
|
105 |
"databasePrefix" => $this->options->databasePrefix,
|
106 |
-
"
|
107 |
-
"uploadsSymlinked"
|
108 |
];
|
109 |
|
110 |
if( update_option( "wpstg_existing_clones_beta", $this->options->existingClones ) === false ) {
|
80 |
$this->options->existingClones[$this->options->clone]['url'] = $this->getDestinationUrl();
|
81 |
$this->options->existingClones[$this->options->clone]['status'] = 'finished';
|
82 |
$this->options->existingClones[$this->options->clone]['prefix'] = $this->options->prefix;
|
83 |
+
$this->options->existingClones[$this->options->clone]['emailsAllowed'] = (bool) $this->options->emailsAllowed;
|
84 |
+
$this->options->existingClones[$this->options->clone]['uploadsSymlinked'] = (bool) $this->options->uploadsSymlinked;
|
85 |
update_option( "wpstg_existing_clones_beta", $this->options->existingClones );
|
86 |
$this->log( "Finish: The job finished!" );
|
87 |
return true;
|
104 |
"databaseDatabase" => $this->options->databaseDatabase,
|
105 |
"databaseServer" => $this->options->databaseServer,
|
106 |
"databasePrefix" => $this->options->databasePrefix,
|
107 |
+
"emailsAllowed" => (bool) $this->options->emailsAllowed,
|
108 |
+
"uploadsSymlinked" => (bool)$this->options->uploadsSymlinked
|
109 |
];
|
110 |
|
111 |
if( update_option( "wpstg_existing_clones_beta", $this->options->existingClones ) === false ) {
|
Backend/Modules/Jobs/Updating.php
CHANGED
@@ -119,6 +119,16 @@ class Updating extends Job
|
|
119 |
$excludedDirectories[] = rtrim($wpUploadsFolder, '/\\');
|
120 |
}
|
121 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
122 |
// Excluded Directories
|
123 |
if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"])) {
|
124 |
$this->options->excludedDirectories = wpstg_urldecode($_POST["excludedDirectories"]);
|
@@ -154,7 +164,11 @@ class Updating extends Job
|
|
154 |
|
155 |
$this->options->cloneHostname = $this->options->destinationHostname;
|
156 |
|
157 |
-
|
|
|
|
|
|
|
|
|
158 |
|
159 |
// Directories to Copy
|
160 |
$this->options->directoriesToCopy = array_merge(
|
119 |
$excludedDirectories[] = rtrim($wpUploadsFolder, '/\\');
|
120 |
}
|
121 |
|
122 |
+
// delete uploads folder before copying if uploads is not symlinked
|
123 |
+
$this->options->deleteUploadsFolder = !$this->options->uploadsSymlinked && isset($_POST['cleanUploadsDir']) && $_POST['cleanUploadsDir'] === 'true';
|
124 |
+
// should not backup uploads during update process
|
125 |
+
$this->options->backupUploadsFolder = false;
|
126 |
+
// clean plugins and themes dir before updating
|
127 |
+
$this->options->deletePluginsAndThemes = isset($_POST['cleanPluginsThemes']) && $_POST['cleanPluginsThemes'] === 'true';
|
128 |
+
// set default statuses for backup of uploads dir and cleaning of uploads, themes and plugins dirs
|
129 |
+
$this->options->statusBackupUploadsDir = 'skipped';
|
130 |
+
$this->options->statusContentCleaner = 'pending';
|
131 |
+
|
132 |
// Excluded Directories
|
133 |
if (isset($_POST["excludedDirectories"]) && is_array($_POST["excludedDirectories"])) {
|
134 |
$this->options->excludedDirectories = wpstg_urldecode($_POST["excludedDirectories"]);
|
164 |
|
165 |
$this->options->cloneHostname = $this->options->destinationHostname;
|
166 |
|
167 |
+
// Make sure it is always enabled for free version
|
168 |
+
$this->options->emailsAllowed = true;
|
169 |
+
if (defined('WPSTGPRO_VERSION')) {
|
170 |
+
$this->options->emailsAllowed = isset($_POST['emailsAllowed']) && $_POST['emailsAllowed'] !== "false";
|
171 |
+
}
|
172 |
|
173 |
// Directories to Copy
|
174 |
$this->options->directoriesToCopy = array_merge(
|
Backend/Notices/BooleanNotice.php
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Backend\Notices;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class BooleanNotice
|
7 |
+
*
|
8 |
+
* This class is used to reduce the boilerplate code for boolean notices
|
9 |
+
*
|
10 |
+
* @package WPStaging\Backend\Notices;
|
11 |
+
*/
|
12 |
+
abstract class BooleanNotice
|
13 |
+
{
|
14 |
+
/**
|
15 |
+
* The name of option on which the visibility of this notice is stored in db
|
16 |
+
*
|
17 |
+
* @return string
|
18 |
+
*/
|
19 |
+
abstract function getOptionName();
|
20 |
+
|
21 |
+
/**
|
22 |
+
* Enable the option in database to show this notice
|
23 |
+
*/
|
24 |
+
public function enable()
|
25 |
+
{
|
26 |
+
return add_option($this->getOptionName(), true);
|
27 |
+
}
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Check whether to show this notice or not
|
31 |
+
*
|
32 |
+
* @return bool
|
33 |
+
*/
|
34 |
+
public function isEnabled()
|
35 |
+
{
|
36 |
+
return get_option($this->getOptionName(), false);
|
37 |
+
}
|
38 |
+
|
39 |
+
/**
|
40 |
+
* Delete the option in database to disable showing the notice
|
41 |
+
*
|
42 |
+
* @return bool
|
43 |
+
*/
|
44 |
+
public function disable()
|
45 |
+
{
|
46 |
+
return delete_option($this->getOptionName());
|
47 |
+
}
|
48 |
+
}
|
Backend/Notices/DisabledCacheNotice.php
CHANGED
@@ -9,38 +9,15 @@ namespace WPStaging\Backend\Notices;
|
|
9 |
*
|
10 |
* @package WPStaging\Backend\Notices;
|
11 |
*/
|
12 |
-
class DisabledCacheNotice
|
13 |
{
|
14 |
/**
|
15 |
-
* The option name to
|
16 |
*/
|
17 |
const OPTION_NAME = 'wpstg_disabled_cache_notice';
|
18 |
|
19 |
-
|
20 |
-
* Enable the option in database to show this notice
|
21 |
-
*/
|
22 |
-
public function enable()
|
23 |
-
{
|
24 |
-
return add_option(self::OPTION_NAME, true);
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Check whether to show this notice or not
|
29 |
-
*
|
30 |
-
* @return bool
|
31 |
-
*/
|
32 |
-
public function isEnabled()
|
33 |
-
{
|
34 |
-
return get_option(self::OPTION_NAME, false);
|
35 |
-
}
|
36 |
-
|
37 |
-
/**
|
38 |
-
* Delete the option in database to disable showing the notice
|
39 |
-
*
|
40 |
-
* @return bool
|
41 |
-
*/
|
42 |
-
public function disable()
|
43 |
{
|
44 |
-
return
|
45 |
}
|
46 |
}
|
9 |
*
|
10 |
* @package WPStaging\Backend\Notices;
|
11 |
*/
|
12 |
+
class DisabledCacheNotice extends BooleanNotice
|
13 |
{
|
14 |
/**
|
15 |
+
* The option name to store the visibility of disabled cache notice
|
16 |
*/
|
17 |
const OPTION_NAME = 'wpstg_disabled_cache_notice';
|
18 |
|
19 |
+
public function getOptionName()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
{
|
21 |
+
return self::OPTION_NAME;
|
22 |
}
|
23 |
}
|
Backend/Notices/Notices.php
CHANGED
@@ -32,6 +32,11 @@ class Notices
|
|
32 |
*/
|
33 |
private $url;
|
34 |
|
|
|
|
|
|
|
|
|
|
|
35 |
public function __construct($path, $url)
|
36 |
{
|
37 |
$this->path = $path;
|
@@ -170,7 +175,7 @@ class Notices
|
|
170 |
require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
|
171 |
}
|
172 |
|
173 |
-
//
|
174 |
if(!$this->isPro() && version_compare(WPStaging::getInstance()->get('WPSTG_COMPATIBLE'), get_bloginfo("version"), "<")) {
|
175 |
require_once "{$viewsNoticesPath}wp-version-compatible-message.php";
|
176 |
}
|
@@ -179,6 +184,37 @@ class Notices
|
|
179 |
if ($this->isDifferentScheme()) {
|
180 |
require_once "{$viewsNoticesPath}wrong-scheme.php";
|
181 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
182 |
}
|
183 |
|
184 |
/**
|
@@ -193,4 +229,22 @@ class Notices
|
|
193 |
return !($siteurlScheme === $homeScheme);
|
194 |
}
|
195 |
|
196 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
32 |
*/
|
33 |
private $url;
|
34 |
|
35 |
+
/**
|
36 |
+
* @var string The key that holds directory listing errors in the container.
|
37 |
+
*/
|
38 |
+
public static $directoryListingErrors = 'directoryListingErrors';
|
39 |
+
|
40 |
public function __construct($path, $url)
|
41 |
{
|
42 |
$this->path = $path;
|
175 |
require_once "{$viewsNoticesPath}/staging-directory-permission-problem.php";
|
176 |
}
|
177 |
|
178 |
+
// WPSTAGING is not tested with current WordPress version
|
179 |
if(!$this->isPro() && version_compare(WPStaging::getInstance()->get('WPSTG_COMPATIBLE'), get_bloginfo("version"), "<")) {
|
180 |
require_once "{$viewsNoticesPath}wp-version-compatible-message.php";
|
181 |
}
|
184 |
if ($this->isDifferentScheme()) {
|
185 |
require_once "{$viewsNoticesPath}wrong-scheme.php";
|
186 |
}
|
187 |
+
|
188 |
+
$this->showDirectoryListingWarningNotice($viewsNoticesPath);
|
189 |
+
}
|
190 |
+
|
191 |
+
/**
|
192 |
+
* Displays the notice that we could not prevent
|
193 |
+
* directory listing on a sensitive folder for some reason.
|
194 |
+
*
|
195 |
+
* @see \WPStaging\Framework\Filesystem\Filesystem::mkdir The place where all errors are enqueued
|
196 |
+
* to be displayed as a single notice here.
|
197 |
+
*
|
198 |
+
* Note: When refactoring this, keep in mind this code should be
|
199 |
+
* called only once, otherwise the message would be enqueued multiple times.
|
200 |
+
*
|
201 |
+
* @param string $viewsNoticesPath The path to the views folder.
|
202 |
+
*/
|
203 |
+
private function showDirectoryListingWarningNotice($viewsNoticesPath)
|
204 |
+
{
|
205 |
+
$directoryListingErrors = WPStaging::getInstance()->getContainer()->getFromArray(static::$directoryListingErrors);
|
206 |
+
|
207 |
+
// Early bail: No errors to show
|
208 |
+
if (empty($directoryListingErrors)) {
|
209 |
+
return;
|
210 |
+
}
|
211 |
+
|
212 |
+
// Early bail: These warnings were disabled by the user.
|
213 |
+
if ((bool)apply_filters('wpstg.notices.hideDirectoryListingWarnings', false)) {
|
214 |
+
return;
|
215 |
+
}
|
216 |
+
|
217 |
+
require_once "{$viewsNoticesPath}directory-listing-could-not-be-prevented.php";
|
218 |
}
|
219 |
|
220 |
/**
|
229 |
return !($siteurlScheme === $homeScheme);
|
230 |
}
|
231 |
|
232 |
+
/**
|
233 |
+
* Get the path of plugin
|
234 |
+
* @return string
|
235 |
+
*/
|
236 |
+
public function getPluginPath()
|
237 |
+
{
|
238 |
+
return $this->path;
|
239 |
+
}
|
240 |
+
|
241 |
+
/**
|
242 |
+
* Get the path of plugin
|
243 |
+
* @return string
|
244 |
+
*/
|
245 |
+
public function getPluginUrl()
|
246 |
+
{
|
247 |
+
return $this->url;
|
248 |
+
}
|
249 |
+
|
250 |
+
}
|
Backend/Optimizer/Optimizer.php
CHANGED
@@ -2,6 +2,8 @@
|
|
2 |
namespace WPStaging\Backend\Optimizer;
|
3 |
|
4 |
// No Direct Access
|
|
|
|
|
5 |
if( !defined( "WPINC" ) ) {
|
6 |
die;
|
7 |
}
|
@@ -33,7 +35,7 @@ class Optimizer {
|
|
33 |
return false;
|
34 |
}
|
35 |
|
36 |
-
if(
|
37 |
$this->copy();
|
38 |
}
|
39 |
return false;
|
2 |
namespace WPStaging\Backend\Optimizer;
|
3 |
|
4 |
// No Direct Access
|
5 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
6 |
+
|
7 |
if( !defined( "WPINC" ) ) {
|
8 |
die;
|
9 |
}
|
35 |
return false;
|
36 |
}
|
37 |
|
38 |
+
if( (new Filesystem)->mkdir( $this->mudir ) ) {
|
39 |
$this->copy();
|
40 |
}
|
41 |
return false;
|
Backend/Optimizer/wp-staging-optimizer.php
CHANGED
@@ -86,7 +86,7 @@ function wpstgExcludePlugins($plugins)
|
|
86 |
return $plugins;
|
87 |
}
|
88 |
|
89 |
-
if (!
|
90 |
return $plugins;
|
91 |
}
|
92 |
|
@@ -118,7 +118,7 @@ function wpstgExcludeSitePlugins($plugins)
|
|
118 |
return $plugins;
|
119 |
}
|
120 |
|
121 |
-
if (!
|
122 |
return $plugins;
|
123 |
}
|
124 |
|
@@ -148,7 +148,7 @@ function wpstgDisableTheme($dir)
|
|
148 |
{
|
149 |
$enableTheme = apply_filters('wpstg_optimizer_enable_theme', false);
|
150 |
|
151 |
-
if (
|
152 |
$wpstgRootPro = wpstgGetPluginsDir() . 'wp-staging-pro';
|
153 |
$wpstgRoot = wpstgGetPluginsDir() . 'wp-staging';
|
154 |
|
@@ -173,28 +173,28 @@ add_filter('stylesheet_directory', 'wpstgDisableTheme');
|
|
173 |
add_filter('template_directory', 'wpstgDisableTheme');
|
174 |
|
175 |
/**
|
176 |
-
* Should the current request be processed by
|
177 |
*
|
178 |
* @return bool
|
179 |
*/
|
180 |
-
function
|
181 |
{
|
182 |
|
183 |
-
// Optimizer not enabled
|
184 |
if (!wpstgIsEnabledOptimizer()) {
|
185 |
return false;
|
186 |
}
|
187 |
|
188 |
-
if (
|
189 |
-
|
190 |
-
|
191 |
-
strpos($_POST['action'], '
|
|
|
192 |
) {
|
193 |
|
194 |
-
return
|
195 |
}
|
196 |
|
197 |
-
return
|
198 |
}
|
199 |
|
200 |
/**
|
86 |
return $plugins;
|
87 |
}
|
88 |
|
89 |
+
if (!wpstgIsOptimizerRequest()) {
|
90 |
return $plugins;
|
91 |
}
|
92 |
|
118 |
return $plugins;
|
119 |
}
|
120 |
|
121 |
+
if (!wpstgIsOptimizerRequest()) {
|
122 |
return $plugins;
|
123 |
}
|
124 |
|
148 |
{
|
149 |
$enableTheme = apply_filters('wpstg_optimizer_enable_theme', false);
|
150 |
|
151 |
+
if (wpstgIsOptimizerRequest() && $enableTheme === false) {
|
152 |
$wpstgRootPro = wpstgGetPluginsDir() . 'wp-staging-pro';
|
153 |
$wpstgRoot = wpstgGetPluginsDir() . 'wp-staging';
|
154 |
|
173 |
add_filter('template_directory', 'wpstgDisableTheme');
|
174 |
|
175 |
/**
|
176 |
+
* Should the current request be processed by optimizer?
|
177 |
*
|
178 |
* @return bool
|
179 |
*/
|
180 |
+
function wpstgIsOptimizerRequest()
|
181 |
{
|
182 |
|
|
|
183 |
if (!wpstgIsEnabledOptimizer()) {
|
184 |
return false;
|
185 |
}
|
186 |
|
187 |
+
if (defined('DOING_AJAX') &&
|
188 |
+
DOING_AJAX &&
|
189 |
+
isset($_POST['action']) &&
|
190 |
+
strpos($_POST['action'], 'wpstg_send_report') === false &&
|
191 |
+
strpos($_POST['action'], 'wpstg') === 0
|
192 |
) {
|
193 |
|
194 |
+
return true;
|
195 |
}
|
196 |
|
197 |
+
return false;
|
198 |
}
|
199 |
|
200 |
/**
|
Backend/Upgrade/Upgrade.php
CHANGED
@@ -6,7 +6,6 @@ use WPStaging\Core\WPStaging;
|
|
6 |
use WPStaging\Core\Utils\Logger;
|
7 |
use WPStaging\Core\Utils\IISWebConfig;
|
8 |
use WPStaging\Core\Utils\Htaccess;
|
9 |
-
use WPStaging\Core\Utils\Filesystem;
|
10 |
|
11 |
/**
|
12 |
* Upgrade Class
|
@@ -117,11 +116,6 @@ class Upgrade {
|
|
117 |
$htaccess->createLitespeed( ABSPATH . '.htaccess' );
|
118 |
}
|
119 |
|
120 |
-
// Create empty index.php in wp staging uploads folder
|
121 |
-
$filesystem = new Filesystem();
|
122 |
-
$filesystem->create( trailingslashit( \WPStaging\Core\WPStaging::getContentDir() ) . 'index.php', "<?php // silence" );
|
123 |
-
$filesystem->create( trailingslashit( \WPStaging\Core\WPStaging::getContentDir() ) . 'logs/index.php', "<?php // silence" );
|
124 |
-
|
125 |
// create web.config file for IIS in wp staging uploads folder
|
126 |
$webconfig = new IISWebConfig();
|
127 |
$webconfig->create( trailingslashit( \WPStaging\Core\WPStaging::getContentDir() ) . 'web.config' );
|
6 |
use WPStaging\Core\Utils\Logger;
|
7 |
use WPStaging\Core\Utils\IISWebConfig;
|
8 |
use WPStaging\Core\Utils\Htaccess;
|
|
|
9 |
|
10 |
/**
|
11 |
* Upgrade Class
|
116 |
$htaccess->createLitespeed( ABSPATH . '.htaccess' );
|
117 |
}
|
118 |
|
|
|
|
|
|
|
|
|
|
|
119 |
// create web.config file for IIS in wp staging uploads folder
|
120 |
$webconfig = new IISWebConfig();
|
121 |
$webconfig->create( trailingslashit( \WPStaging\Core\WPStaging::getContentDir() ) . 'web.config' );
|
Backend/public/css/wpstg-admin.css
CHANGED
@@ -34,7 +34,7 @@
|
|
34 |
padding-bottom: 12px;
|
35 |
}
|
36 |
|
37 |
-
|
38 |
padding: 0;
|
39 |
}
|
40 |
|
@@ -56,12 +56,7 @@
|
|
56 |
display: none;
|
57 |
}
|
58 |
|
59 |
-
|
60 |
-
/* Layout of admin table and rows
|
61 |
-
*/
|
62 |
-
|
63 |
-
#wpstg-tab-container .panel-container {
|
64 |
-
background: #FFF;
|
65 |
padding: 0 20px 20px 20px;
|
66 |
overflow: auto;
|
67 |
}
|
@@ -758,20 +753,35 @@
|
|
758 |
|
759 |
.wpstg-button.green {
|
760 |
display: inline-block;
|
761 |
-
background-color: #83c11f;
|
762 |
padding: 10px;
|
763 |
min-width: 170px;
|
764 |
-
color: white;
|
765 |
font-size: 16px;
|
766 |
text-decoration: none;
|
767 |
text-align: center;
|
768 |
margin-top: 20px;
|
|
|
|
|
769 |
}
|
770 |
|
771 |
.wpstg-button.green:hover {
|
772 |
background-color: #8ed122;
|
773 |
}
|
774 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
775 |
#wpstg-welcome li {
|
776 |
font-size: 18px;
|
777 |
line-height: 29px;
|
@@ -1073,6 +1083,12 @@
|
|
1073 |
text-align: center;
|
1074 |
}
|
1075 |
|
|
|
|
|
|
|
|
|
|
|
|
|
1076 |
.wpstg-success {
|
1077 |
color: #3c763d;
|
1078 |
background-color: #dff0d8;
|
@@ -1295,11 +1311,11 @@ Tooltip top arrow
|
|
1295 |
color: #f56363;
|
1296 |
}
|
1297 |
|
1298 |
-
.swal2-modal .swal2-cancel.wpstg--btn--cancel {
|
1299 |
margin-bottom: 0;
|
1300 |
}
|
1301 |
|
1302 |
-
.swal2-modal .swal2-confirm.wpstg--btn--confirm {
|
1303 |
font-size: 16px;
|
1304 |
padding: .5em;
|
1305 |
line-height: normal;
|
@@ -1307,7 +1323,7 @@ Tooltip top arrow
|
|
1307 |
margin-right: 10px;
|
1308 |
}
|
1309 |
|
1310 |
-
.swal2-modal .wpstg-loader {
|
1311 |
display: inline-block !important;
|
1312 |
}
|
1313 |
|
@@ -1657,7 +1673,7 @@ span.wpstg--drag-or-upload {
|
|
1657 |
color: #a8a8a8;
|
1658 |
}
|
1659 |
|
1660 |
-
#
|
1661 |
margin-left: 10px;
|
1662 |
}
|
1663 |
|
@@ -1930,4 +1946,8 @@ span.wpstg--drag-or-upload {
|
|
1930 |
|
1931 |
.wpstg-issue-resubmit-confirmation.swal2-container {
|
1932 |
z-index: 10500;
|
1933 |
-
}
|
|
|
|
|
|
|
|
34 |
padding-bottom: 12px;
|
35 |
}
|
36 |
|
37 |
+
.wpstg-tabs-container .nav-tab-wrapper {
|
38 |
padding: 0;
|
39 |
}
|
40 |
|
56 |
display: none;
|
57 |
}
|
58 |
|
59 |
+
#wpstg-tab-container .wpstg-settings-panel {
|
|
|
|
|
|
|
|
|
|
|
60 |
padding: 0 20px 20px 20px;
|
61 |
overflow: auto;
|
62 |
}
|
753 |
|
754 |
.wpstg-button.green {
|
755 |
display: inline-block;
|
|
|
756 |
padding: 10px;
|
757 |
min-width: 170px;
|
|
|
758 |
font-size: 16px;
|
759 |
text-decoration: none;
|
760 |
text-align: center;
|
761 |
margin-top: 20px;
|
762 |
+
background-color: #83c11f;
|
763 |
+
color: white;
|
764 |
}
|
765 |
|
766 |
.wpstg-button.green:hover {
|
767 |
background-color: #8ed122;
|
768 |
}
|
769 |
|
770 |
+
.wpstg-button.wpstg-save {
|
771 |
+
background-color: #1687A7;
|
772 |
+
color: white;
|
773 |
+
}
|
774 |
+
|
775 |
+
.wpstg-button.wpstg-save:hover {
|
776 |
+
background-color: #276678;
|
777 |
+
}
|
778 |
+
|
779 |
+
.wpstg-button.wpstg-bordered {
|
780 |
+
border-radius:3px;
|
781 |
+
font-size: 14px;
|
782 |
+
border: 1px solid white;
|
783 |
+
}
|
784 |
+
|
785 |
#wpstg-welcome li {
|
786 |
font-size: 18px;
|
787 |
line-height: 29px;
|
1083 |
text-align: center;
|
1084 |
}
|
1085 |
|
1086 |
+
.wpstg-text-field>#wpstg-db-status {
|
1087 |
+
margin-top: 8px;
|
1088 |
+
margin-left: 25%;
|
1089 |
+
min-width: 350px;
|
1090 |
+
}
|
1091 |
+
|
1092 |
.wpstg-success {
|
1093 |
color: #3c763d;
|
1094 |
background-color: #dff0d8;
|
1311 |
color: #f56363;
|
1312 |
}
|
1313 |
|
1314 |
+
body.toplevel_page_wpstg_clone .swal2-modal .swal2-cancel.wpstg--btn--cancel {
|
1315 |
margin-bottom: 0;
|
1316 |
}
|
1317 |
|
1318 |
+
body.toplevel_page_wpstg_clone .swal2-modal .swal2-confirm.wpstg--btn--confirm {
|
1319 |
font-size: 16px;
|
1320 |
padding: .5em;
|
1321 |
line-height: normal;
|
1323 |
margin-right: 10px;
|
1324 |
}
|
1325 |
|
1326 |
+
body.toplevel_page_wpstg_clone .swal2-modal .wpstg-loader {
|
1327 |
display: inline-block !important;
|
1328 |
}
|
1329 |
|
1673 |
color: #a8a8a8;
|
1674 |
}
|
1675 |
|
1676 |
+
#wpstg_allow_emails {
|
1677 |
margin-left: 10px;
|
1678 |
}
|
1679 |
|
1946 |
|
1947 |
.wpstg-issue-resubmit-confirmation.swal2-container {
|
1948 |
z-index: 10500;
|
1949 |
+
}
|
1950 |
+
|
1951 |
+
body.toplevel_page_wpstg_clone .swal2-container .swal2-content {
|
1952 |
+
z-index:2;
|
1953 |
+
}
|
Backend/public/js/wpstg-admin-beta.js
CHANGED
@@ -2,7 +2,7 @@ jQuery(document).ready(function($){
|
|
2 |
$(".wpstg_hide_beta").click(function(e) {
|
3 |
e.preventDefault();
|
4 |
|
5 |
-
WPStaging.ajax(
|
6 |
{action: "wpstg_hide_beta"},
|
7 |
function(response)
|
8 |
{
|
2 |
$(".wpstg_hide_beta").click(function(e) {
|
3 |
e.preventDefault();
|
4 |
|
5 |
+
window.WPStaging.ajax(
|
6 |
{action: "wpstg_hide_beta"},
|
7 |
function(response)
|
8 |
{
|
Backend/public/js/wpstg-admin-poll.js
CHANGED
@@ -2,7 +2,7 @@ jQuery(document).ready(function ($) {
|
|
2 |
$(".wpstg_hide_poll").click(function (e) {
|
3 |
e.preventDefault();
|
4 |
|
5 |
-
WPStaging.ajax(
|
6 |
{action: "wpstg_hide_poll"},
|
7 |
function (response)
|
8 |
{
|
2 |
$(".wpstg_hide_poll").click(function (e) {
|
3 |
e.preventDefault();
|
4 |
|
5 |
+
window.WPStaging.ajax(
|
6 |
{action: "wpstg_hide_poll"},
|
7 |
function (response)
|
8 |
{
|
Backend/public/js/wpstg-admin.js
CHANGED
@@ -857,9 +857,10 @@ var WPStaging = (function ($) {
|
|
857 |
var cloneDir = $("#wpstg_clone_dir").val();
|
858 |
that.data.cloneDir = encodeURIComponent($.trim(cloneDir));
|
859 |
that.data.cloneHostname = $("#wpstg_clone_hostname").val();
|
860 |
-
that.data.
|
861 |
that.data.uploadsSymlinked = $("#wpstg_symlink_upload").is(':checked');
|
862 |
-
|
|
|
863 |
};
|
864 |
|
865 |
var proceedCloning = function($this, workflow) {
|
@@ -1001,11 +1002,13 @@ var WPStaging = (function ($) {
|
|
1001 |
showAjaxFatalError(response);
|
1002 |
|
1003 |
// Finished
|
1004 |
-
if ("undefined" !== typeof response.delete && response.delete === 'finished') {
|
1005 |
|
1006 |
cache.get("#wpstg-removing-clone").removeClass("loading").html('');
|
1007 |
|
1008 |
-
|
|
|
|
|
1009 |
|
1010 |
if ($(".wpstg-clone").length < 1) {
|
1011 |
cache.get("#wpstg-existing-clones").find("h3").text('');
|
@@ -1992,16 +1995,27 @@ var WPStaging = (function ($) {
|
|
1992 |
|
1993 |
if (data.type === 'database') {
|
1994 |
that.snapshots.type = data.type;
|
|
|
|
|
|
|
1995 |
delete requestData['includedDirectories'];
|
1996 |
delete requestData['wpContentDir'];
|
1997 |
delete requestData['availableDirectories'];
|
1998 |
delete requestData['wpStagingDir'];
|
|
|
|
|
|
|
1999 |
requestData = that.snapshots.requestData(
|
2000 |
'tasks.snapshot.database.create',
|
2001 |
{ ...requestData, type: 'manual' }
|
2002 |
);
|
2003 |
} else if (data.type === 'site') {
|
2004 |
that.snapshots.type = data.type;
|
|
|
|
|
|
|
|
|
|
|
2005 |
requestData = that.snapshots.requestData(
|
2006 |
'jobs.snapshot.site.create',
|
2007 |
requestData
|
@@ -2013,10 +2027,15 @@ var WPStaging = (function ($) {
|
|
2013 |
requestData.jobs.snapshot.site.create.excludedDirectories = data.availableDirectories
|
2014 |
.split('|')
|
2015 |
.filter(item => !data.includedDirectories.includes(item))
|
2016 |
-
.map(item =>
|
2017 |
;
|
|
|
|
|
|
|
2018 |
|
2019 |
-
|
|
|
|
|
2020 |
|
2021 |
// delete requestData.jobs.snapshot.site.create.includedDirectories;
|
2022 |
delete requestData.jobs.snapshot.site.create.wpContentDir;
|
@@ -2228,6 +2247,7 @@ var WPStaging = (function ($) {
|
|
2228 |
availableDirectories: container.querySelector('input[name="availableDirectories"]').value || null,
|
2229 |
wpStagingDir: container.querySelector('input[name="wpStagingDir"]').value || null,
|
2230 |
exportDatabase: container.querySelector('input[name="export_database"]:checked') !== null,
|
|
|
2231 |
};
|
2232 |
},
|
2233 |
});
|
@@ -3055,4 +3075,4 @@ jQuery(document).ready(function ($) {
|
|
3055 |
e.preventDefault();
|
3056 |
});
|
3057 |
|
3058 |
-
});
|
857 |
var cloneDir = $("#wpstg_clone_dir").val();
|
858 |
that.data.cloneDir = encodeURIComponent($.trim(cloneDir));
|
859 |
that.data.cloneHostname = $("#wpstg_clone_hostname").val();
|
860 |
+
that.data.emailsAllowed = $("#wpstg_allow_emails").is(':checked');
|
861 |
that.data.uploadsSymlinked = $("#wpstg_symlink_upload").is(':checked');
|
862 |
+
that.data.cleanPluginsThemes = $('#wpstg-clean-plugins-themes').is(':checked');
|
863 |
+
that.data.cleanUploadsDir = $('#wpstg-clean-uploads').is(':checked');
|
864 |
};
|
865 |
|
866 |
var proceedCloning = function($this, workflow) {
|
1002 |
showAjaxFatalError(response);
|
1003 |
|
1004 |
// Finished
|
1005 |
+
if ("undefined" !== typeof response.delete && (response.delete === 'finished' || response.delete === 'unfinished')) {
|
1006 |
|
1007 |
cache.get("#wpstg-removing-clone").removeClass("loading").html('');
|
1008 |
|
1009 |
+
if (response.delete === 'finished') {
|
1010 |
+
$(".wpstg-clone#" + clone).remove();
|
1011 |
+
}
|
1012 |
|
1013 |
if ($(".wpstg-clone").length < 1) {
|
1014 |
cache.get("#wpstg-existing-clones").find("h3").text('');
|
1995 |
|
1996 |
if (data.type === 'database') {
|
1997 |
that.snapshots.type = data.type;
|
1998 |
+
|
1999 |
+
// Only send to back-end what BE is expecting to receive.
|
2000 |
+
// Prevent error: Trying to hydrate DTO with value that does not exist.
|
2001 |
delete requestData['includedDirectories'];
|
2002 |
delete requestData['wpContentDir'];
|
2003 |
delete requestData['availableDirectories'];
|
2004 |
delete requestData['wpStagingDir'];
|
2005 |
+
delete requestData['exportDatabase'];
|
2006 |
+
delete requestData['includeOtherFilesInWpContent'];
|
2007 |
+
|
2008 |
requestData = that.snapshots.requestData(
|
2009 |
'tasks.snapshot.database.create',
|
2010 |
{ ...requestData, type: 'manual' }
|
2011 |
);
|
2012 |
} else if (data.type === 'site') {
|
2013 |
that.snapshots.type = data.type;
|
2014 |
+
|
2015 |
+
// Only send to back-end what BE is expecting to receive.
|
2016 |
+
// Prevent error: Trying to hydrate DTO with value that does not exist.
|
2017 |
+
delete requestData['type'];
|
2018 |
+
|
2019 |
requestData = that.snapshots.requestData(
|
2020 |
'jobs.snapshot.site.create',
|
2021 |
requestData
|
2027 |
requestData.jobs.snapshot.site.create.excludedDirectories = data.availableDirectories
|
2028 |
.split('|')
|
2029 |
.filter(item => !data.includedDirectories.includes(item))
|
2030 |
+
.map(item => item)
|
2031 |
;
|
2032 |
+
requestData.jobs.snapshot.site.create.includeOtherFilesInWpContent = [
|
2033 |
+
data.includeOtherFilesInWpContent,
|
2034 |
+
];
|
2035 |
|
2036 |
+
// Do not exclude the wp-content/uploads/wp-staging using regex by default
|
2037 |
+
// This folder is excluded by PHP without REGEX.
|
2038 |
+
//requestData.jobs.snapshot.site.create.excludedDirectories.push(`#${data.wpStagingDir}*#`);
|
2039 |
|
2040 |
// delete requestData.jobs.snapshot.site.create.includedDirectories;
|
2041 |
delete requestData.jobs.snapshot.site.create.wpContentDir;
|
2247 |
availableDirectories: container.querySelector('input[name="availableDirectories"]').value || null,
|
2248 |
wpStagingDir: container.querySelector('input[name="wpStagingDir"]').value || null,
|
2249 |
exportDatabase: container.querySelector('input[name="export_database"]:checked') !== null,
|
2250 |
+
includeOtherFilesInWpContent: container.querySelector('input[name="includeOtherFilesInWpContent"]:checked') !== null,
|
2251 |
};
|
2252 |
},
|
2253 |
});
|
3075 |
e.preventDefault();
|
3076 |
});
|
3077 |
|
3078 |
+
});
|
Backend/views/clone/ajax/external-database.php
CHANGED
@@ -11,20 +11,31 @@
|
|
11 |
<?php _e('Copy Staging Site to Separate Database', 'wp-staging'); ?></strong>
|
12 |
<br><?php _e('Database must be created manually in advance!', 'wp-staging'); ?>
|
13 |
</p>
|
14 |
-
<
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
21 |
-
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
</fieldset>
|
30 |
|
11 |
<?php _e('Copy Staging Site to Separate Database', 'wp-staging'); ?></strong>
|
12 |
<br><?php _e('Database must be created manually in advance!', 'wp-staging'); ?>
|
13 |
</p>
|
14 |
+
<div id="wpstg-external-db">
|
15 |
+
<div class="wpstg-form-group wpstg-text-field">
|
16 |
+
<label><?php _e('Server: ', 'wp-staging'); ?> </label>
|
17 |
+
<input type="text" name="wpstg_db_server" id="wpstg_db_server" value="" title="wpstg_db_server" placeholder="localhost" autocapitalize="off" readonly>
|
18 |
+
</div>
|
19 |
+
<div class="wpstg-form-group wpstg-text-field">
|
20 |
+
<label><?php _e('User: ', 'wp-staging'); ?></label>
|
21 |
+
<input type="text" name="wpstg_db_username" id="wpstg_db_username" value="" autocapitalize="off" class="" readonly>
|
22 |
+
</div>
|
23 |
+
<div class="wpstg-form-group wpstg-text-field">
|
24 |
+
<label><?php _e('Password: ', 'wp-staging'); ?></label>
|
25 |
+
<input type="password" name="wpstg_db_password" id="wpstg_db_password" class="" readonly>
|
26 |
+
</div>
|
27 |
+
<div class="wpstg-form-group wpstg-text-field">
|
28 |
+
<label><?php _e('Database: ', 'wp-staging'); ?></label>
|
29 |
+
<input type="text" name="wpstg_db_database" id="wpstg_db_database" value="" autocapitalize="off" readonly>
|
30 |
+
</div>
|
31 |
+
<div class="wpstg-form-group wpstg-text-field">
|
32 |
+
<label><?php _e('Database Prefix: ', 'wp-staging'); ?></label>
|
33 |
+
<input type="text" name="wpstg_db_prefix" id="wpstg_db_prefix" value="" placeholder="<?php echo $db->prefix; ?>" autocapitalize="off" readonly>
|
34 |
+
</div>
|
35 |
+
<div class="wpstg-form-group wpstg-text-field">
|
36 |
+
<label> </label>
|
37 |
+
<a href="#" id="wpstg-db-connect"><?php _e("Test Database Connection", "wp-staging"); ?></a>
|
38 |
+
</div>
|
39 |
+
</div>
|
40 |
</fieldset>
|
41 |
|
Backend/views/clone/ajax/mail-setting.php
CHANGED
@@ -1,15 +1,14 @@
|
|
1 |
-
<
|
2 |
-
<p>
|
3 |
-
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
<
|
8 |
-
|
9 |
-
|
10 |
-
|
11 |
-
|
12 |
-
<p style="font-weight:bold;background-color:#e6e6e6;padding:15px;border-top: 1px solid white;margin-top: 20px;"><?php _e('That\'s a Pro Feature', 'wp-staging'); ?>
|
13 |
<br>
|
14 |
-
<a href="https://wp-staging.com/?utm_source=wp-admin&utm_medium=wp-admin&utm_campaign=db-external&utm_term=db-external" target="_blank" class="quads-button green wpstg-button
|
15 |
-
</p>
|
1 |
+
<fieldset disabled class="wpstg-fieldset">
|
2 |
+
<p>
|
3 |
+
<?php _e('Toggle emails sending for the staging site.', 'wp-staging'); ?>
|
4 |
+
</p>
|
5 |
+
<div class="wpstg-form-group">
|
6 |
+
<label class="wpstg-checkbox" for="wpstg_allow_emails">
|
7 |
+
<?php _e('Allow Emails Sending:', 'wp-staging'); ?> <input type="checkbox" id="wpstg_allow_emails" disabled checked>
|
8 |
+
</label>
|
9 |
+
</div>
|
10 |
+
</fieldset>
|
11 |
+
<p class="wpstg-light-alert"><?php _e('That\'s a Pro Feature', 'wp-staging'); ?>
|
|
|
12 |
<br>
|
13 |
+
<a href="https://wp-staging.com/?utm_source=wp-admin&utm_medium=wp-admin&utm_campaign=db-external&utm_term=db-external" target="_blank" class="quads-button green wpstg-button wpstg-bordered"><?php _e("Get WP STAGING Pro", "wp-staging"); ?></a>
|
14 |
+
</p>
|
Backend/views/clone/ajax/scan.php
CHANGED
@@ -109,22 +109,38 @@
|
|
109 |
</a>
|
110 |
|
111 |
<div class="wpstg-tab-section" id="wpstg-advanced-settings">
|
112 |
-
|
113 |
<?php
|
114 |
if (defined('WPSTGPRO_VERSION')) {
|
115 |
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/external-database.php');
|
116 |
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/custom-directory.php');
|
117 |
-
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/mail-setting.php');
|
118 |
} else {
|
119 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'external-database.php');
|
120 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'custom-directory.php');
|
121 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mail-setting.php');
|
122 |
}
|
123 |
?>
|
124 |
-
|
125 |
</div>
|
126 |
</div>
|
127 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
128 |
<strong>Important:</strong><a href="#" id="wpstg-check-space"><?php _e( 'Check required disk space', 'wp-staging' ); ?></a>
|
129 |
<p></p>
|
130 |
|
109 |
</a>
|
110 |
|
111 |
<div class="wpstg-tab-section" id="wpstg-advanced-settings">
|
|
|
112 |
<?php
|
113 |
if (defined('WPSTGPRO_VERSION')) {
|
114 |
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/external-database.php');
|
115 |
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/custom-directory.php');
|
|
|
116 |
} else {
|
117 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'external-database.php');
|
118 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'custom-directory.php');
|
119 |
require_once(__DIR__ . DIRECTORY_SEPARATOR . 'mail-setting.php');
|
120 |
}
|
121 |
?>
|
|
|
122 |
</div>
|
123 |
</div>
|
124 |
|
125 |
+
<?php
|
126 |
+
if (defined('WPSTGPRO_VERSION')) {
|
127 |
+
require_once(WPSTG_PLUGIN_DIR . 'Backend/Pro/views/clone/ajax/mail-setting.php');
|
128 |
+
}
|
129 |
+
|
130 |
+
if( $options->current !== null ) {
|
131 |
+
$uploadsSymlinked = isset($options->existingClones[$options->current]['uploadsSymlinked']) ? (bool)$options->existingClones[$options->current]['uploadsSymlinked'] : false;
|
132 |
+
?>
|
133 |
+
<p><label>
|
134 |
+
<input type="checkbox" id="wpstg-clean-plugins-themes" name="wpstg-clean-plugins-themes">
|
135 |
+
<?php echo __("Delete all plugins & themes on staging site before starting copy process.", "wp-staging"); ?>
|
136 |
+
</label></p>
|
137 |
+
<p><label> <?php echo ($uploadsSymlinked ? "<b>" . __("Note: This option is disabled as uploads directory is symlinked", "wp-staging") . "</b><br/>": '') ?>
|
138 |
+
<input type="checkbox" id="wpstg-clean-uploads" name="wpstg-clean-uploads" <?php echo ($uploadsSymlinked ? 'disabled' : '') ?>>
|
139 |
+
<?php echo __("Delete entire folder wp-content/uploads on staging site including all images before starting copy process.", "wp-staging"); ?>
|
140 |
+
</label></p>
|
141 |
+
<?php
|
142 |
+
}
|
143 |
+
?>
|
144 |
<strong>Important:</strong><a href="#" id="wpstg-check-space"><?php _e( 'Check required disk space', 'wp-staging' ); ?></a>
|
145 |
<p></p>
|
146 |
|
Backend/views/clone/ajax/single-overview.php
CHANGED
@@ -30,7 +30,10 @@
|
|
30 |
do_action('wpstg.views.single_overview.before_existing_clones_buttons', $name, $data, $license);
|
31 |
|
32 |
// Todo: Remove in future versions
|
33 |
-
|
|
|
|
|
|
|
34 |
?>
|
35 |
|
36 |
<a href="<?php echo $urlLogin ?>" class="wpstg-open-clone wpstg-clone-action" target="_blank" title="<?php echo __( "Open the staging site in a new tab", "wp-staging" ) ?>">
|
@@ -49,7 +52,10 @@
|
|
49 |
do_action('wpstg.views.single_overview.after_existing_clones_buttons', $name, $data, $license);
|
50 |
|
51 |
// Todo: Remove in future versions
|
52 |
-
|
|
|
|
|
|
|
53 |
?>
|
54 |
|
55 |
<div class="wpstg-staging-info">
|
@@ -59,7 +65,8 @@
|
|
59 |
$cloneDir = ! empty($data['path']) ? $data['path'] : '';
|
60 |
$url = ! empty($data['url']) ? sprintf('<a href="%1$s" target="_blank">%1$s</a>', $data['url']) : '';
|
61 |
$datetime = ! empty($data['datetime']) ? date("D, d M Y H:i:s T", $data['datetime']) : ' ';
|
62 |
-
|
|
|
63 |
$statusTooltip = "This clone is incomplete and does not work. Clone or update it again! \n\n".
|
64 |
"Important: Keep the browser open until the cloning is finished. \n".
|
65 |
"It will not proceed if your browser is not open.\n\n".
|
@@ -86,6 +93,8 @@
|
|
86 |
echo '</br>';
|
87 |
echo sprintf(__('URL: <span class="wpstg-bold">%s</span>', 'wp-staging'), $url);
|
88 |
echo '</br>';
|
|
|
|
|
89 |
echo $status;
|
90 |
echo '</br>';
|
91 |
echo sprintf(__('Updated: <span>%s</span>', 'wp-staging'), $datetime);
|
30 |
do_action('wpstg.views.single_overview.before_existing_clones_buttons', $name, $data, $license);
|
31 |
|
32 |
// Todo: Remove in future versions
|
33 |
+
if (function_exists('apply_filters_deprecated')) {
|
34 |
+
// apply_filters_deprecated exists since WP 4.6
|
35 |
+
echo apply_filters_deprecated("wpstg_before_stage_buttons", [$html = '', $name, $data], '2.7.6', 'wpstg.views.single_overview.before_existing_clones_buttons', 'The replacement filter uses do_action()');
|
36 |
+
}
|
37 |
?>
|
38 |
|
39 |
<a href="<?php echo $urlLogin ?>" class="wpstg-open-clone wpstg-clone-action" target="_blank" title="<?php echo __( "Open the staging site in a new tab", "wp-staging" ) ?>">
|
52 |
do_action('wpstg.views.single_overview.after_existing_clones_buttons', $name, $data, $license);
|
53 |
|
54 |
// Todo: Remove in future versions
|
55 |
+
if (function_exists('apply_filters_deprecated')) {
|
56 |
+
// apply_filters_deprecated exists since WP 4.6
|
57 |
+
echo apply_filters_deprecated("wpstg_after_stage_buttons", [$html = '', $name, $data], '2.7.6', 'wpstg.views.single_overview.after_existing_clones_buttons', 'The replacement filter uses do_action()');
|
58 |
+
}
|
59 |
?>
|
60 |
|
61 |
<div class="wpstg-staging-info">
|
65 |
$cloneDir = ! empty($data['path']) ? $data['path'] : '';
|
66 |
$url = ! empty($data['url']) ? sprintf('<a href="%1$s" target="_blank">%1$s</a>', $data['url']) : '';
|
67 |
$datetime = ! empty($data['datetime']) ? date("D, d M Y H:i:s T", $data['datetime']) : ' ';
|
68 |
+
$owner = ! empty($data['ownerId']) ? get_userdata($data['ownerId']) : null;
|
69 |
+
$ownerName = ($owner !== null) ? $owner->user_login : 'N/A';
|
70 |
$statusTooltip = "This clone is incomplete and does not work. Clone or update it again! \n\n".
|
71 |
"Important: Keep the browser open until the cloning is finished. \n".
|
72 |
"It will not proceed if your browser is not open.\n\n".
|
93 |
echo '</br>';
|
94 |
echo sprintf(__('URL: <span class="wpstg-bold">%s</span>', 'wp-staging'), $url);
|
95 |
echo '</br>';
|
96 |
+
echo sprintf(__('Created By: <span class="wpstg-bold">%s</span>', 'wp-staging'), $ownerName);
|
97 |
+
echo '</br>';
|
98 |
echo $status;
|
99 |
echo '</br>';
|
100 |
echo sprintf(__('Updated: <span>%s</span>', 'wp-staging'), $datetime);
|
Backend/views/clone/ajax/start.php
CHANGED
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<div class=successfullying-section">
|
2 |
<h2 id="wpstg-processing-header"><?php echo __("Processing, please wait...", "wp-staging")?></h2>
|
3 |
<div class="wpstg-progress-bar">
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @see \WPStaging\Backend\Administrator::ajaxStartClone A place where this view is being called.
|
4 |
+
* @var \WPStaging\Backend\Modules\Jobs\Cloning $cloning
|
5 |
+
*/
|
6 |
+
?>
|
7 |
<div class=successfullying-section">
|
8 |
<h2 id="wpstg-processing-header"><?php echo __("Processing, please wait...", "wp-staging")?></h2>
|
9 |
<div class="wpstg-progress-bar">
|
Backend/views/clone/ajax/update.php
CHANGED
@@ -1,3 +1,9 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
<div class=successfullying-section">
|
2 |
<h2 id="wpstg-processing-header"><?php echo __("Processing, please wait...", "wp-staging")?></h2>
|
3 |
<div class="wpstg-progress-bar">
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @see \WPStaging\Backend\Administrator::ajaxUpdateProcess A place where this view is being called.
|
4 |
+
* @var \WPStaging\Backend\Modules\Jobs\Cloning $cloning
|
5 |
+
*/
|
6 |
+
?>
|
7 |
<div class=successfullying-section">
|
8 |
<h2 id="wpstg-processing-header"><?php echo __("Processing, please wait...", "wp-staging")?></h2>
|
9 |
<div class="wpstg-progress-bar">
|
Backend/views/notices/directory-listing-could-not-be-prevented.php
ADDED
@@ -0,0 +1,14 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @see \WPStaging\Backend\Notices\Notices::showDirectoryListingWarningNotice
|
4 |
+
* @var array $directoryListingErrors An array of directory listing errors to display.
|
5 |
+
*/
|
6 |
+
?>
|
7 |
+
|
8 |
+
<div class='notice-warning notice is-dismissible'>
|
9 |
+
<p style='font-weight: bold;'><?php _e('WPSTAGING - Failed to prevent directory listing', 'wp-staging'); ?></p>
|
10 |
+
<p><?php _e('Following the best development practices, WPSTAGING tries to prevent directory listing on it\'s own directories
|
11 |
+
that might contain sensitive data. This warning tells you that we could not prevent directory listing on one
|
12 |
+
of the directories.'); ?></p>
|
13 |
+
<p><?php echo implode('<br>', esc_html($directoryListingErrors)); ?></p>
|
14 |
+
</div>
|
Backend/views/settings/main-settings.php
CHANGED
@@ -1,436 +1,42 @@
|
|
1 |
<div class="wpstg_admin">
|
2 |
<?php require_once(WPSTG_PLUGIN_DIR . 'Backend/views/_main/header.php'); ?>
|
3 |
|
4 |
-
<
|
5 |
-
|
6 |
-
$tabs = \WPStaging\Core\WPStaging::getInstance()->get("tabs")->get();
|
7 |
-
$activeTab = (isset($_GET["tab"]) && array_key_exists($_GET["tab"], $tabs)) ? $_GET["tab"] : "general";
|
8 |
-
|
9 |
-
# Loop through tabs
|
10 |
-
foreach ($tabs as $id => $name):
|
11 |
-
$url = esc_url(
|
12 |
-
add_query_arg(
|
13 |
-
[
|
14 |
-
"settings-updated" => false,
|
15 |
-
"tab" => $id
|
16 |
-
]
|
17 |
-
)
|
18 |
-
);
|
19 |
-
|
20 |
-
$activeClass = ($activeTab === $id) ? " nav-tab-active" : '';
|
21 |
-
?>
|
22 |
-
<li>
|
23 |
-
<a href="<?php
|
24 |
-
echo $url ?>" title="<?php
|
25 |
-
echo esc_attr($name) ?>" class="nav-tab<?php
|
26 |
-
echo $activeClass ?>">
|
27 |
-
<?php
|
28 |
-
echo esc_html($name) ?>
|
29 |
-
</a>
|
30 |
-
</li>
|
31 |
<?php
|
32 |
-
|
33 |
-
|
34 |
-
|
35 |
-
|
36 |
-
|
37 |
-
|
38 |
-
|
39 |
-
|
40 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
41 |
<?php
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
|
46 |
-
|
47 |
-
if ($form === null) {
|
48 |
-
continue;
|
49 |
-
}
|
50 |
-
?>
|
51 |
-
<div id="<?php
|
52 |
-
echo $id ?>__wpstg_header">
|
53 |
-
<table class="wpstg-form-table">
|
54 |
-
<thead>
|
55 |
-
<tr class="row">
|
56 |
-
<th class="row th" colspan="2">
|
57 |
-
<div class="col-title">
|
58 |
-
<strong><?php
|
59 |
-
echo $name ?></strong>
|
60 |
-
<span class="description"></span>
|
61 |
-
</div>
|
62 |
-
</th>
|
63 |
-
</tr>
|
64 |
-
</thead>
|
65 |
-
|
66 |
-
<tbody>
|
67 |
-
<tr class="row">
|
68 |
-
<td class="row th">
|
69 |
-
<div class="col-title">
|
70 |
-
<?php
|
71 |
-
echo $form->label("wpstg_settings[queryLimit]")
|
72 |
-
?>
|
73 |
-
<span class="description">
|
74 |
-
<?php
|
75 |
-
_e(
|
76 |
-
"Number of DB rows, that are copied within one ajax query.
|
77 |
-
The higher the value the faster the database copy process.
|
78 |
-
To find out the highest possible values try a high value like 1.000 or more. If you get timeout issues, lower it
|
79 |
-
until you get no more errors during copying process.",
|
80 |
-
"wp-staging"
|
81 |
-
); ?>
|
82 |
-
<br>
|
83 |
-
<strong> Default: 10000 </strong>
|
84 |
-
</span>
|
85 |
-
</div>
|
86 |
-
</td>
|
87 |
-
<td>
|
88 |
-
<?php
|
89 |
-
echo $form->render("wpstg_settings[queryLimit]") ?>
|
90 |
-
</td>
|
91 |
-
</tr>
|
92 |
-
<tr class="row">
|
93 |
-
<td class="row th">
|
94 |
-
<div class="col-title">
|
95 |
-
<?php
|
96 |
-
echo $form->label("wpstg_settings[querySRLimit]")
|
97 |
-
?>
|
98 |
-
<span class="description">
|
99 |
-
<?php
|
100 |
-
_e(
|
101 |
-
"Number of DB rows, that are processed within one ajax query.
|
102 |
-
The higher the value the faster the database search & replace process.
|
103 |
-
This is a high memory consumptive process. If you get timeouts lower this value!",
|
104 |
-
"wp-staging"
|
105 |
-
); ?>
|
106 |
-
<br>
|
107 |
-
<strong> Default: 5000 </strong>
|
108 |
-
</span>
|
109 |
-
</div>
|
110 |
-
</td>
|
111 |
-
<td>
|
112 |
-
<?php
|
113 |
-
echo $form->render("wpstg_settings[querySRLimit]") ?>
|
114 |
-
</td>
|
115 |
-
</tr>
|
116 |
-
|
117 |
-
<tr class="row">
|
118 |
-
<td class="row th">
|
119 |
-
<div class="col-title">
|
120 |
-
<?php
|
121 |
-
echo $form->label("wpstg_settings[fileLimit]")
|
122 |
-
?>
|
123 |
-
<span class="description">
|
124 |
-
<?php
|
125 |
-
_e(
|
126 |
-
"Number of files to copy that will be copied within one ajax request.
|
127 |
-
The higher the value the faster the file copy process.
|
128 |
-
To find out the highest possible values try a high value like 500 or more. If you get timeout issues, lower it
|
129 |
-
until you get no more errors during copying process.",
|
130 |
-
"wp-staging"
|
131 |
-
); ?>
|
132 |
-
<br>
|
133 |
-
<br>
|
134 |
-
<?php
|
135 |
-
_e(
|
136 |
-
"<strong>Important:</strong> If CPU Load Priority is <strong>Low</strong> set a file copy limit value of 50 or higher! Otherwise file copying process takes a lot of time.",
|
137 |
-
"wp-staging"
|
138 |
-
); ?>
|
139 |
-
<br>
|
140 |
-
<br>
|
141 |
-
<strong> Default: 50 </strong>
|
142 |
-
</span>
|
143 |
-
</div>
|
144 |
-
</td>
|
145 |
-
<td>
|
146 |
-
<?php
|
147 |
-
echo $form->render("wpstg_settings[fileLimit]") ?>
|
148 |
-
</td>
|
149 |
-
</tr>
|
150 |
-
|
151 |
-
<tr class="row">
|
152 |
-
<td class="row th">
|
153 |
-
<div class="col-title">
|
154 |
-
<?php
|
155 |
-
echo $form->label("wpstg_settings[maxFileSize]") ?>
|
156 |
-
<span class="description">
|
157 |
-
<?php
|
158 |
-
_e(
|
159 |
-
"Maximum size of the files which are allowed to copy. All files larger than this value will be skipped.
|
160 |
-
Note: Increase this option only if you have a good reason. Files larger than a few megabytes are in 99% of all cases log and backup files which are not needed on a staging site.",
|
161 |
-
"wp-staging"
|
162 |
-
); ?>
|
163 |
-
<br>
|
164 |
-
<strong>Default:</strong> 8 MB
|
165 |
-
</span>
|
166 |
-
</div>
|
167 |
-
</td>
|
168 |
-
<td>
|
169 |
-
<?php
|
170 |
-
echo $form->render("wpstg_settings[maxFileSize]") ?>
|
171 |
-
</td>
|
172 |
-
</tr>
|
173 |
-
<tr class="row">
|
174 |
-
<td class="row th">
|
175 |
-
<div class="col-title">
|
176 |
-
<?php
|
177 |
-
echo $form->label("wpstg_settings[batchSize]") ?>
|
178 |
-
<span class="description">
|
179 |
-
<?php
|
180 |
-
_e(
|
181 |
-
"Buffer size for the file copy process in megabyte.
|
182 |
-
The higher the value the faster large files are copied.
|
183 |
-
To find out the highest possible values try a high one and lower it until
|
184 |
-
you get no errors during file copy process. Usually this value correlates directly
|
185 |
-
with the memory consumption of php so make sure that
|
186 |
-
it does not exceed any php.ini max_memory limits.",
|
187 |
-
"wp-staging"
|
188 |
-
); ?>
|
189 |
-
<br>
|
190 |
-
<strong>Default:</strong> 2 MB
|
191 |
-
</span>
|
192 |
-
</div>
|
193 |
-
</td>
|
194 |
-
<td>
|
195 |
-
<?php
|
196 |
-
echo $form->render("wpstg_settings[batchSize]") ?>
|
197 |
-
</td>
|
198 |
-
</tr>
|
199 |
-
|
200 |
-
<tr class="row">
|
201 |
-
<td class="row th">
|
202 |
-
<div class="col-title">
|
203 |
-
<?php
|
204 |
-
echo $form->label("wpstg_settings[cpuLoad]") ?>
|
205 |
-
<span class="description">
|
206 |
-
<?php
|
207 |
-
_e(
|
208 |
-
"Using high will result in fast as possible processing but the cpu load
|
209 |
-
increases and it's also possible that staging process gets interrupted because of too many ajax requests
|
210 |
-
(e.g. <strong>authorization error</strong>).
|
211 |
-
Using a lower value results in lower cpu load on your server but also slower staging site creation.",
|
212 |
-
"wp-staging"
|
213 |
-
); ?>
|
214 |
-
<br>
|
215 |
-
<strong>Default: </strong> Low
|
216 |
-
</span>
|
217 |
-
</div>
|
218 |
-
</td>
|
219 |
-
<td>
|
220 |
-
<?php
|
221 |
-
echo $form->render("wpstg_settings[cpuLoad]") ?>
|
222 |
-
</td>
|
223 |
-
</tr>
|
224 |
-
<tr class="row">
|
225 |
-
<td class="row th">
|
226 |
-
<div class="col-title">
|
227 |
-
<?php
|
228 |
-
echo $form->label("wpstg_settings[delayRequests]") ?>
|
229 |
-
<span class="description">
|
230 |
-
<?php
|
231 |
-
_e(
|
232 |
-
"If your server uses rate limits it blocks requests and WP Staging can be interrupted. You can resolve that by adding one or more seconds of delay between the processing requests. ",
|
233 |
-
"wp-staging"
|
234 |
-
); ?>
|
235 |
-
<br>
|
236 |
-
<strong>Default: </strong> 0s
|
237 |
-
</span>
|
238 |
-
</div>
|
239 |
-
</td>
|
240 |
-
<td>
|
241 |
-
<?php
|
242 |
-
echo $form->render("wpstg_settings[delayRequests]") ?>
|
243 |
-
</td>
|
244 |
-
</tr>
|
245 |
-
<?php
|
246 |
-
if (!defined('WPSTGPRO_VERSION')) {
|
247 |
-
?>
|
248 |
-
<tr class="row">
|
249 |
-
<td class="row th">
|
250 |
-
<div class="col-title">
|
251 |
-
<?php
|
252 |
-
echo $form->label("wpstg_settings[disableAdminLogin]") ?>
|
253 |
-
<span class="description">
|
254 |
-
If you want to remove the requirement to login to the staging site you can deactivate it here.
|
255 |
-
<strong>Note:</strong> The staging site discourages search engines from indexing the site by setting the 'noindex' tag into header of the staging site.
|
256 |
-
</span>
|
257 |
-
</div>
|
258 |
-
</td>
|
259 |
-
<td>
|
260 |
-
<?php
|
261 |
-
echo $form->render("wpstg_settings[disableAdminLogin]") ?>
|
262 |
-
</td>
|
263 |
-
</tr>
|
264 |
-
<?php
|
265 |
-
}
|
266 |
-
?>
|
267 |
-
<?php
|
268 |
-
if (defined('WPSTGPRO_VERSION')) {
|
269 |
-
?>
|
270 |
-
<tr class="row">
|
271 |
-
<td class="row th">
|
272 |
-
<div class="col-title">
|
273 |
-
<?php
|
274 |
-
echo $form->label("wpstg_settings[keepPermalinks]") ?>
|
275 |
-
<span class="description">
|
276 |
-
<?php
|
277 |
-
echo sprintf(
|
278 |
-
__(
|
279 |
-
'Keep permalinks original setting activated and do not disable permalinks on staging site. <br/>Read more: <a href="%1$s" target="_blank">Permalink Settings</a> ',
|
280 |
-
'wp-staging'
|
281 |
-
),
|
282 |
-
'https://wp-staging.com/docs/activate-permalinks-staging-site/'
|
283 |
-
); ?>
|
284 |
-
</span>
|
285 |
-
</div>
|
286 |
-
</td>
|
287 |
-
<td>
|
288 |
-
<?php
|
289 |
-
echo $form->render("wpstg_settings[keepPermalinks]") ?>
|
290 |
-
</td>
|
291 |
-
</tr>
|
292 |
-
<?php
|
293 |
-
}
|
294 |
-
?>
|
295 |
-
<tr class="row">
|
296 |
-
<td class="row th">
|
297 |
-
<div class="col-title">
|
298 |
-
<?php
|
299 |
-
echo $form->label("wpstg_settings[debugMode]") ?>
|
300 |
-
<span class="description">
|
301 |
-
<?php
|
302 |
-
_e(
|
303 |
-
"This will enable an extended debug mode which creates additional entries
|
304 |
-
in <strong>wp-content/uploads/wp-staging/logs/logfile.log</strong>.
|
305 |
-
<strong>Do NOT activate this until we ask you to do so!</strong>",
|
306 |
-
"wp-staging"
|
307 |
-
); ?>
|
308 |
-
</span>
|
309 |
-
</div>
|
310 |
-
</td>
|
311 |
-
<td>
|
312 |
-
<?php
|
313 |
-
echo $form->render("wpstg_settings[debugMode]") ?>
|
314 |
-
</td>
|
315 |
-
</tr>
|
316 |
-
<tr class="row">
|
317 |
-
<td class="row th">
|
318 |
-
<div class="col-title">
|
319 |
-
<?php
|
320 |
-
echo $form->label("wpstg_settings[optimizer]") ?>
|
321 |
-
<span class="description">
|
322 |
-
<?php
|
323 |
-
_e(
|
324 |
-
"The Optimizer is a mu plugin which disables all other plugins during WP Staging processing. Usually this makes the cloning process more reliable. If you experience issues, disable the Optimizer.",
|
325 |
-
"wp-staging"
|
326 |
-
); ?>
|
327 |
-
</span>
|
328 |
-
</div>
|
329 |
-
</td>
|
330 |
-
<td>
|
331 |
-
<?php
|
332 |
-
echo $form->render("wpstg_settings[optimizer]") ?>
|
333 |
-
</td>
|
334 |
-
</tr>
|
335 |
-
|
336 |
-
<tr class="row">
|
337 |
-
<td class="row th">
|
338 |
-
<div class="col-title">
|
339 |
-
<?php
|
340 |
-
echo $form->label("wpstg_settings[unInstallOnDelete]") ?>
|
341 |
-
<span class="description">
|
342 |
-
<?php
|
343 |
-
_e(
|
344 |
-
"Check this box if you like WP Staging to completely remove all of its data when the plugin is deleted.
|
345 |
-
This will not remove staging sites files or database tables.",
|
346 |
-
"wp-staging"
|
347 |
-
); ?>
|
348 |
-
</span>
|
349 |
-
</div>
|
350 |
-
</td>
|
351 |
-
<td>
|
352 |
-
<?php
|
353 |
-
echo $form->render("wpstg_settings[unInstallOnDelete]") ?>
|
354 |
-
</td>
|
355 |
-
</tr>
|
356 |
|
357 |
-
|
358 |
-
|
359 |
-
<div class="col-title">
|
360 |
-
<?php
|
361 |
-
echo $form->label("wpstg_settings[checkDirectorySize]") ?>
|
362 |
-
<span class="description">
|
363 |
-
<?php
|
364 |
-
_e(
|
365 |
-
"Check this box if you like WP Staging to check sizes of each directory on scanning process.
|
366 |
-
<br>
|
367 |
-
Warning this may cause timeout problems in big directory / file structures.",
|
368 |
-
"wp-staging"
|
369 |
-
); ?>
|
370 |
-
</span>
|
371 |
-
</div>
|
372 |
-
</td>
|
373 |
-
<td>
|
374 |
-
<?php
|
375 |
-
echo $form->render("wpstg_settings[checkDirectorySize]") ?>
|
376 |
-
</td>
|
377 |
-
</tr>
|
378 |
-
<?php
|
379 |
-
if (defined('WPSTGPRO_VERSION')) {
|
380 |
-
?>
|
381 |
-
<tr class="row">
|
382 |
-
<td class="row th">
|
383 |
-
<div class="col-title">
|
384 |
-
<?php
|
385 |
-
echo $form->label("wpstg_settings[userRoles][]") ?>
|
386 |
-
<span class="description">
|
387 |
-
<?php
|
388 |
-
_e(
|
389 |
-
'Select the user role you want to give access to the staging site. You can select multiple roles by holding CTRL or ⌘ Cmd key while clicking. <strong>Change this option on the staging site if you want to change the authentication behavior there.</strong>',
|
390 |
-
'wp-staging'
|
391 |
-
); ?>
|
392 |
-
</span>
|
393 |
-
</div>
|
394 |
-
</td>
|
395 |
-
<td>
|
396 |
-
<?php
|
397 |
-
echo $form->render("wpstg_settings[userRoles][]") ?>
|
398 |
-
</td>
|
399 |
-
</tr>
|
400 |
-
<tr class="row">
|
401 |
-
<td class="row th">
|
402 |
-
<div class="col-title">
|
403 |
-
<?php
|
404 |
-
echo $form->label("wpstg_settings[usersWithStagingAccess]") ?>
|
405 |
-
<span class="description">
|
406 |
-
<?php
|
407 |
-
_e(
|
408 |
-
'Specify users who will have access to the staging site regardless of their role. You can enter multiple user names separated by a comma. <strong>Change this option on the staging site if you want to change the authentication behavior there.</strong>',
|
409 |
-
'wp-staging'
|
410 |
-
); ?>
|
411 |
-
</span>
|
412 |
-
</div>
|
413 |
-
</td>
|
414 |
-
<td>
|
415 |
-
<?php
|
416 |
-
echo $form->render("wpstg_settings[usersWithStagingAccess]") ?>
|
417 |
-
</td>
|
418 |
-
</tr>
|
419 |
-
<?php
|
420 |
-
}
|
421 |
-
?>
|
422 |
-
</tbody>
|
423 |
-
</table>
|
424 |
-
</div>
|
425 |
-
<?php
|
426 |
-
endforeach;
|
427 |
-
// Show submit button any tab but add-ons
|
428 |
-
if ($activeTab !== "add-ons") {
|
429 |
-
submit_button();
|
430 |
-
}
|
431 |
-
unset($tabs);
|
432 |
-
?>
|
433 |
-
</form>
|
434 |
</div>
|
435 |
</div>
|
436 |
</div>
|
1 |
<div class="wpstg_admin">
|
2 |
<?php require_once(WPSTG_PLUGIN_DIR . 'Backend/views/_main/header.php'); ?>
|
3 |
|
4 |
+
<div class="wpstg-tabs-container" id="wpstg-settings">
|
5 |
+
<ul class="nav-tab-wrapper">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
<?php
|
7 |
+
$tabs = \WPStaging\Core\WPStaging::getInstance()->get("tabs")->get();
|
8 |
+
$activeTab = (isset($_GET["tab"]) && array_key_exists($_GET["tab"], $tabs)) ? $_GET["tab"] : "general";
|
9 |
+
|
10 |
+
# Loop through tabs
|
11 |
+
foreach ($tabs as $id => $name):
|
12 |
+
$url = esc_url(
|
13 |
+
add_query_arg(
|
14 |
+
[
|
15 |
+
"settings-updated" => false,
|
16 |
+
"tab" => $id
|
17 |
+
]
|
18 |
+
)
|
19 |
+
);
|
20 |
+
|
21 |
+
$activeClass = ($activeTab === $id) ? " nav-tab-active" : '';
|
22 |
+
?>
|
23 |
+
<li>
|
24 |
+
<a href="<?php
|
25 |
+
echo $url ?>" title="<?php
|
26 |
+
echo esc_attr($name) ?>" class="nav-tab<?php
|
27 |
+
echo $activeClass ?>">
|
28 |
+
<?php
|
29 |
+
echo esc_html($name) ?>
|
30 |
+
</a>
|
31 |
+
</li>
|
32 |
<?php
|
33 |
+
unset($url, $activeClass);
|
34 |
+
endforeach;
|
35 |
+
?>
|
36 |
+
</ul>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
37 |
|
38 |
+
<div class="wpstg-metabox-holder">
|
39 |
+
<?php require_once $this->path . "views/settings/tabs/" . $activeTab . ".php"?>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
40 |
</div>
|
41 |
</div>
|
42 |
</div>
|
Backend/views/settings/tabs/general.php
ADDED
@@ -0,0 +1,401 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<!-- General Settings -->
|
2 |
+
<div id="wpstg-tab-container" class="tab_container">
|
3 |
+
<form class="wpstg-settings-panel" method="post" action="options.php">
|
4 |
+
<?php
|
5 |
+
settings_fields("wpstg_settings");
|
6 |
+
|
7 |
+
foreach ($tabs as $id => $name):
|
8 |
+
if ($id === 'mail-settings') {
|
9 |
+
continue;
|
10 |
+
}
|
11 |
+
|
12 |
+
$form = \WPStaging\Core\WPStaging::getInstance()->get("forms")->get($id);
|
13 |
+
|
14 |
+
if ($form === null) {
|
15 |
+
continue;
|
16 |
+
}
|
17 |
+
?>
|
18 |
+
<div id="<?php
|
19 |
+
echo $id ?>__wpstg_header">
|
20 |
+
<table class="wpstg-form-table">
|
21 |
+
<thead>
|
22 |
+
<tr class="row">
|
23 |
+
<th class="row th" colspan="2">
|
24 |
+
<div class="col-title">
|
25 |
+
<strong><?php
|
26 |
+
echo $name ?></strong>
|
27 |
+
<span class="description"></span>
|
28 |
+
</div>
|
29 |
+
</th>
|
30 |
+
</tr>
|
31 |
+
</thead>
|
32 |
+
|
33 |
+
<tbody>
|
34 |
+
<tr class="row">
|
35 |
+
<td class="row th">
|
36 |
+
<div class="col-title">
|
37 |
+
<?php
|
38 |
+
echo $form->label("wpstg_settings[queryLimit]")
|
39 |
+
?>
|
40 |
+
<span class="description">
|
41 |
+
<?php
|
42 |
+
_e(
|
43 |
+
"Number of DB rows, that are copied within one ajax query.
|
44 |
+
The higher the value the faster the database copy process.
|
45 |
+
To find out the highest possible values try a high value like 1.000 or more. If you get timeout issues, lower it
|
46 |
+
until you get no more errors during copying process.",
|
47 |
+
"wp-staging"
|
48 |
+
); ?>
|
49 |
+
<br>
|
50 |
+
<strong> Default: 10000 </strong>
|
51 |
+
</span>
|
52 |
+
</div>
|
53 |
+
</td>
|
54 |
+
<td>
|
55 |
+
<?php
|
56 |
+
echo $form->render("wpstg_settings[queryLimit]") ?>
|
57 |
+
</td>
|
58 |
+
</tr>
|
59 |
+
<tr class="row">
|
60 |
+
<td class="row th">
|
61 |
+
<div class="col-title">
|
62 |
+
<?php
|
63 |
+
echo $form->label("wpstg_settings[querySRLimit]")
|
64 |
+
?>
|
65 |
+
<span class="description">
|
66 |
+
<?php
|
67 |
+
_e(
|
68 |
+
"Number of DB rows, that are processed within one ajax query.
|
69 |
+
The higher the value the faster the database search & replace process.
|
70 |
+
This is a high memory consumptive process. If you get timeouts lower this value!",
|
71 |
+
"wp-staging"
|
72 |
+
); ?>
|
73 |
+
<br>
|
74 |
+
<strong> Default: 5000 </strong>
|
75 |
+
</span>
|
76 |
+
</div>
|
77 |
+
</td>
|
78 |
+
<td>
|
79 |
+
<?php
|
80 |
+
echo $form->render("wpstg_settings[querySRLimit]") ?>
|
81 |
+
</td>
|
82 |
+
</tr>
|
83 |
+
|
84 |
+
<tr class="row">
|
85 |
+
<td class="row th">
|
86 |
+
<div class="col-title">
|
87 |
+
<?php
|
88 |
+
echo $form->label("wpstg_settings[fileLimit]")
|
89 |
+
?>
|
90 |
+
<span class="description">
|
91 |
+
<?php
|
92 |
+
_e(
|
93 |
+
"Number of files to copy that will be copied within one ajax request.
|
94 |
+
The higher the value the faster the file copy process.
|
95 |
+
To find out the highest possible values try a high value like 500 or more. If you get timeout issues, lower it
|
96 |
+
until you get no more errors during copying process.",
|
97 |
+
"wp-staging"
|
98 |
+
); ?>
|
99 |
+
<br>
|
100 |
+
<br>
|
101 |
+
<?php
|
102 |
+
_e(
|
103 |
+
"<strong>Important:</strong> If CPU Load Priority is <strong>Low</strong> set a file copy limit value of 50 or higher! Otherwise file copying process takes a lot of time.",
|
104 |
+
"wp-staging"
|
105 |
+
); ?>
|
106 |
+
<br>
|
107 |
+
<br>
|
108 |
+
<strong> Default: 50 </strong>
|
109 |
+
</span>
|
110 |
+
</div>
|
111 |
+
</td>
|
112 |
+
<td>
|
113 |
+
<?php
|
114 |
+
echo $form->render("wpstg_settings[fileLimit]") ?>
|
115 |
+
</td>
|
116 |
+
</tr>
|
117 |
+
|
118 |
+
<tr class="row">
|
119 |
+
<td class="row th">
|
120 |
+
<div class="col-title">
|
121 |
+
<?php
|
122 |
+
echo $form->label("wpstg_settings[maxFileSize]") ?>
|
123 |
+
<span class="description">
|
124 |
+
<?php
|
125 |
+
_e(
|
126 |
+
"Maximum size of the files which are allowed to copy. All files larger than this value will be skipped.
|
127 |
+
Note: Increase this option only if you have a good reason. Files larger than a few megabytes are in 99% of all cases log and backup files which are not needed on a staging site.",
|
128 |
+
"wp-staging"
|
129 |
+
); ?>
|
130 |
+
<br>
|
131 |
+
<strong>Default:</strong> 8 MB
|
132 |
+
</span>
|
133 |
+
</div>
|
134 |
+
</td>
|
135 |
+
<td>
|
136 |
+
<?php
|
137 |
+
echo $form->render("wpstg_settings[maxFileSize]") ?>
|
138 |
+
</td>
|
139 |
+
</tr>
|
140 |
+
<tr class="row">
|
141 |
+
<td class="row th">
|
142 |
+
<div class="col-title">
|
143 |
+
<?php
|
144 |
+
echo $form->label("wpstg_settings[batchSize]") ?>
|
145 |
+
<span class="description">
|
146 |
+
<?php
|
147 |
+
_e(
|
148 |
+
"Buffer size for the file copy process in megabyte.
|
149 |
+
The higher the value the faster large files are copied.
|
150 |
+
To find out the highest possible values try a high one and lower it until
|
151 |
+
you get no errors during file copy process. Usually this value correlates directly
|
152 |
+
with the memory consumption of php so make sure that
|
153 |
+
it does not exceed any php.ini max_memory limits.",
|
154 |
+
"wp-staging"
|
155 |
+
); ?>
|
156 |
+
<br>
|
157 |
+
<strong>Default:</strong> 2 MB
|
158 |
+
</span>
|
159 |
+
</div>
|
160 |
+
</td>
|
161 |
+
<td>
|
162 |
+
<?php
|
163 |
+
echo $form->render("wpstg_settings[batchSize]") ?>
|
164 |
+
</td>
|
165 |
+
</tr>
|
166 |
+
|
167 |
+
<tr class="row">
|
168 |
+
<td class="row th">
|
169 |
+
<div class="col-title">
|
170 |
+
<?php
|
171 |
+
echo $form->label("wpstg_settings[cpuLoad]") ?>
|
172 |
+
<span class="description">
|
173 |
+
<?php
|
174 |
+
_e(
|
175 |
+
"Using high will result in fast as possible processing but the cpu load
|
176 |
+
increases and it's also possible that staging process gets interrupted because of too many ajax requests
|
177 |
+
(e.g. <strong>authorization error</strong>).
|
178 |
+
Using a lower value results in lower cpu load on your server but also slower staging site creation.",
|
179 |
+
"wp-staging"
|
180 |
+
); ?>
|
181 |
+
<br>
|
182 |
+
<strong>Default: </strong> Low
|
183 |
+
</span>
|
184 |
+
</div>
|
185 |
+
</td>
|
186 |
+
<td>
|
187 |
+
<?php
|
188 |
+
echo $form->render("wpstg_settings[cpuLoad]") ?>
|
189 |
+
</td>
|
190 |
+
</tr>
|
191 |
+
<tr class="row">
|
192 |
+
<td class="row th">
|
193 |
+
<div class="col-title">
|
194 |
+
<?php
|
195 |
+
echo $form->label("wpstg_settings[delayRequests]") ?>
|
196 |
+
<span class="description">
|
197 |
+
<?php
|
198 |
+
_e(
|
199 |
+
"If your server uses rate limits it blocks requests and WP Staging can be interrupted. You can resolve that by adding one or more seconds of delay between the processing requests. ",
|
200 |
+
"wp-staging"
|
201 |
+
); ?>
|
202 |
+
<br>
|
203 |
+
<strong>Default: </strong> 0s
|
204 |
+
</span>
|
205 |
+
</div>
|
206 |
+
</td>
|
207 |
+
<td>
|
208 |
+
<?php
|
209 |
+
echo $form->render("wpstg_settings[delayRequests]") ?>
|
210 |
+
</td>
|
211 |
+
</tr>
|
212 |
+
<?php
|
213 |
+
if (!defined('WPSTGPRO_VERSION')) {
|
214 |
+
?>
|
215 |
+
<tr class="row">
|
216 |
+
<td class="row th">
|
217 |
+
<div class="col-title">
|
218 |
+
<?php
|
219 |
+
echo $form->label("wpstg_settings[disableAdminLogin]") ?>
|
220 |
+
<span class="description">
|
221 |
+
If you want to remove the requirement to login to the staging site you can deactivate it here.
|
222 |
+
<strong>Note:</strong> The staging site discourages search engines from indexing the site by setting the 'noindex' tag into header of the staging site.
|
223 |
+
</span>
|
224 |
+
</div>
|
225 |
+
</td>
|
226 |
+
<td>
|
227 |
+
<?php
|
228 |
+
echo $form->render("wpstg_settings[disableAdminLogin]") ?>
|
229 |
+
</td>
|
230 |
+
</tr>
|
231 |
+
<?php
|
232 |
+
}
|
233 |
+
?>
|
234 |
+
<?php
|
235 |
+
if (defined('WPSTGPRO_VERSION')) {
|
236 |
+
?>
|
237 |
+
<tr class="row">
|
238 |
+
<td class="row th">
|
239 |
+
<div class="col-title">
|
240 |
+
<?php
|
241 |
+
echo $form->label("wpstg_settings[keepPermalinks]") ?>
|
242 |
+
<span class="description">
|
243 |
+
<?php
|
244 |
+
echo sprintf(
|
245 |
+
__(
|
246 |
+
'Keep permalinks original setting activated and do not disable permalinks on staging site. <br/>Read more: <a href="%1$s" target="_blank">Permalink Settings</a> ',
|
247 |
+
'wp-staging'
|
248 |
+
),
|
249 |
+
'https://wp-staging.com/docs/activate-permalinks-staging-site/'
|
250 |
+
); ?>
|
251 |
+
</span>
|
252 |
+
</div>
|
253 |
+
</td>
|
254 |
+
<td>
|
255 |
+
<?php
|
256 |
+
echo $form->render("wpstg_settings[keepPermalinks]") ?>
|
257 |
+
</td>
|
258 |
+
</tr>
|
259 |
+
<?php
|
260 |
+
}
|
261 |
+
?>
|
262 |
+
<tr class="row">
|
263 |
+
<td class="row th">
|
264 |
+
<div class="col-title">
|
265 |
+
<?php
|
266 |
+
echo $form->label("wpstg_settings[debugMode]") ?>
|
267 |
+
<span class="description">
|
268 |
+
<?php
|
269 |
+
_e(
|
270 |
+
"This will enable an extended debug mode which creates additional entries
|
271 |
+
in <strong>wp-content/uploads/wp-staging/logs/logfile.log</strong>.
|
272 |
+
<strong>Do NOT activate this until we ask you to do so!</strong>",
|
273 |
+
"wp-staging"
|
274 |
+
); ?>
|
275 |
+
</span>
|
276 |
+
</div>
|
277 |
+
</td>
|
278 |
+
<td>
|
279 |
+
<?php
|
280 |
+
echo $form->render("wpstg_settings[debugMode]") ?>
|
281 |
+
</td>
|
282 |
+
</tr>
|
283 |
+
<tr class="row">
|
284 |
+
<td class="row th">
|
285 |
+
<div class="col-title">
|
286 |
+
<?php
|
287 |
+
echo $form->label("wpstg_settings[optimizer]") ?>
|
288 |
+
<span class="description">
|
289 |
+
<?php
|
290 |
+
_e(
|
291 |
+
"The Optimizer is a mu plugin which disables all other plugins during WP Staging processing. Usually this makes the cloning process more reliable. If you experience issues, disable the Optimizer.",
|
292 |
+
"wp-staging"
|
293 |
+
); ?>
|
294 |
+
</span>
|
295 |
+
</div>
|
296 |
+
</td>
|
297 |
+
<td>
|
298 |
+
<?php
|
299 |
+
echo $form->render("wpstg_settings[optimizer]") ?>
|
300 |
+
</td>
|
301 |
+
</tr>
|
302 |
+
|
303 |
+
<tr class="row">
|
304 |
+
<td class="row th">
|
305 |
+
<div class="col-title">
|
306 |
+
<?php
|
307 |
+
echo $form->label("wpstg_settings[unInstallOnDelete]") ?>
|
308 |
+
<span class="description">
|
309 |
+
<?php
|
310 |
+
_e(
|
311 |
+
"Check this box if you like WP Staging to completely remove all of its data when the plugin is deleted.
|
312 |
+
This will not remove staging sites files or database tables.",
|
313 |
+
"wp-staging"
|
314 |
+
); ?>
|
315 |
+
</span>
|
316 |
+
</div>
|
317 |
+
</td>
|
318 |
+
<td>
|
319 |
+
<?php
|
320 |
+
echo $form->render("wpstg_settings[unInstallOnDelete]") ?>
|
321 |
+
</td>
|
322 |
+
</tr>
|
323 |
+
|
324 |
+
<tr class="row">
|
325 |
+
<td class="row th">
|
326 |
+
<div class="col-title">
|
327 |
+
<?php
|
328 |
+
echo $form->label("wpstg_settings[checkDirectorySize]") ?>
|
329 |
+
<span class="description">
|
330 |
+
<?php
|
331 |
+
_e(
|
332 |
+
"Check this box if you like WP Staging to check sizes of each directory on scanning process.
|
333 |
+
<br>
|
334 |
+
Warning this may cause timeout problems in big directory / file structures.",
|
335 |
+
"wp-staging"
|
336 |
+
); ?>
|
337 |
+
</span>
|
338 |
+
</div>
|
339 |
+
</td>
|
340 |
+
<td>
|
341 |
+
<?php
|
342 |
+
echo $form->render("wpstg_settings[checkDirectorySize]") ?>
|
343 |
+
</td>
|
344 |
+
</tr>
|
345 |
+
<?php
|
346 |
+
if (defined('WPSTGPRO_VERSION')) {
|
347 |
+
?>
|
348 |
+
<tr class="row">
|
349 |
+
<td class="row th">
|
350 |
+
<div class="col-title">
|
351 |
+
<?php
|
352 |
+
echo $form->label("wpstg_settings[userRoles][]") ?>
|
353 |
+
<span class="description">
|
354 |
+
<?php
|
355 |
+
_e(
|
356 |
+
'Select the user role you want to give access to the staging site. You can select multiple roles by holding CTRL or ⌘ Cmd key while clicking. <strong>Change this option on the staging site if you want to change the authentication behavior there.</strong>',
|
357 |
+
'wp-staging'
|
358 |
+
); ?>
|
359 |
+
</span>
|
360 |
+
</div>
|
361 |
+
</td>
|
362 |
+
<td>
|
363 |
+
<?php
|
364 |
+
echo $form->render("wpstg_settings[userRoles][]") ?>
|
365 |
+
</td>
|
366 |
+
</tr>
|
367 |
+
<tr class="row">
|
368 |
+
<td class="row th">
|
369 |
+
<div class="col-title">
|
370 |
+
<?php
|
371 |
+
echo $form->label("wpstg_settings[usersWithStagingAccess]") ?>
|
372 |
+
<span class="description">
|
373 |
+
<?php
|
374 |
+
_e(
|
375 |
+
'Specify users who will have access to the staging site regardless of their role. You can enter multiple user names separated by a comma. <strong>Change this option on the staging site if you want to change the authentication behavior there.</strong>',
|
376 |
+
'wp-staging'
|
377 |
+
); ?>
|
378 |
+
</span>
|
379 |
+
</div>
|
380 |
+
</td>
|
381 |
+
<td>
|
382 |
+
<?php
|
383 |
+
echo $form->render("wpstg_settings[usersWithStagingAccess]") ?>
|
384 |
+
</td>
|
385 |
+
</tr>
|
386 |
+
<?php
|
387 |
+
}
|
388 |
+
?>
|
389 |
+
</tbody>
|
390 |
+
</table>
|
391 |
+
</div>
|
392 |
+
<?php
|
393 |
+
endforeach;
|
394 |
+
// Show submit button any tab but add-ons
|
395 |
+
if ($activeTab !== "add-ons") {
|
396 |
+
submit_button();
|
397 |
+
}
|
398 |
+
unset($tabs);
|
399 |
+
?>
|
400 |
+
</form>
|
401 |
+
</div>
|
Backend/views/settings/tabs/mail-settings.php
ADDED
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<form class="wpstg-mail-settings-form" method="post">
|
2 |
+
<?php $emailsAllowed = !((bool)get_option(\WPStaging\Framework\Staging\FirstRun::MAILS_DISABLED_KEY, false)); ?>
|
3 |
+
<p>
|
4 |
+
<strong class="wpstg-fs-14"> <?php _e('Mail Delivery Setting', 'wp-staging'); ?></strong>
|
5 |
+
<br/>
|
6 |
+
<?php _e('Toggle mails sending for this staging site', 'wp-staging'); ?>
|
7 |
+
</p>
|
8 |
+
|
9 |
+
<div class="wpstg-form-group">
|
10 |
+
<label class="wpstg-checkbox" for="wpstg_allow_emails">
|
11 |
+
<?php _e('Allow Mails Sending:', 'wp-staging'); ?> <input type="checkbox" name="wpstg_allow_emails" id="wpstg_allow_emails" <?php echo $emailsAllowed === true ? 'checked' : '' ?>>
|
12 |
+
</label>
|
13 |
+
</div>
|
14 |
+
|
15 |
+
<p>
|
16 |
+
<b><?php _e('Note', 'wp-staging') ?>: </b> <?php echo sprintf(__('Some plugins might still be able to send out mails if they don\'t depend upon %s.', 'wp-staging'), '<code>wp_mail()</code>', '<code>wp_mail()</code>', '<strong>WP STAGING</strong>'); ?>
|
17 |
+
</p>
|
18 |
+
|
19 |
+
<button type="button" id="wpstg-update-mail-settings" class="wpstg-link-btn wpstg-blue-primary"><?php _e("Update Settings", "wp-staging") ?></button>
|
20 |
+
</form>
|
Backend/views/tools/index.php
CHANGED
@@ -1,34 +1,34 @@
|
|
1 |
-
|
2 |
-
|
3 |
-
<div class="wrap" id="wpstg-tools">
|
4 |
-
<ul class="nav-tab-wrapper">
|
5 |
-
<?php
|
6 |
-
$tabs = \WPStaging\Core\WPStaging::getInstance()->get("tabs")->get();
|
7 |
-
$activeTab = (isset($_GET["tab"]) && array_key_exists($_GET["tab"], $tabs)) ? $_GET["tab"] : "system_info";
|
8 |
|
9 |
-
|
10 |
-
|
11 |
-
$url = esc_url(add_query_arg([
|
12 |
-
"settings-updated" => false,
|
13 |
-
"tab" => $id
|
14 |
-
]));
|
15 |
-
|
16 |
-
$activeClass = ($activeTab === $id) ? " nav-tab-active" : '';
|
17 |
-
?>
|
18 |
-
<li>
|
19 |
-
<a href="<?php echo $url?>" title="<?php echo esc_attr($name)?>" class="nav-tab<?php echo $activeClass?>">
|
20 |
-
<?php echo esc_html($name)?>
|
21 |
-
</a>
|
22 |
-
</li>
|
23 |
<?php
|
24 |
-
|
25 |
-
|
26 |
-
?>
|
27 |
-
</ul>
|
28 |
|
29 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
|
31 |
-
|
32 |
-
|
|
|
33 |
</div>
|
34 |
</div>
|
1 |
+
<div class="wpstg_admin">
|
2 |
+
<?php require_once(WPSTG_PLUGIN_DIR . 'Backend/views/_main/header.php'); ?>
|
|
|
|
|
|
|
|
|
|
|
3 |
|
4 |
+
<div class="wpstg-tabs-container" id="wpstg-tools">
|
5 |
+
<ul class="nav-tab-wrapper">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
6 |
<?php
|
7 |
+
$tabs = \WPStaging\Core\WPStaging::getInstance()->get("tabs")->get();
|
8 |
+
$activeTab = (isset($_GET["tab"]) && array_key_exists($_GET["tab"], $tabs)) ? $_GET["tab"] : "system_info";
|
|
|
|
|
9 |
|
10 |
+
# Loop through tabs
|
11 |
+
foreach ($tabs as $id => $name):
|
12 |
+
$url = esc_url(add_query_arg([
|
13 |
+
"settings-updated" => false,
|
14 |
+
"tab" => $id
|
15 |
+
]));
|
16 |
+
|
17 |
+
$activeClass = ($activeTab === $id) ? " nav-tab-active" : '';
|
18 |
+
?>
|
19 |
+
<li>
|
20 |
+
<a href="<?php echo $url?>" title="<?php echo esc_attr($name)?>" class="nav-tab<?php echo $activeClass?>">
|
21 |
+
<?php echo esc_html($name)?>
|
22 |
+
</a>
|
23 |
+
</li>
|
24 |
+
<?php
|
25 |
+
unset($url, $activeClass);
|
26 |
+
endforeach;
|
27 |
+
?>
|
28 |
+
</ul>
|
29 |
|
30 |
+
<div class="wpstg-metabox-holder">
|
31 |
+
<?php require_once $this->path . "views/tools/tabs/" . $activeTab . ".php"?>
|
32 |
+
</div>
|
33 |
</div>
|
34 |
</div>
|
Bootstrap/V1/Requirements/WpstgFreeRequirements.php
DELETED
@@ -1,183 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace WPStaging\Bootstrap\V1;
|
4 |
-
|
5 |
-
if (!class_exists(WpstgFreeRequirements::class)) {
|
6 |
-
require_once 'WpstgRequirements.php';
|
7 |
-
|
8 |
-
class WpstgFreeRequirements extends WpstgRequirements
|
9 |
-
{
|
10 |
-
/** @var string */
|
11 |
-
private $proPlugin;
|
12 |
-
|
13 |
-
/** @var string */
|
14 |
-
private $freePlugin;
|
15 |
-
|
16 |
-
public function checkRequirements()
|
17 |
-
{
|
18 |
-
$this->proVersionMustNotBeEnabled();
|
19 |
-
$this->anotherInstanceOfWpstagingMustNotBeEnabled();
|
20 |
-
}
|
21 |
-
|
22 |
-
/**
|
23 |
-
* Prevent conflicts when WP STAGING Pro is active.
|
24 |
-
*/
|
25 |
-
private function proVersionMustNotBeEnabled()
|
26 |
-
{
|
27 |
-
// Early bail: Pro is not loaded, therefore there's no need for further checks.
|
28 |
-
if (!defined('WPSTG_PRO_LOADED')) {
|
29 |
-
return;
|
30 |
-
}
|
31 |
-
|
32 |
-
$this->proPlugin = plugin_basename(WPSTG_PRO_LOADED);
|
33 |
-
$this->freePlugin = plugin_basename($this->pluginFile);
|
34 |
-
|
35 |
-
require_once ABSPATH . 'wp-admin/includes/plugin.php';
|
36 |
-
|
37 |
-
if (is_multisite()) {
|
38 |
-
if (is_network_admin()) {
|
39 |
-
$this->deactivateFreePluginOnMultisiteNetworkLevel();
|
40 |
-
} else {
|
41 |
-
$this->deactivateFreeOrProPluginOnMultisite();
|
42 |
-
}
|
43 |
-
} else {
|
44 |
-
$this->deactivateFreePluginIfProIsActiveOnSingleSite();
|
45 |
-
}
|
46 |
-
}
|
47 |
-
|
48 |
-
/**
|
49 |
-
* Catch-all to prevent conflicts when another instance of WP STAGING is active.
|
50 |
-
*/
|
51 |
-
private function anotherInstanceOfWpstagingMustNotBeEnabled()
|
52 |
-
{
|
53 |
-
$oldVersionsLoaded = defined('WPSTG_PLUGIN_DIR') || defined('WPSTG_PLUGIN_FILE');
|
54 |
-
$proVersionLoaded = defined('WPSTG_PRO_LOADED');
|
55 |
-
$anotherFreeVersionLoaded = defined('WPSTG_FREE_LOADED') && $this->pluginFile !== WPSTG_FREE_LOADED;
|
56 |
-
|
57 |
-
if ($oldVersionsLoaded || $proVersionLoaded || $anotherFreeVersionLoaded) {
|
58 |
-
$this->notificationMessage = __('Another instance of WP STAGING is activated, therefore other instances of WP STAGING were automatically prevented from running to avoid errors. Please leave only one instance of the WP STAGING plugin active.', 'wp-staging');
|
59 |
-
|
60 |
-
if (is_network_admin() && current_user_can('manage_network_plugins')) {
|
61 |
-
add_action('network_admin_notices', [$this, '_displayWarning']);
|
62 |
-
} elseif (!is_network_admin() && current_user_can('activate_plugins')) {
|
63 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
64 |
-
} elseif (!is_network_admin() && !current_user_can('activate_plugins')) {
|
65 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
66 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
67 |
-
}
|
68 |
-
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG === true) {
|
69 |
-
throw new \RuntimeException(sprintf("Another instance of WP STAGING is activated, therefore other instances of WP STAGING were automatically prevented from running to avoid errors. Please leave only one instance of the WP STAGING plugin active. Plugin that was prevented from loading: %s", $this->pluginFile));
|
70 |
-
}
|
71 |
-
}
|
72 |
-
}
|
73 |
-
|
74 |
-
/**
|
75 |
-
* Pro active
|
76 |
-
* Free active
|
77 |
-
*
|
78 |
-
* Result: Deactivate Free
|
79 |
-
*/
|
80 |
-
private function deactivateFreePluginIfProIsActiveOnSingleSite()
|
81 |
-
{
|
82 |
-
if (is_plugin_active($this->proPlugin)) {
|
83 |
-
if (current_user_can('deactivate_plugin', $this->freePlugin)) {
|
84 |
-
unset($_GET['activate']);
|
85 |
-
deactivate_plugins($this->freePlugin);
|
86 |
-
|
87 |
-
$this->notificationMessage = __('WP STAGING Pro is activated, therefore WP STAGING Basic was automatically disabled.', 'wp-staging');
|
88 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
89 |
-
|
90 |
-
throw new \RuntimeException(sprintf("WP STAGING Pro is activated, therefore WP STAGING Basic was automatically disabled. Pro version that was active: %s, Basic version that was disabled: %s", $this->proPlugin, $this->freePlugin));
|
91 |
-
}
|
92 |
-
|
93 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
94 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
95 |
-
|
96 |
-
throw new \RuntimeException(sprintf('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Plugin that was loaded: %s, Plugin that was prevented from loading: %s', $this->freePlugin, $this->proPlugin));
|
97 |
-
}
|
98 |
-
}
|
99 |
-
|
100 |
-
private function deactivateFreeOrProPluginOnMultisite()
|
101 |
-
{
|
102 |
-
/*
|
103 |
-
* Pro active site-level
|
104 |
-
* Free active site-level
|
105 |
-
* Free deactivated network-level
|
106 |
-
*
|
107 |
-
* Result: Deactivate Free site-level
|
108 |
-
*/
|
109 |
-
if (
|
110 |
-
is_plugin_active($this->proPlugin) &&
|
111 |
-
is_plugin_active($this->freePlugin) &&
|
112 |
-
!is_plugin_active_for_network($this->freePlugin)
|
113 |
-
) {
|
114 |
-
if (current_user_can('deactivate_plugin', $this->freePlugin)) {
|
115 |
-
unset($_GET['activate']);
|
116 |
-
deactivate_plugins($this->freePlugin);
|
117 |
-
|
118 |
-
$this->notificationMessage = __('WP STAGING Pro is activated, therefore WP STAGING Basic was automatically disabled.', 'wp-staging');
|
119 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
120 |
-
|
121 |
-
throw new \RuntimeException(sprintf("WP STAGING Pro is activated, therefore WP STAGING Basic was automatically disabled. Pro version that was active: %s, Basic version that was disabled: %s", $this->proPlugin, $this->freePlugin));
|
122 |
-
}
|
123 |
-
|
124 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
125 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
126 |
-
|
127 |
-
throw new \RuntimeException(sprintf('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Plugin that was loaded: %s, Plugin that was prevented from loading: %s', $this->freePlugin, $this->proPlugin));
|
128 |
-
}
|
129 |
-
|
130 |
-
/*
|
131 |
-
* Pro active site-level
|
132 |
-
* Free active network-level
|
133 |
-
*
|
134 |
-
* Result: Deactivate Pro site-level
|
135 |
-
*/
|
136 |
-
if (
|
137 |
-
is_plugin_active($this->proPlugin) &&
|
138 |
-
is_plugin_active_for_network($this->freePlugin)
|
139 |
-
) {
|
140 |
-
if (current_user_can('deactivate_plugin', $this->proPlugin)) {
|
141 |
-
unset($_GET['activate']);
|
142 |
-
deactivate_plugins($this->proPlugin);
|
143 |
-
|
144 |
-
$this->notificationMessage = __('WP STAGING Basic is activated network-wide, therefore WP STAGING Pro was automatically disabled. Please disable WP STAGING Basic network-wide to enable WP STAGING Pro.', 'wp-staging');
|
145 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
146 |
-
|
147 |
-
throw new \RuntimeException(sprintf("WP STAGING Basic is activated networkwide, therefore WP STAGING Pro was automatically disabled. Basic version that was activate networkwide: %s, Pro version that was disabled: %s", $this->freePlugin, $this->proPlugin));
|
148 |
-
}
|
149 |
-
|
150 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
151 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
152 |
-
|
153 |
-
throw new \RuntimeException(sprintf('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Plugin that was loaded: %s, Plugin that was prevented from loading: %s', $this->freePlugin, $this->proPlugin));
|
154 |
-
}
|
155 |
-
}
|
156 |
-
|
157 |
-
/*
|
158 |
-
* Pro active network-level
|
159 |
-
* Free active network-level
|
160 |
-
*
|
161 |
-
* Result: Deactivate Free network-level
|
162 |
-
*/
|
163 |
-
private function deactivateFreePluginOnMultisiteNetworkLevel()
|
164 |
-
{
|
165 |
-
if (is_plugin_active_for_network($this->proPlugin)) {
|
166 |
-
if (current_user_can('manage_network_plugins')) {
|
167 |
-
unset($_GET['activate']);
|
168 |
-
deactivate_plugins($this->freePlugin, null, true);
|
169 |
-
|
170 |
-
$this->notificationMessage = __('WP STAGING Pro is activated network-wide, therefore WP STAGING Basic was disabled network-wide.', 'wp-staging');
|
171 |
-
add_action('network_admin_notices', [$this, '_displayWarning']);
|
172 |
-
|
173 |
-
throw new \RuntimeException(sprintf("WP STAGING Pro is activated networkwide, therefore WP STAGING Basic networkwide was automatically disabled. Pro version that was activate networkwide: %s, Basic version that was disabled networkwide: %s", $this->proPlugin, $this->freePlugin));
|
174 |
-
}
|
175 |
-
|
176 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
177 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
178 |
-
|
179 |
-
throw new \RuntimeException(sprintf('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Plugin that was loaded: %s, Plugin that was prevented from loading: %s', $this->freePlugin, $this->proPlugin));
|
180 |
-
}
|
181 |
-
}
|
182 |
-
}
|
183 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bootstrap/V1/Requirements/WpstgProRequirements.php
DELETED
@@ -1,40 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace WPStaging\Bootstrap\V1;
|
4 |
-
|
5 |
-
if (!class_exists(WpstgProRequirements::class)) {
|
6 |
-
require_once 'WpstgRequirements.php';
|
7 |
-
|
8 |
-
class WpstgProRequirements extends WpstgRequirements
|
9 |
-
{
|
10 |
-
public function checkRequirements()
|
11 |
-
{
|
12 |
-
$this->anotherInstanceOfWpstagingMustNotBeEnabled();
|
13 |
-
}
|
14 |
-
|
15 |
-
/**
|
16 |
-
* Catch-all to prevent conflicts when another instance of WPSTAGING is active.
|
17 |
-
*/
|
18 |
-
private function anotherInstanceOfWpstagingMustNotBeEnabled()
|
19 |
-
{
|
20 |
-
$oldVersionsLoaded = defined('WPSTG_PLUGIN_DIR') || defined('WPSTG_PLUGIN_FILE');
|
21 |
-
$anotherProVersionLoaded = defined('WPSTG_PRO_LOADED') && $this->pluginFile !== WPSTG_PRO_LOADED;
|
22 |
-
|
23 |
-
if ($oldVersionsLoaded || $anotherProVersionLoaded) {
|
24 |
-
$this->notificationMessage = __('Another instance of WP STAGING is activated, therefore other instances of WP STAGING were automatically prevented from running to avoid errors. Please leave only one instance of the WP STAGING plugin active.', 'wp-staging');
|
25 |
-
|
26 |
-
if (is_network_admin() && current_user_can('manage_network_plugins')) {
|
27 |
-
add_action('network_admin_notices', [$this, '_displayWarning']);
|
28 |
-
} elseif (!is_network_admin() && current_user_can('activate_plugins')) {
|
29 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
30 |
-
} elseif (!is_network_admin() && !current_user_can('activate_plugins')) {
|
31 |
-
$this->notificationMessage = __('Another instance of WP STAGING was activated, therefore other instances of the WP STAGING plugin were prevented from loading. Please ask the site administrator to leave only one instance of WP STAGING active.', 'wp-staging');
|
32 |
-
add_action('admin_notices', [$this, '_displayWarning']);
|
33 |
-
}
|
34 |
-
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG === true){
|
35 |
-
throw new \RuntimeException(sprintf("Another instance of WP STAGING is activated, therefore other instances of WP STAGING were automatically prevented from running to avoid errors. Please leave only one instance of the WP STAGING plugin active. Plugin that was prevented from loading: %s", $this->pluginFile));
|
36 |
-
}
|
37 |
-
}
|
38 |
-
}
|
39 |
-
}
|
40 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bootstrap/V1/Requirements/WpstgRequirements.php
DELETED
@@ -1,36 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace WPStaging\Bootstrap\V1;
|
4 |
-
|
5 |
-
if (!class_exists(WpstgRequirements::class)) {
|
6 |
-
abstract class WpstgRequirements
|
7 |
-
{
|
8 |
-
protected $notificationTitle = '';
|
9 |
-
protected $notificationMessage = '';
|
10 |
-
protected $pluginFile;
|
11 |
-
|
12 |
-
public function __construct($pluginFile)
|
13 |
-
{
|
14 |
-
$this->pluginFile = $pluginFile;
|
15 |
-
}
|
16 |
-
|
17 |
-
abstract public function checkRequirements();
|
18 |
-
|
19 |
-
public function _displayWarning()
|
20 |
-
{
|
21 |
-
$title = esc_html($this->notificationTitle ?: __('WP STAGING', 'wp-staging'));
|
22 |
-
$message = wp_kses_post($this->notificationMessage);
|
23 |
-
|
24 |
-
echo <<<MESSAGE
|
25 |
-
<div class="notice-warning notice is-dismissible">
|
26 |
-
<p style="font-weight: bold;">$title</p>
|
27 |
-
<p>$message</p>
|
28 |
-
</div>
|
29 |
-
MESSAGE;
|
30 |
-
|
31 |
-
// Cleanup the state.
|
32 |
-
$this->notificationTitle = '';
|
33 |
-
$this->notificationMessage = '';
|
34 |
-
}
|
35 |
-
}
|
36 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bootstrap/V1/WpstgBootstrap.php
DELETED
@@ -1,61 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace WPStaging\Bootstrap\V1;
|
4 |
-
|
5 |
-
if (!class_exists(WpstgBootstrap::class)) {
|
6 |
-
abstract class WpstgBootstrap
|
7 |
-
{
|
8 |
-
private $shouldBootstrap = true;
|
9 |
-
private $rootPath;
|
10 |
-
private $requirements;
|
11 |
-
|
12 |
-
/**
|
13 |
-
* WpstgBootstrap constructor.
|
14 |
-
*
|
15 |
-
* @param string $rootPath
|
16 |
-
* @param WpstgRequirements $requirements
|
17 |
-
*/
|
18 |
-
public function __construct($rootPath, WpstgRequirements $requirements)
|
19 |
-
{
|
20 |
-
$this->rootPath = $rootPath;
|
21 |
-
$this->requirements = $requirements;
|
22 |
-
}
|
23 |
-
|
24 |
-
abstract protected function afterBootstrap();
|
25 |
-
|
26 |
-
public function checkRequirements()
|
27 |
-
{
|
28 |
-
try {
|
29 |
-
$this->requirements->checkRequirements();
|
30 |
-
} catch (\Exception $e) {
|
31 |
-
$this->shouldBootstrap = false;
|
32 |
-
|
33 |
-
if (defined('WP_DEBUG') && WP_DEBUG) {
|
34 |
-
error_log(sprintf("[Activation] WP STAGING: %s", $e->getMessage()));
|
35 |
-
}
|
36 |
-
}
|
37 |
-
}
|
38 |
-
|
39 |
-
public function bootstrap()
|
40 |
-
{
|
41 |
-
// Early bail: Requirements not met.
|
42 |
-
if (!$this->shouldBootstrap) {
|
43 |
-
return;
|
44 |
-
}
|
45 |
-
|
46 |
-
if (file_exists(__DIR__ . '/../autoloader_dev.php')) {
|
47 |
-
require_once __DIR__ . '/../autoloader_dev.php';
|
48 |
-
} else {
|
49 |
-
require_once __DIR__ . '/../autoloader.php';
|
50 |
-
}
|
51 |
-
|
52 |
-
$this->afterBootstrap();
|
53 |
-
}
|
54 |
-
|
55 |
-
public function passedRequirements()
|
56 |
-
{
|
57 |
-
return $this->shouldBootstrap;
|
58 |
-
}
|
59 |
-
}
|
60 |
-
}
|
61 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Component/Job/AbstractJob.php
CHANGED
@@ -1,8 +1,5 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
// If child class has `init` method, it will be executed with constructor to prepare the class for job execution
|
4 |
-
// Such as setting -if needed- total steps, current step etc.
|
5 |
-
|
6 |
namespace WPStaging\Component\Job;
|
7 |
|
8 |
use WPStaging\Component\Task\TaskResponseDto;
|
1 |
<?php
|
2 |
|
|
|
|
|
|
|
3 |
namespace WPStaging\Component\Job;
|
4 |
|
5 |
use WPStaging\Component\Task\TaskResponseDto;
|
Component/Job/AbstractQueueJob.php
CHANGED
@@ -10,15 +10,13 @@ use WPStaging\Component\Task\TaskInterface;
|
|
10 |
use WPStaging\Component\Task\TaskResponseDto;
|
11 |
use WPStaging\Framework\Queue\Queue;
|
12 |
use WPStaging\Framework\Queue\Storage\CacheStorage;
|
13 |
-
use WPStaging\Framework\Queue\Storage\StorageInterface;
|
14 |
use WPStaging\Framework\Utils\Cache\Cache;
|
15 |
-
use WPStaging\Repository\SettingsRepository;
|
16 |
use WPStaging\Core\WPStaging;
|
17 |
|
18 |
abstract class AbstractQueueJob extends AbstractJob
|
19 |
{
|
20 |
/** @var Cache */
|
21 |
-
|
22 |
|
23 |
/** @var QueueJobDto */
|
24 |
protected $dto;
|
@@ -26,17 +24,20 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
26 |
/** @var Queue */
|
27 |
protected $queue;
|
28 |
|
|
|
|
|
|
|
|
|
|
|
29 |
/** @var TaskInterface */
|
30 |
protected $currentTask;
|
31 |
|
32 |
-
public function __construct()
|
33 |
{
|
34 |
-
$this->
|
35 |
-
|
36 |
-
$this->
|
37 |
-
$this->
|
38 |
-
$this->cache->setFilename('job_' . $this->getJobName());
|
39 |
-
$this->cache->setPath(trailingslashit($this->cache->getPath() . $this->getJobName()));
|
40 |
|
41 |
$this->setUp();
|
42 |
}
|
@@ -49,10 +50,11 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
49 |
|
50 |
if ($this->dto->isFinished()) {
|
51 |
$this->clean();
|
|
|
52 |
return;
|
53 |
}
|
54 |
|
55 |
-
$this->
|
56 |
}
|
57 |
|
58 |
abstract protected function initiateTasks();
|
@@ -71,14 +73,6 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
71 |
$this->queue->reset();
|
72 |
}
|
73 |
|
74 |
-
/**
|
75 |
-
* @return string
|
76 |
-
*/
|
77 |
-
protected function getDtoClass()
|
78 |
-
{
|
79 |
-
return QueueJobDto::class;
|
80 |
-
}
|
81 |
-
|
82 |
protected function prepare()
|
83 |
{
|
84 |
if (method_exists($this, 'provideRequestDto')) {
|
@@ -94,18 +88,21 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
94 |
|
95 |
protected function setUp()
|
96 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
if (!empty($_POST['reset']) && ($_POST['reset'] === true || $_POST['reset'] === 'true')) {
|
98 |
/** @noinspection DynamicInvocationViaScopeResolutionInspection */
|
99 |
AbstractJob::clean();
|
100 |
}
|
101 |
|
102 |
-
$dtoClass = $this->getDtoClass();
|
103 |
-
/** @var QueueJobDto $dto */
|
104 |
-
$this->dto = (new $dtoClass);
|
105 |
$this->dto->setInit(true);
|
106 |
$this->dto->setFinished(false);
|
107 |
|
108 |
-
$data = $this->
|
109 |
if ($data) {
|
110 |
$this->dto->hydrate($data);
|
111 |
}
|
@@ -138,31 +135,18 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
138 |
}
|
139 |
$this->currentTask->setJobId($this->dto->getId());
|
140 |
$this->currentTask->setJobName($this->getJobName());
|
141 |
-
|
142 |
-
/** @var SettingsRepository $repoSettings */
|
143 |
-
$repoSettings = WPStaging::getInstance()->get(SettingsRepository::class);
|
144 |
-
$settings = $repoSettings->find();
|
145 |
-
$this->currentTask->setDebug($settings ? $settings->isDebug() : false);
|
146 |
}
|
147 |
|
148 |
protected function setQueue()
|
149 |
{
|
150 |
-
$this->queue = new Queue;
|
151 |
$this->queue->setName($this->findCurrentJob());
|
152 |
-
$this->queue->setStorage($this->provideQueueStorage());
|
153 |
-
}
|
154 |
|
155 |
-
|
156 |
-
|
157 |
-
|
158 |
-
|
159 |
-
|
160 |
-
/** @var CacheStorage $cacheStorage */
|
161 |
-
$cacheStorage = WPStaging::getInstance()->get(CacheStorage::class);
|
162 |
-
$cache = $cacheStorage->getCache();
|
163 |
-
/** @noinspection NullPointerExceptionInspection */
|
164 |
-
$cache->setPath(trailingslashit($cache->getPath() . $this->getJobName()));
|
165 |
-
return $cacheStorage;
|
166 |
}
|
167 |
|
168 |
protected function addTasks(array $tasks = [])
|
@@ -189,10 +173,12 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
189 |
|
190 |
if ($response->isStatus() && $this->queue->count() === 0) {
|
191 |
$this->dto->setFinished(true);
|
|
|
192 |
return $response;
|
193 |
}
|
194 |
|
195 |
$response->setStatus(false);
|
|
|
196 |
return $response;
|
197 |
}
|
198 |
|
@@ -213,9 +199,9 @@ abstract class AbstractQueueJob extends AbstractJob
|
|
213 |
return;
|
214 |
}
|
215 |
|
216 |
-
$args
|
217 |
$title = $this->currentTask->getStatusTitle($args);
|
218 |
$this->dto->setCurrentStatusTitle($title);
|
219 |
-
$this->
|
220 |
}
|
221 |
}
|
10 |
use WPStaging\Component\Task\TaskResponseDto;
|
11 |
use WPStaging\Framework\Queue\Queue;
|
12 |
use WPStaging\Framework\Queue\Storage\CacheStorage;
|
|
|
13 |
use WPStaging\Framework\Utils\Cache\Cache;
|
|
|
14 |
use WPStaging\Core\WPStaging;
|
15 |
|
16 |
abstract class AbstractQueueJob extends AbstractJob
|
17 |
{
|
18 |
/** @var Cache */
|
19 |
+
private $jobCache;
|
20 |
|
21 |
/** @var QueueJobDto */
|
22 |
protected $dto;
|
24 |
/** @var Queue */
|
25 |
protected $queue;
|
26 |
|
27 |
+
/**
|
28 |
+
* @var CacheStorage $queueCache Controls the cache file for the queue.
|
29 |
+
*/
|
30 |
+
protected $queueCache;
|
31 |
+
|
32 |
/** @var TaskInterface */
|
33 |
protected $currentTask;
|
34 |
|
35 |
+
public function __construct(Cache $jobCache, Queue $queue, CacheStorage $queueCache, QueueJobDto $dto)
|
36 |
{
|
37 |
+
$this->queue = $queue;
|
38 |
+
$this->jobCache = $jobCache;
|
39 |
+
$this->queueCache = $queueCache;
|
40 |
+
$this->dto = $dto;
|
|
|
|
|
41 |
|
42 |
$this->setUp();
|
43 |
}
|
50 |
|
51 |
if ($this->dto->isFinished()) {
|
52 |
$this->clean();
|
53 |
+
|
54 |
return;
|
55 |
}
|
56 |
|
57 |
+
$this->jobCache->save($this->dto->toArray());
|
58 |
}
|
59 |
|
60 |
abstract protected function initiateTasks();
|
73 |
$this->queue->reset();
|
74 |
}
|
75 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
76 |
protected function prepare()
|
77 |
{
|
78 |
if (method_exists($this, 'provideRequestDto')) {
|
88 |
|
89 |
protected function setUp()
|
90 |
{
|
91 |
+
$this->setQueue();
|
92 |
+
|
93 |
+
$this->jobCache->setLifetime(HOUR_IN_SECONDS);
|
94 |
+
$this->jobCache->setFilename('job_' . $this->getJobName());
|
95 |
+
$this->jobCache->setPath(trailingslashit($this->jobCache->getPath() . $this->getJobName()));
|
96 |
+
|
97 |
if (!empty($_POST['reset']) && ($_POST['reset'] === true || $_POST['reset'] === 'true')) {
|
98 |
/** @noinspection DynamicInvocationViaScopeResolutionInspection */
|
99 |
AbstractJob::clean();
|
100 |
}
|
101 |
|
|
|
|
|
|
|
102 |
$this->dto->setInit(true);
|
103 |
$this->dto->setFinished(false);
|
104 |
|
105 |
+
$data = $this->jobCache->get([]);
|
106 |
if ($data) {
|
107 |
$this->dto->hydrate($data);
|
108 |
}
|
135 |
}
|
136 |
$this->currentTask->setJobId($this->dto->getId());
|
137 |
$this->currentTask->setJobName($this->getJobName());
|
138 |
+
$this->currentTask->setDebug(defined('WPSTG_DEBUG') && WPSTG_DEBUG);
|
|
|
|
|
|
|
|
|
139 |
}
|
140 |
|
141 |
protected function setQueue()
|
142 |
{
|
|
|
143 |
$this->queue->setName($this->findCurrentJob());
|
|
|
|
|
144 |
|
145 |
+
$this->queueCache->getCache()->setPath(
|
146 |
+
trailingslashit($this->queueCache->getCache()->getPath() . $this->getJobName())
|
147 |
+
);
|
148 |
+
|
149 |
+
$this->queue->setStorage($this->queueCache);
|
|
|
|
|
|
|
|
|
|
|
|
|
150 |
}
|
151 |
|
152 |
protected function addTasks(array $tasks = [])
|
173 |
|
174 |
if ($response->isStatus() && $this->queue->count() === 0) {
|
175 |
$this->dto->setFinished(true);
|
176 |
+
|
177 |
return $response;
|
178 |
}
|
179 |
|
180 |
$response->setStatus(false);
|
181 |
+
|
182 |
return $response;
|
183 |
}
|
184 |
|
199 |
return;
|
200 |
}
|
201 |
|
202 |
+
$args = $this->findCurrentStatusTitleArgs();
|
203 |
$title = $this->currentTask->getStatusTitle($args);
|
204 |
$this->dto->setCurrentStatusTitle($title);
|
205 |
+
$this->jobCache->save($this->dto->toArray());
|
206 |
}
|
207 |
}
|
Component/Job/QueueJobDto.php
CHANGED
@@ -4,7 +4,7 @@ namespace WPStaging\Component\Job;
|
|
4 |
|
5 |
use WPStaging\Component\Dto\AbstractDto;
|
6 |
|
7 |
-
class QueueJobDto extends AbstractDto
|
8 |
{
|
9 |
/** @var string|int|null */
|
10 |
protected $id;
|
@@ -100,4 +100,4 @@ class QueueJobDto extends AbstractDto
|
|
100 |
{
|
101 |
$this->currentStatusTitle = $currentStatusTitle;
|
102 |
}
|
103 |
-
}
|
4 |
|
5 |
use WPStaging\Component\Dto\AbstractDto;
|
6 |
|
7 |
+
abstract class QueueJobDto extends AbstractDto
|
8 |
{
|
9 |
/** @var string|int|null */
|
10 |
protected $id;
|
100 |
{
|
101 |
$this->currentStatusTitle = $currentStatusTitle;
|
102 |
}
|
103 |
+
}
|
Component/Task/Filesystem/DirectoryScannerRequestDto.php
CHANGED
@@ -10,20 +10,20 @@ use WPStaging\Component\Dto\AbstractRequestDto;
|
|
10 |
class DirectoryScannerRequestDto extends AbstractRequestDto
|
11 |
{
|
12 |
/** @var array */
|
13 |
-
private $included;
|
14 |
|
15 |
/** @var array */
|
16 |
-
private $excluded;
|
17 |
|
18 |
/**
|
19 |
* @return array
|
20 |
*/
|
21 |
public function getIncluded()
|
22 |
{
|
23 |
-
return $this->included;
|
24 |
}
|
25 |
|
26 |
-
public function setIncluded(array $included =
|
27 |
{
|
28 |
$this->included = $included;
|
29 |
}
|
@@ -33,7 +33,7 @@ class DirectoryScannerRequestDto extends AbstractRequestDto
|
|
33 |
*/
|
34 |
public function getExcluded()
|
35 |
{
|
36 |
-
return $this->excluded;
|
37 |
}
|
38 |
|
39 |
public function setExcluded(array $excluded = null)
|
@@ -41,6 +41,6 @@ class DirectoryScannerRequestDto extends AbstractRequestDto
|
|
41 |
// $this->excluded = array_map(static function($dir) {
|
42 |
// return str_replace(ABSPATH, null, $dir);
|
43 |
// }, $excluded);
|
44 |
-
$this->excluded = $excluded;
|
45 |
}
|
46 |
}
|
10 |
class DirectoryScannerRequestDto extends AbstractRequestDto
|
11 |
{
|
12 |
/** @var array */
|
13 |
+
private $included = [];
|
14 |
|
15 |
/** @var array */
|
16 |
+
private $excluded = [];
|
17 |
|
18 |
/**
|
19 |
* @return array
|
20 |
*/
|
21 |
public function getIncluded()
|
22 |
{
|
23 |
+
return (array)$this->included;
|
24 |
}
|
25 |
|
26 |
+
public function setIncluded(array $included = [])
|
27 |
{
|
28 |
$this->included = $included;
|
29 |
}
|
33 |
*/
|
34 |
public function getExcluded()
|
35 |
{
|
36 |
+
return (array)$this->excluded;
|
37 |
}
|
38 |
|
39 |
public function setExcluded(array $excluded = null)
|
41 |
// $this->excluded = array_map(static function($dir) {
|
42 |
// return str_replace(ABSPATH, null, $dir);
|
43 |
// }, $excluded);
|
44 |
+
$this->excluded = (array)$excluded;
|
45 |
}
|
46 |
}
|
Component/Task/Filesystem/DirectoryScannerTask.php
CHANGED
@@ -14,8 +14,15 @@ use WPStaging\Framework\Queue\FinishedQueueException;
|
|
14 |
use WPStaging\Framework\Traits\ResourceTrait;
|
15 |
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
16 |
use WPStaging\Framework\Utils\Cache\Cache;
|
17 |
-
use WPStaging\Framework\Filesystem\
|
18 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
class DirectoryScannerTask extends AbstractTask
|
20 |
{
|
21 |
use ResourceTrait;
|
@@ -28,8 +35,8 @@ class DirectoryScannerTask extends AbstractTask
|
|
28 |
/** @var DirectoryScannerRequestDto */
|
29 |
public $requestDto;
|
30 |
|
31 |
-
/** @var
|
32 |
-
private $
|
33 |
|
34 |
/** @var BufferedCache */
|
35 |
private $directoryCache;
|
@@ -37,17 +44,17 @@ class DirectoryScannerTask extends AbstractTask
|
|
37 |
/** @var array */
|
38 |
private $directories;
|
39 |
|
40 |
-
public function __construct(
|
41 |
{
|
42 |
parent::__construct($logger, $cache);
|
43 |
$this->directories = [];
|
44 |
|
45 |
-
$
|
46 |
-
$this->
|
47 |
|
48 |
-
$this->directoryCache = clone $
|
49 |
$this->directoryCache->setLifetime(DAY_IN_SECONDS);
|
50 |
-
$this->directoryCache->setFilename(
|
51 |
}
|
52 |
|
53 |
public function __destruct()
|
@@ -109,7 +116,7 @@ class DirectoryScannerTask extends AbstractTask
|
|
109 |
{
|
110 |
$directories = null;
|
111 |
try {
|
112 |
-
$directories = $this->
|
113 |
} catch (FinishedQueueException $e) {
|
114 |
$this->logger->info('Finished scanning directories');
|
115 |
$this->requestDto->getSteps()->finish();
|
@@ -121,7 +128,7 @@ class DirectoryScannerTask extends AbstractTask
|
|
121 |
}
|
122 |
|
123 |
// No directories found here, skip it
|
124 |
-
if ($directories
|
125 |
return;
|
126 |
}
|
127 |
|
@@ -129,10 +136,11 @@ class DirectoryScannerTask extends AbstractTask
|
|
129 |
if ($this->isThreshold()) {
|
130 |
return;
|
131 |
}
|
132 |
-
$relativePath = str_replace(ABSPATH, null, $directory
|
133 |
-
$this->
|
134 |
$this->directories[] = $relativePath;
|
135 |
}
|
|
|
136 |
}
|
137 |
|
138 |
protected function findRequestDto()
|
@@ -152,8 +160,8 @@ class DirectoryScannerTask extends AbstractTask
|
|
152 |
}, $this->requestDto->getIncluded());
|
153 |
|
154 |
/** @noinspection NullPointerExceptionInspection */
|
155 |
-
if ($this->
|
156 |
-
$this->
|
157 |
}
|
158 |
|
159 |
$totalSteps = count($this->requestDto->getIncluded());
|
@@ -166,10 +174,9 @@ class DirectoryScannerTask extends AbstractTask
|
|
166 |
// There is no need to backup WP Staging as you shouldn't restore WPSTG backup without WPSTG having installed
|
167 |
// Don't backup / restore cache as it can be problematic
|
168 |
$excludedDirs = $this->requestDto->getExcluded();
|
169 |
-
|
170 |
-
|
171 |
-
|
172 |
-
$adapter = $this->scanner->getService()->getDirectory();
|
173 |
$excludedDirs[] = WPSTG_PLUGIN_DIR;
|
174 |
$excludedDirs[] = $adapter->getPluginUploadsDirectory();
|
175 |
$excludedDirs[] = WP_CONTENT_DIR . '/cache';
|
@@ -180,9 +187,9 @@ class DirectoryScannerTask extends AbstractTask
|
|
180 |
{
|
181 |
$caches = parent::getCaches();
|
182 |
$caches[] = $this->directoryCache;
|
183 |
-
$caches[] = $this->
|
184 |
/** @noinspection NullPointerExceptionInspection */
|
185 |
-
$caches[] = $this->
|
186 |
return $caches;
|
187 |
}
|
188 |
|
@@ -201,7 +208,7 @@ class DirectoryScannerTask extends AbstractTask
|
|
201 |
$steps->setTotal($steps->getTotal() + count($this->directories));
|
202 |
|
203 |
/** @noinspection NullPointerExceptionInspection */
|
204 |
-
if ($this->
|
205 |
return;
|
206 |
}
|
207 |
|
14 |
use WPStaging\Framework\Traits\ResourceTrait;
|
15 |
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
16 |
use WPStaging\Framework\Utils\Cache\Cache;
|
17 |
+
use WPStaging\Framework\Filesystem\DirectoryScannerControl;
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Class DirectoryScannerTask
|
21 |
+
*
|
22 |
+
* @see DirectoryScannerControl
|
23 |
+
*
|
24 |
+
* @package WPStaging\Component\Task\Filesystem
|
25 |
+
*/
|
26 |
class DirectoryScannerTask extends AbstractTask
|
27 |
{
|
28 |
use ResourceTrait;
|
35 |
/** @var DirectoryScannerRequestDto */
|
36 |
public $requestDto;
|
37 |
|
38 |
+
/** @var DirectoryScannerControl */
|
39 |
+
private $scannerControl;
|
40 |
|
41 |
/** @var BufferedCache */
|
42 |
private $directoryCache;
|
44 |
/** @var array */
|
45 |
private $directories;
|
46 |
|
47 |
+
public function __construct(DirectoryScannerControl $scannerControl, LoggerInterface $logger, Cache $cache)
|
48 |
{
|
49 |
parent::__construct($logger, $cache);
|
50 |
$this->directories = [];
|
51 |
|
52 |
+
$scannerControl->setQueueByName();
|
53 |
+
$this->scannerControl = $scannerControl;
|
54 |
|
55 |
+
$this->directoryCache = clone $scannerControl->getCache();
|
56 |
$this->directoryCache->setLifetime(DAY_IN_SECONDS);
|
57 |
+
$this->directoryCache->setFilename(DirectoryScannerControl::DATA_CACHE_FILE);
|
58 |
}
|
59 |
|
60 |
public function __destruct()
|
116 |
{
|
117 |
$directories = null;
|
118 |
try {
|
119 |
+
$directories = $this->scannerControl->scanCurrentPath($this->requestDto->getExcluded());
|
120 |
} catch (FinishedQueueException $e) {
|
121 |
$this->logger->info('Finished scanning directories');
|
122 |
$this->requestDto->getSteps()->finish();
|
128 |
}
|
129 |
|
130 |
// No directories found here, skip it
|
131 |
+
if (empty($directories)) {
|
132 |
return;
|
133 |
}
|
134 |
|
136 |
if ($this->isThreshold()) {
|
137 |
return;
|
138 |
}
|
139 |
+
$relativePath = str_replace(ABSPATH, null, $directory);
|
140 |
+
$this->scannerControl->addToNewQueue($relativePath);
|
141 |
$this->directories[] = $relativePath;
|
142 |
}
|
143 |
+
$this->directories = array_unique($this->directories);
|
144 |
}
|
145 |
|
146 |
protected function findRequestDto()
|
160 |
}, $this->requestDto->getIncluded());
|
161 |
|
162 |
/** @noinspection NullPointerExceptionInspection */
|
163 |
+
if ($this->scannerControl->getQueue()->count() < 1) {
|
164 |
+
$this->scannerControl->setNewQueueItems($this->directories);
|
165 |
}
|
166 |
|
167 |
$totalSteps = count($this->requestDto->getIncluded());
|
174 |
// There is no need to backup WP Staging as you shouldn't restore WPSTG backup without WPSTG having installed
|
175 |
// Don't backup / restore cache as it can be problematic
|
176 |
$excludedDirs = $this->requestDto->getExcluded();
|
177 |
+
|
178 |
+
$adapter = $this->scannerControl->getDirectory();
|
179 |
+
|
|
|
180 |
$excludedDirs[] = WPSTG_PLUGIN_DIR;
|
181 |
$excludedDirs[] = $adapter->getPluginUploadsDirectory();
|
182 |
$excludedDirs[] = WP_CONTENT_DIR . '/cache';
|
187 |
{
|
188 |
$caches = parent::getCaches();
|
189 |
$caches[] = $this->directoryCache;
|
190 |
+
$caches[] = $this->scannerControl->getCache();
|
191 |
/** @noinspection NullPointerExceptionInspection */
|
192 |
+
$caches[] = $this->scannerControl->getQueue()->getStorage()->getCache();
|
193 |
return $caches;
|
194 |
}
|
195 |
|
208 |
$steps->setTotal($steps->getTotal() + count($this->directories));
|
209 |
|
210 |
/** @noinspection NullPointerExceptionInspection */
|
211 |
+
if ($this->scannerControl->getQueue()->count() > 0) {
|
212 |
return;
|
213 |
}
|
214 |
|
Component/Task/Filesystem/FileScannerRequestDto.php
CHANGED
@@ -9,22 +9,24 @@ use WPStaging\Component\Dto\AbstractRequestDto;
|
|
9 |
|
10 |
class FileScannerRequestDto extends AbstractRequestDto
|
11 |
{
|
12 |
-
|
13 |
/** @var array */
|
14 |
-
private $included;
|
15 |
|
16 |
/** @var array */
|
17 |
-
private $excluded;
|
|
|
|
|
|
|
18 |
|
19 |
/**
|
20 |
* @return array
|
21 |
*/
|
22 |
public function getIncluded()
|
23 |
{
|
24 |
-
return $this->included
|
25 |
}
|
26 |
|
27 |
-
public function setIncluded(array $included =
|
28 |
{
|
29 |
$this->included = $included;
|
30 |
}
|
@@ -34,11 +36,24 @@ class FileScannerRequestDto extends AbstractRequestDto
|
|
34 |
*/
|
35 |
public function getExcluded()
|
36 |
{
|
37 |
-
return $this->excluded;
|
38 |
}
|
39 |
|
40 |
-
public function setExcluded(array $excluded =
|
41 |
{
|
42 |
$this->excluded = $excluded;
|
43 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
44 |
}
|
9 |
|
10 |
class FileScannerRequestDto extends AbstractRequestDto
|
11 |
{
|
|
|
12 |
/** @var array */
|
13 |
+
private $included = [];
|
14 |
|
15 |
/** @var array */
|
16 |
+
private $excluded = [];
|
17 |
+
|
18 |
+
/** @var bool */
|
19 |
+
private $includeOtherFilesInWpContent;
|
20 |
|
21 |
/**
|
22 |
* @return array
|
23 |
*/
|
24 |
public function getIncluded()
|
25 |
{
|
26 |
+
return (array)$this->included;
|
27 |
}
|
28 |
|
29 |
+
public function setIncluded(array $included = [])
|
30 |
{
|
31 |
$this->included = $included;
|
32 |
}
|
36 |
*/
|
37 |
public function getExcluded()
|
38 |
{
|
39 |
+
return (array)$this->excluded;
|
40 |
}
|
41 |
|
42 |
+
public function setExcluded(array $excluded = [])
|
43 |
{
|
44 |
$this->excluded = $excluded;
|
45 |
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* @return bool
|
49 |
+
*/
|
50 |
+
public function getIncludeOtherFilesInWpContent()
|
51 |
+
{
|
52 |
+
return (bool)$this->includeOtherFilesInWpContent;
|
53 |
+
}
|
54 |
+
|
55 |
+
public function setIncludeOtherFilesInWpContent($includeOtherFilesInWpContent)
|
56 |
+
{
|
57 |
+
$this->includeOtherFilesInWpContent = $includeOtherFilesInWpContent;
|
58 |
+
}
|
59 |
}
|
Component/Task/Filesystem/FileScannerTask.php
CHANGED
@@ -16,8 +16,8 @@ use WPStaging\Framework\Traits\ResourceTrait;
|
|
16 |
use WPStaging\Framework\Utils\Cache\AbstractCache;
|
17 |
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
18 |
use WPStaging\Framework\Utils\Cache\Cache;
|
19 |
-
use WPStaging\Framework\Filesystem\
|
20 |
-
use WPStaging\Framework\Filesystem\
|
21 |
use WPStaging\Framework\Filesystem\Filesystem;
|
22 |
|
23 |
class FileScannerTask extends AbstractTask
|
@@ -32,8 +32,8 @@ class FileScannerTask extends AbstractTask
|
|
32 |
/** @var FileScannerRequestDto */
|
33 |
public $requestDto;
|
34 |
|
35 |
-
/** @var
|
36 |
-
private $
|
37 |
|
38 |
/** @var BufferedCache */
|
39 |
private $fileCache;
|
@@ -41,17 +41,17 @@ class FileScannerTask extends AbstractTask
|
|
41 |
/** @var array */
|
42 |
private $files;
|
43 |
|
44 |
-
public function __construct(
|
45 |
{
|
46 |
parent::__construct($logger, $cache);
|
47 |
$this->files = [];
|
48 |
|
49 |
-
$
|
50 |
-
$this->
|
51 |
|
52 |
-
$this->fileCache = clone $
|
53 |
$this->fileCache->setLifetime(DAY_IN_SECONDS);
|
54 |
-
$this->fileCache->setFilename(
|
55 |
}
|
56 |
|
57 |
public function __destruct()
|
@@ -118,7 +118,7 @@ class FileScannerTask extends AbstractTask
|
|
118 |
{
|
119 |
$files = null;
|
120 |
try {
|
121 |
-
$files = $this->
|
122 |
} catch (FinishedQueueException $e) {
|
123 |
$this->logger->info('Finished scanning files');
|
124 |
$this->requestDto->getSteps()->finish();
|
@@ -127,8 +127,8 @@ class FileScannerTask extends AbstractTask
|
|
127 |
$this->logger->warning($e->getMessage());
|
128 |
}
|
129 |
|
130 |
-
// No
|
131 |
-
if ($files
|
132 |
return;
|
133 |
}
|
134 |
|
@@ -136,9 +136,10 @@ class FileScannerTask extends AbstractTask
|
|
136 |
if ($this->isThreshold()) {
|
137 |
return;
|
138 |
}
|
139 |
-
$relativePath = str_replace(ABSPATH, null, $file
|
140 |
$this->files[] = $relativePath;
|
141 |
}
|
|
|
142 |
}
|
143 |
|
144 |
protected function findRequestDto()
|
@@ -154,7 +155,7 @@ class FileScannerTask extends AbstractTask
|
|
154 |
}, $this->requestDto->getIncluded()));
|
155 |
|
156 |
/** @noinspection NullPointerExceptionInspection */
|
157 |
-
if ($this->
|
158 |
$this->initiateQueue();
|
159 |
}
|
160 |
|
@@ -166,17 +167,17 @@ class FileScannerTask extends AbstractTask
|
|
166 |
$caches = parent::getCaches();
|
167 |
$caches[] = $this->fileCache;
|
168 |
/** @noinspection NullPointerExceptionInspection */
|
169 |
-
$caches[] = $this->
|
170 |
return $caches;
|
171 |
}
|
172 |
|
173 |
private function initiateQueue()
|
174 |
{
|
175 |
if ($this->requestDto->getIncluded()) {
|
176 |
-
$this->
|
177 |
}
|
178 |
|
179 |
-
$directoryData = $this->cache->getPath() .
|
180 |
if (!file_exists($directoryData)) {
|
181 |
throw new RuntimeException(sprintf(
|
182 |
'File %s does not exists. Need to Scan Directories first',
|
@@ -184,7 +185,7 @@ class FileScannerTask extends AbstractTask
|
|
184 |
));
|
185 |
}
|
186 |
|
187 |
-
$queueFile = $this->cache->getPath() . BufferedCacheStorage::FILE_PREFIX .
|
188 |
$queueFile .= '.' . AbstractCache::EXTENSION;
|
189 |
|
190 |
if (!(new Filesystem)->copy($directoryData, $queueFile)) {
|
@@ -207,7 +208,7 @@ class FileScannerTask extends AbstractTask
|
|
207 |
$steps->setTotal($steps->getTotal() + count($this->files));
|
208 |
|
209 |
/** @noinspection NullPointerExceptionInspection */
|
210 |
-
if ($this->
|
211 |
return;
|
212 |
}
|
213 |
|
16 |
use WPStaging\Framework\Utils\Cache\AbstractCache;
|
17 |
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
18 |
use WPStaging\Framework\Utils\Cache\Cache;
|
19 |
+
use WPStaging\Framework\Filesystem\DirectoryScannerControl;
|
20 |
+
use WPStaging\Framework\Filesystem\FileScannerControl;
|
21 |
use WPStaging\Framework\Filesystem\Filesystem;
|
22 |
|
23 |
class FileScannerTask extends AbstractTask
|
32 |
/** @var FileScannerRequestDto */
|
33 |
public $requestDto;
|
34 |
|
35 |
+
/** @var FileScannerControl */
|
36 |
+
private $scannerControl;
|
37 |
|
38 |
/** @var BufferedCache */
|
39 |
private $fileCache;
|
41 |
/** @var array */
|
42 |
private $files;
|
43 |
|
44 |
+
public function __construct(FileScannerControl $scannerControl, LoggerInterface $logger, Cache $cache)
|
45 |
{
|
46 |
parent::__construct($logger, $cache);
|
47 |
$this->files = [];
|
48 |
|
49 |
+
$scannerControl->setQueueByName();
|
50 |
+
$this->scannerControl = $scannerControl;
|
51 |
|
52 |
+
$this->fileCache = clone $scannerControl->getCache();
|
53 |
$this->fileCache->setLifetime(DAY_IN_SECONDS);
|
54 |
+
$this->fileCache->setFilename(FileScannerControl::DATA_CACHE_FILE);
|
55 |
}
|
56 |
|
57 |
public function __destruct()
|
118 |
{
|
119 |
$files = null;
|
120 |
try {
|
121 |
+
$files = $this->scannerControl->scanCurrentPath($this->requestDto->getIncludeOtherFilesInWpContent());
|
122 |
} catch (FinishedQueueException $e) {
|
123 |
$this->logger->info('Finished scanning files');
|
124 |
$this->requestDto->getSteps()->finish();
|
127 |
$this->logger->warning($e->getMessage());
|
128 |
}
|
129 |
|
130 |
+
// No files found here, skip it
|
131 |
+
if (empty($files)) {
|
132 |
return;
|
133 |
}
|
134 |
|
136 |
if ($this->isThreshold()) {
|
137 |
return;
|
138 |
}
|
139 |
+
$relativePath = str_replace(ABSPATH, null, $file);
|
140 |
$this->files[] = $relativePath;
|
141 |
}
|
142 |
+
$this->files = array_unique($this->files);
|
143 |
}
|
144 |
|
145 |
protected function findRequestDto()
|
155 |
}, $this->requestDto->getIncluded()));
|
156 |
|
157 |
/** @noinspection NullPointerExceptionInspection */
|
158 |
+
if ($this->scannerControl->getQueue()->count() < 1) {
|
159 |
$this->initiateQueue();
|
160 |
}
|
161 |
|
167 |
$caches = parent::getCaches();
|
168 |
$caches[] = $this->fileCache;
|
169 |
/** @noinspection NullPointerExceptionInspection */
|
170 |
+
$caches[] = $this->scannerControl->getQueue()->getStorage()->getCache();
|
171 |
return $caches;
|
172 |
}
|
173 |
|
174 |
private function initiateQueue()
|
175 |
{
|
176 |
if ($this->requestDto->getIncluded()) {
|
177 |
+
$this->scannerControl->setNewQueueItems($this->requestDto->getIncluded());
|
178 |
}
|
179 |
|
180 |
+
$directoryData = $this->cache->getPath() . DirectoryScannerControl::DATA_CACHE_FILE . '.' . AbstractCache::EXTENSION;
|
181 |
if (!file_exists($directoryData)) {
|
182 |
throw new RuntimeException(sprintf(
|
183 |
'File %s does not exists. Need to Scan Directories first',
|
185 |
));
|
186 |
}
|
187 |
|
188 |
+
$queueFile = $this->cache->getPath() . BufferedCacheStorage::FILE_PREFIX . FileScannerControl::QUEUE_CACHE_FILE;
|
189 |
$queueFile .= '.' . AbstractCache::EXTENSION;
|
190 |
|
191 |
if (!(new Filesystem)->copy($directoryData, $queueFile)) {
|
208 |
$steps->setTotal($steps->getTotal() + count($this->files));
|
209 |
|
210 |
/** @noinspection NullPointerExceptionInspection */
|
211 |
+
if ($this->scannerControl->getQueue()->count() > 0) {
|
212 |
return;
|
213 |
}
|
214 |
|
Core/Cron/Cron.php
CHANGED
@@ -16,15 +16,15 @@ class Cron
|
|
16 |
|
17 |
public function __construct()
|
18 |
{
|
19 |
-
add_filter('cron_schedules', [$this, '
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
* Add new intervals for wp cron jobs
|
24 |
-
* @param
|
25 |
-
* @return
|
26 |
*/
|
27 |
-
public function
|
28 |
{
|
29 |
// add weekly and monthly intervals
|
30 |
$schedules['weekly'] = [
|
@@ -40,7 +40,10 @@ class Cron
|
|
40 |
return $schedules;
|
41 |
}
|
42 |
|
43 |
-
|
|
|
|
|
|
|
44 |
{
|
45 |
if (!wp_next_scheduled('wpstg_weekly_event')) {
|
46 |
wp_schedule_event(time(), 'weekly', 'wpstg_weekly_event');
|
@@ -48,6 +51,8 @@ class Cron
|
|
48 |
if (!wp_next_scheduled('wpstg_daily_event')) {
|
49 |
wp_schedule_event(time(), 'daily', 'wpstg_daily_event');
|
50 |
}
|
|
|
|
|
51 |
}
|
52 |
|
53 |
}
|
16 |
|
17 |
public function __construct()
|
18 |
{
|
19 |
+
add_filter('cron_schedules', [$this, 'addIntervals']);
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
* Add new intervals for wp cron jobs
|
24 |
+
* @param array $schedules
|
25 |
+
* @return array
|
26 |
*/
|
27 |
+
public function addIntervals($schedules)
|
28 |
{
|
29 |
// add weekly and monthly intervals
|
30 |
$schedules['weekly'] = [
|
40 |
return $schedules;
|
41 |
}
|
42 |
|
43 |
+
/**
|
44 |
+
* @return bool
|
45 |
+
*/
|
46 |
+
public function scheduleEvent()
|
47 |
{
|
48 |
if (!wp_next_scheduled('wpstg_weekly_event')) {
|
49 |
wp_schedule_event(time(), 'weekly', 'wpstg_weekly_event');
|
51 |
if (!wp_next_scheduled('wpstg_daily_event')) {
|
52 |
wp_schedule_event(time(), 'daily', 'wpstg_daily_event');
|
53 |
}
|
54 |
+
|
55 |
+
return true;
|
56 |
}
|
57 |
|
58 |
}
|
Core/Utils/Cache.php
CHANGED
@@ -8,6 +8,7 @@ if( !defined( "WPINC" ) ) {
|
|
8 |
}
|
9 |
|
10 |
use Exception;
|
|
|
11 |
|
12 |
/**
|
13 |
* Class Cache
|
@@ -69,16 +70,15 @@ class Cache {
|
|
69 |
$this->cacheExtension = $cacheExtension;
|
70 |
}
|
71 |
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
-
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
}
|
82 |
}
|
83 |
|
84 |
/**
|
8 |
}
|
9 |
|
10 |
use Exception;
|
11 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
12 |
|
13 |
/**
|
14 |
* Class Cache
|
70 |
$this->cacheExtension = $cacheExtension;
|
71 |
}
|
72 |
|
73 |
+
/**
|
74 |
+
* If cache directory doesn't exists, create it.
|
75 |
+
*
|
76 |
+
* There's no need to handle failure to create here,
|
77 |
+
* as a warning is already displayed on:
|
78 |
+
*
|
79 |
+
* @see \WPStaging\Backend\Notices\Notices::messages
|
80 |
+
*/
|
81 |
+
(new Filesystem)->mkdir($this->cacheDir);
|
|
|
82 |
}
|
83 |
|
84 |
/**
|
Core/Utils/Filesystem.php
DELETED
@@ -1,56 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
namespace WPStaging\Core\Utils;
|
4 |
-
|
5 |
-
// No Direct Access
|
6 |
-
if( !defined( "WPINC" ) ) {
|
7 |
-
die;
|
8 |
-
}
|
9 |
-
|
10 |
-
class Filesystem {
|
11 |
-
|
12 |
-
/**
|
13 |
-
* Create a file with content
|
14 |
-
*
|
15 |
-
* @param string $path Path to the file
|
16 |
-
* @param string $content Content of the file
|
17 |
-
* @return boolean
|
18 |
-
*/
|
19 |
-
public function create( $path, $content ) {
|
20 |
-
if( !@file_exists( $path ) ) {
|
21 |
-
if( !@is_writable( dirname( $path ) ) ) {
|
22 |
-
return false;
|
23 |
-
}
|
24 |
-
|
25 |
-
if( !@touch( $path ) ) {
|
26 |
-
return false;
|
27 |
-
}
|
28 |
-
} elseif( !@is_writable( $path ) ) {
|
29 |
-
return false;
|
30 |
-
}
|
31 |
-
|
32 |
-
$written = false;
|
33 |
-
if( ( $handle = @fopen( $path, 'w' ) ) !== false ) {
|
34 |
-
if( @fwrite( $handle, $content ) !== false ) {
|
35 |
-
$written = true;
|
36 |
-
}
|
37 |
-
|
38 |
-
@fclose( $handle );
|
39 |
-
}
|
40 |
-
|
41 |
-
return $written;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* Create a file with marker and content
|
46 |
-
*
|
47 |
-
* @param string $path Path to the file
|
48 |
-
* @param string $marker Name of the marker
|
49 |
-
* @param string $content Content of the file
|
50 |
-
* @return boolean
|
51 |
-
*/
|
52 |
-
public function createWithMarkers( $path, $marker, $content ) {
|
53 |
-
return @insert_with_markers( $path, $marker, $content );
|
54 |
-
}
|
55 |
-
|
56 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Core/Utils/Htaccess.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
-
use WPStaging\
|
6 |
|
7 |
// No Direct Access
|
8 |
if (!defined("WPINC"))
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
6 |
|
7 |
// No Direct Access
|
8 |
if (!defined("WPINC"))
|
Core/Utils/IISWebConfig.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
-
use WPStaging\
|
6 |
|
7 |
// No Direct Access
|
8 |
if( !defined( "WPINC" ) ) {
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
6 |
|
7 |
// No Direct Access
|
8 |
if( !defined( "WPINC" ) ) {
|
Core/Utils/Logger.php
CHANGED
@@ -9,6 +9,7 @@
|
|
9 |
|
10 |
namespace WPStaging\Core\Utils;
|
11 |
|
|
|
12 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
13 |
use WPStaging\Vendor\Psr\Log\LogLevel;
|
14 |
|
@@ -83,17 +84,11 @@ class Logger implements LoggerInterface
|
|
83 |
$this->logExtension = $logExtension;
|
84 |
}
|
85 |
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
* as a warning is already displayed on:
|
92 |
-
*
|
93 |
-
* @see \WPStaging\Backend\Notices\Notices::messages
|
94 |
-
*/
|
95 |
-
// throw new \Exception("Failed to create log directory!");
|
96 |
-
}
|
97 |
}
|
98 |
|
99 |
public function __destruct()
|
@@ -135,7 +130,7 @@ class Logger implements LoggerInterface
|
|
135 |
}
|
136 |
|
137 |
/**
|
138 |
-
* @param
|
139 |
*/
|
140 |
public function setFileName($fileName)
|
141 |
{
|
9 |
|
10 |
namespace WPStaging\Core\Utils;
|
11 |
|
12 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
13 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
14 |
use WPStaging\Vendor\Psr\Log\LogLevel;
|
15 |
|
84 |
$this->logExtension = $logExtension;
|
85 |
}
|
86 |
|
87 |
+
/**
|
88 |
+
* If log directory doesn't exists, create it.
|
89 |
+
* @see \WPStaging\Backend\Notices\Notices::messages Notice that shows if log directory couldn't be created.
|
90 |
+
*/
|
91 |
+
(new Filesystem)->mkdir($this->logDir);
|
|
|
|
|
|
|
|
|
|
|
|
|
92 |
}
|
93 |
|
94 |
public function __destruct()
|
130 |
}
|
131 |
|
132 |
/**
|
133 |
+
* @param string $fileName
|
134 |
*/
|
135 |
public function setFileName($fileName)
|
136 |
{
|
Core/Utils/RobotsTxt.php
CHANGED
@@ -2,7 +2,7 @@
|
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
-
use WPStaging\
|
6 |
|
7 |
// No Direct Access
|
8 |
if (!defined("WPINC"))
|
2 |
|
3 |
namespace WPStaging\Core\Utils;
|
4 |
|
5 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
6 |
|
7 |
// No Direct Access
|
8 |
if (!defined("WPINC"))
|
Core/Utils/functions.php
CHANGED
@@ -9,35 +9,6 @@
|
|
9 |
*
|
10 |
*/
|
11 |
|
12 |
-
/**
|
13 |
-
* Get directory permissions
|
14 |
-
*
|
15 |
-
* @return int
|
16 |
-
*/
|
17 |
-
function wpstg_get_permissions_for_directory()
|
18 |
-
{
|
19 |
-
$octal = 0755;
|
20 |
-
if (defined('FS_CHMOD_DIR')) {
|
21 |
-
$octal = FS_CHMOD_DIR;
|
22 |
-
}
|
23 |
-
|
24 |
-
return apply_filters('wpstg_folder_permission', $octal);
|
25 |
-
}
|
26 |
-
|
27 |
-
/**
|
28 |
-
* Get file permissions
|
29 |
-
*
|
30 |
-
* @return int
|
31 |
-
*/
|
32 |
-
function wpstg_get_permissions_for_file()
|
33 |
-
{
|
34 |
-
if (defined('FS_CHMOD_FILE')) {
|
35 |
-
return FS_CHMOD_FILE;
|
36 |
-
}
|
37 |
-
|
38 |
-
return 0644;
|
39 |
-
}
|
40 |
-
|
41 |
/**
|
42 |
* PHP setup environment
|
43 |
*
|
@@ -442,38 +413,6 @@ function wpstg_chmod($file, $mode = false)
|
|
442 |
return true;
|
443 |
}
|
444 |
|
445 |
-
/**
|
446 |
-
* Create file if it does not exist
|
447 |
-
*
|
448 |
-
* @param string $path
|
449 |
-
* @param (int|false) $chmod The permissions as octal number (or false to skip chmod)
|
450 |
-
* @param (string|int) $chown A user name or number (or false to skip chown).
|
451 |
-
* @return boolean true on success, false on failure.
|
452 |
-
*/
|
453 |
-
function wpstg_mkdir($path, $chmod = false, $chown = false)
|
454 |
-
{
|
455 |
-
// Safe mode fails with a trailing slash under certain PHP versions.
|
456 |
-
$path = untrailingslashit($path);
|
457 |
-
if (empty($path)) {
|
458 |
-
return false;
|
459 |
-
}
|
460 |
-
|
461 |
-
if (!$chmod) {
|
462 |
-
$chmod = FS_CHMOD_DIR;
|
463 |
-
}
|
464 |
-
|
465 |
-
if (!@mkdir($path)) {
|
466 |
-
return false;
|
467 |
-
}
|
468 |
-
wpstg_chmod($path, $chmod);
|
469 |
-
|
470 |
-
if ($chown) {
|
471 |
-
wpstg_chown($path, $chown);
|
472 |
-
}
|
473 |
-
|
474 |
-
return true;
|
475 |
-
}
|
476 |
-
|
477 |
/**
|
478 |
* Changes the owner of a file or directory.
|
479 |
*
|
9 |
*
|
10 |
*/
|
11 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
/**
|
13 |
* PHP setup environment
|
14 |
*
|
413 |
return true;
|
414 |
}
|
415 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
416 |
/**
|
417 |
* Changes the owner of a file or directory.
|
418 |
*
|
Core/Utils/requirements-check.php
DELETED
@@ -1,211 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
/**
|
3 |
-
* Simple requirements checking class.
|
4 |
-
*
|
5 |
-
* @package WP_Requirements_Check
|
6 |
-
*/
|
7 |
-
|
8 |
-
/**
|
9 |
-
* Simple requirements checking class.
|
10 |
-
*/
|
11 |
-
class Wpstg_Requirements_Check {
|
12 |
-
/**
|
13 |
-
* @since 1.1.0
|
14 |
-
*
|
15 |
-
* @var array $args {
|
16 |
-
* Requirement arguments.
|
17 |
-
*
|
18 |
-
* @type string $title Name of the plugin.
|
19 |
-
* @type string $php Minimum required PHP version.
|
20 |
-
* @type string $wp Minimum required WordPress version.
|
21 |
-
* @type string $file Path to the main plugin file.
|
22 |
-
* @type array $i18n {
|
23 |
-
* @type string $php PHP version mismatch error message.
|
24 |
-
* @type string $wp WP version mismatch error message.
|
25 |
-
* }
|
26 |
-
* }
|
27 |
-
*/
|
28 |
-
private $args;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* Constructor.
|
32 |
-
*
|
33 |
-
* @since 1.0.0
|
34 |
-
* @access public
|
35 |
-
*
|
36 |
-
* @param array $args {
|
37 |
-
* An array of arguments to overwrite the default requirements.
|
38 |
-
*
|
39 |
-
* @type string $title Name of the plugin.
|
40 |
-
* @type string $php Minimum required PHP version.
|
41 |
-
* @type string $wp Minimum required WordPress version.
|
42 |
-
* @type string $file Path to the main plugin file.
|
43 |
-
* @type array $i18n {
|
44 |
-
* @type string $php PHP version mismatch error message.
|
45 |
-
* @type string $wp WP version mismatch error message.
|
46 |
-
* }
|
47 |
-
* }
|
48 |
-
*/
|
49 |
-
public function __construct( $args ) {
|
50 |
-
$args = (array) $args;
|
51 |
-
|
52 |
-
$this->args = wp_parse_args(
|
53 |
-
$args,
|
54 |
-
[
|
55 |
-
'title' => '',
|
56 |
-
'php' => '5.2.4',
|
57 |
-
'wp' => '3.8',
|
58 |
-
'file' => null,
|
59 |
-
'i18n' => []
|
60 |
-
]
|
61 |
-
);
|
62 |
-
|
63 |
-
$this->args['i18n'] = wp_parse_args(
|
64 |
-
$this->args['i18n'],
|
65 |
-
[
|
66 |
-
'php' => 'The “%1$s” plugin cannot run on PHP versions older than %2$s. Please contact your host and ask them to upgrade.',
|
67 |
-
'wp' => 'The “%1$s” plugin cannot run on WordPress versions older than %2$s. Please update your WordPress.',
|
68 |
-
]
|
69 |
-
);
|
70 |
-
}
|
71 |
-
|
72 |
-
/**
|
73 |
-
* Check if the install passes the requirements.
|
74 |
-
*
|
75 |
-
* @since 1.0.0
|
76 |
-
* @access public
|
77 |
-
*
|
78 |
-
* @return bool True if the install passes the requirements, false otherwise.
|
79 |
-
*/
|
80 |
-
public function passes() {
|
81 |
-
$passes = $this->php_passes() && $this->wp_passes();
|
82 |
-
|
83 |
-
if ( ! $passes ) {
|
84 |
-
add_action( 'admin_notices', [ $this, 'deactivate' ] );
|
85 |
-
}
|
86 |
-
|
87 |
-
return $passes;
|
88 |
-
}
|
89 |
-
|
90 |
-
/**
|
91 |
-
* Deactivates the plugin again.
|
92 |
-
*
|
93 |
-
* @since 1.0.0
|
94 |
-
* @access public
|
95 |
-
*/
|
96 |
-
public function deactivate() {
|
97 |
-
if ( $this->args['file'] !== null ) {
|
98 |
-
deactivate_plugins( plugin_basename( $this->args['file'] ) );
|
99 |
-
}
|
100 |
-
}
|
101 |
-
|
102 |
-
/**
|
103 |
-
* Checks if the PHP version passes the requirement.
|
104 |
-
*
|
105 |
-
* @since 1.0.0
|
106 |
-
* @access protected
|
107 |
-
*
|
108 |
-
* @return bool True if the PHP version is high enough, false otherwise.
|
109 |
-
*/
|
110 |
-
protected function php_passes() {
|
111 |
-
if ( self::_php_at_least( $this->args['php'] ) ) {
|
112 |
-
return true;
|
113 |
-
}
|
114 |
-
|
115 |
-
add_action( 'admin_notices', [ $this, 'php_version_notice' ] );
|
116 |
-
|
117 |
-
return false;
|
118 |
-
}
|
119 |
-
|
120 |
-
/**
|
121 |
-
* Compares the current PHP version with the minimum required version.
|
122 |
-
*
|
123 |
-
* @since 1.0.0
|
124 |
-
* @access protected
|
125 |
-
*
|
126 |
-
* @param string $min_version The minimum required version.
|
127 |
-
* @return bool True if the PHP version is high enough, false otherwise.
|
128 |
-
*/
|
129 |
-
protected static function _php_at_least( $min_version ) {
|
130 |
-
return version_compare( PHP_VERSION, $min_version, '>=' );
|
131 |
-
}
|
132 |
-
|
133 |
-
/**
|
134 |
-
* Displays the PHP version notice.
|
135 |
-
*
|
136 |
-
* @since 1.0.0
|
137 |
-
* @access public
|
138 |
-
*/
|
139 |
-
public function php_version_notice() {
|
140 |
-
/**
|
141 |
-
* Filters the notice for outdated PHP versions.
|
142 |
-
*
|
143 |
-
* @since 1.1.0
|
144 |
-
*
|
145 |
-
* @param string $message The error message.
|
146 |
-
* @param string $title The plugin name.
|
147 |
-
* @param string $php The WordPress version.
|
148 |
-
*/
|
149 |
-
$message = apply_filters( 'wp_requirements_check_php_notice', $this->args['i18n']['php'], $this->args['title'], $this->args['php'] );
|
150 |
-
?>
|
151 |
-
<div class="error">
|
152 |
-
<p><?php printf( $message, esc_html( $this->args['title'] ), $this->args['php'] ); ?></p>
|
153 |
-
</div>
|
154 |
-
<?php
|
155 |
-
}
|
156 |
-
|
157 |
-
/**
|
158 |
-
* Check if the WordPress version passes the requirement.
|
159 |
-
*
|
160 |
-
* @since 1.0.0
|
161 |
-
* @access protected
|
162 |
-
*
|
163 |
-
* @return bool True if the WordPress version is high enough, false otherwise.
|
164 |
-
*/
|
165 |
-
protected function wp_passes() {
|
166 |
-
if ( self::_wp_at_least( $this->args['wp'] ) ) {
|
167 |
-
return true;
|
168 |
-
}
|
169 |
-
|
170 |
-
add_action( 'admin_notices', [ $this, 'wp_version_notice' ] );
|
171 |
-
|
172 |
-
return false;
|
173 |
-
}
|
174 |
-
|
175 |
-
/**
|
176 |
-
* Compare the current WordPress version with the minimum required version.
|
177 |
-
*
|
178 |
-
* @since 1.0.0
|
179 |
-
* @access protected
|
180 |
-
*
|
181 |
-
* @param string $min_version Minimum required WordPress version.
|
182 |
-
* @return bool True if the WordPress version is high enough, false otherwise.
|
183 |
-
*/
|
184 |
-
protected static function _wp_at_least( $min_version ) {
|
185 |
-
return version_compare( get_bloginfo( 'version' ), $min_version, '>=' );
|
186 |
-
}
|
187 |
-
|
188 |
-
/**
|
189 |
-
* Show the WordPress version notice.
|
190 |
-
*
|
191 |
-
* @since 1.0.0
|
192 |
-
* @access public
|
193 |
-
*/
|
194 |
-
public function wp_version_notice() {
|
195 |
-
/**
|
196 |
-
* Filters the notice for outdated WordPress versions.
|
197 |
-
*
|
198 |
-
* @since 1.1.0
|
199 |
-
*
|
200 |
-
* @param string $message The error message.
|
201 |
-
* @param string $title The plugin name.
|
202 |
-
* @param string $php The WordPress version.
|
203 |
-
*/
|
204 |
-
$message = apply_filters( 'wp_requirements_check_wordpress_notice', $this->args['i18n']['wp'], $this->args['title'], $this->args['wp'] );
|
205 |
-
?>
|
206 |
-
<div class="error">
|
207 |
-
<p><?php printf( $message, esc_html( $this->args['title'] ), $this->args['wp'] ); ?></p>
|
208 |
-
</div>
|
209 |
-
<?php
|
210 |
-
}
|
211 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Core/WPStaging.php
CHANGED
@@ -7,6 +7,8 @@ if( !defined( "WPINC" ) ) {
|
|
7 |
die;
|
8 |
}
|
9 |
|
|
|
|
|
10 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
11 |
use WPStaging\Framework\DI\Container;
|
12 |
use WPStaging\Backend\Administrator;
|
@@ -70,16 +72,28 @@ final class WPStaging {
|
|
70 |
*/
|
71 |
private $accessToken;
|
72 |
|
|
|
|
|
|
|
73 |
private $container;
|
74 |
|
|
|
|
|
|
|
|
|
|
|
75 |
/**
|
76 |
* WPStaging constructor.
|
77 |
*/
|
78 |
private function __construct(Container $container) {
|
79 |
-
|
|
|
80 |
|
81 |
-
|
82 |
-
|
|
|
|
|
|
|
83 |
|
84 |
/*
|
85 |
* @todo Before injecting these using DI, we have to register them in a Service Provider.
|
@@ -95,6 +109,7 @@ final class WPStaging {
|
|
95 |
$this->cloneSiteFirstRun();
|
96 |
$this->maybeLoadPro();
|
97 |
$this->handleCacheIssues();
|
|
|
98 |
}
|
99 |
|
100 |
/**
|
@@ -283,27 +298,24 @@ final class WPStaging {
|
|
283 |
public static function getContentDir() {
|
284 |
$wp_upload_dir = wp_upload_dir();
|
285 |
$path = $wp_upload_dir['basedir'] . '/wp-staging';
|
286 |
-
|
287 |
return apply_filters( 'wpstg_get_upload_dir', $path . '/' );
|
288 |
}
|
289 |
|
290 |
/**
|
291 |
* Get Instance
|
292 |
*
|
293 |
-
* @param Container|null $container
|
294 |
-
*
|
295 |
* @return WPStaging
|
296 |
*/
|
297 |
-
public static function getInstance(
|
298 |
-
|
299 |
-
|
300 |
-
|
301 |
-
|
302 |
-
|
303 |
-
}
|
304 |
-
}
|
305 |
|
306 |
-
|
|
|
307 |
}
|
308 |
|
309 |
return static::$instance;
|
@@ -402,19 +414,42 @@ final class WPStaging {
|
|
402 |
}
|
403 |
|
404 |
/**
|
405 |
-
*
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
406 |
*/
|
407 |
-
public
|
|
|
|
|
|
|
408 |
|
409 |
-
|
410 |
-
|
|
|
|
|
|
|
|
|
411 |
return WPSTGPRO_VERSION;
|
412 |
}
|
413 |
|
414 |
return WPSTG_VERSION;
|
415 |
-
|
416 |
}
|
417 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
418 |
/**
|
419 |
* @return array|mixed|object
|
420 |
*/
|
@@ -477,4 +512,16 @@ final class WPStaging {
|
|
477 |
add_action( 'wp_loaded', [ $permalinksPurge, 'purgePermalinks' ], $permalinksPurge::PLUGINS_LOADED_PRIORITY);
|
478 |
}
|
479 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
480 |
}
|
7 |
die;
|
8 |
}
|
9 |
|
10 |
+
use WPStaging\Framework\Filesystem\DirectoryListing;
|
11 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
12 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
13 |
use WPStaging\Framework\DI\Container;
|
14 |
use WPStaging\Backend\Administrator;
|
72 |
*/
|
73 |
private $accessToken;
|
74 |
|
75 |
+
/**
|
76 |
+
* @var Container
|
77 |
+
*/
|
78 |
private $container;
|
79 |
|
80 |
+
/**
|
81 |
+
* @var bool Whether this Singleton instance has bootstrapped already.
|
82 |
+
*/
|
83 |
+
private $isBootstrapped = false;
|
84 |
+
|
85 |
/**
|
86 |
* WPStaging constructor.
|
87 |
*/
|
88 |
private function __construct(Container $container) {
|
89 |
+
$this->container = $container;
|
90 |
+
}
|
91 |
|
92 |
+
public function bootstrap() {
|
93 |
+
$this->isBootstrapped = true;
|
94 |
+
|
95 |
+
// Todo: Move this to a common service Provider for both Free and Pro. Do not register anything else here.
|
96 |
+
$this->container->bind(LoggerInterface::class, Logger::class);
|
97 |
|
98 |
/*
|
99 |
* @todo Before injecting these using DI, we have to register them in a Service Provider.
|
109 |
$this->cloneSiteFirstRun();
|
110 |
$this->maybeLoadPro();
|
111 |
$this->handleCacheIssues();
|
112 |
+
$this->preventDirectoryListing();
|
113 |
}
|
114 |
|
115 |
/**
|
298 |
public static function getContentDir() {
|
299 |
$wp_upload_dir = wp_upload_dir();
|
300 |
$path = $wp_upload_dir['basedir'] . '/wp-staging';
|
301 |
+
(new Filesystem)->mkdir($path);
|
302 |
return apply_filters( 'wpstg_get_upload_dir', $path . '/' );
|
303 |
}
|
304 |
|
305 |
/**
|
306 |
* Get Instance
|
307 |
*
|
|
|
|
|
308 |
* @return WPStaging
|
309 |
*/
|
310 |
+
public static function getInstance()
|
311 |
+
{
|
312 |
+
if (static::$instance === null) {
|
313 |
+
static::$instance = new WPStaging(new Container);
|
314 |
+
self::getInstance();
|
315 |
+
}
|
|
|
|
|
316 |
|
317 |
+
if (!static::$instance->isBootstrapped) {
|
318 |
+
static::$instance->bootstrap();
|
319 |
}
|
320 |
|
321 |
return static::$instance;
|
414 |
}
|
415 |
|
416 |
/**
|
417 |
+
* Returns the Container. Use this wisely!
|
418 |
+
*
|
419 |
+
* Acceptable example:
|
420 |
+
* - Using the Container as a cache that lives during the request to avoid doing multiple operations.
|
421 |
+
*
|
422 |
+
* Avoid example:
|
423 |
+
* - Using the Container to build instances of classes outside the __construct
|
424 |
+
*
|
425 |
+
* @return Container
|
426 |
*/
|
427 |
+
public function getContainer()
|
428 |
+
{
|
429 |
+
return $this->container;
|
430 |
+
}
|
431 |
|
432 |
+
/**
|
433 |
+
* @return string
|
434 |
+
*/
|
435 |
+
public static function getVersion()
|
436 |
+
{
|
437 |
+
if (self::isPro()) {
|
438 |
return WPSTGPRO_VERSION;
|
439 |
}
|
440 |
|
441 |
return WPSTG_VERSION;
|
|
|
442 |
}
|
443 |
|
444 |
+
/**
|
445 |
+
* @return bool
|
446 |
+
*
|
447 |
+
* @todo find a better place to make it mockable or add filter for mocking
|
448 |
+
*/
|
449 |
+
public static function isPro()
|
450 |
+
{
|
451 |
+
return defined('WPSTGPRO_VERSION');
|
452 |
+
}
|
453 |
/**
|
454 |
* @return array|mixed|object
|
455 |
*/
|
512 |
add_action( 'wp_loaded', [ $permalinksPurge, 'purgePermalinks' ], $permalinksPurge::PLUGINS_LOADED_PRIORITY);
|
513 |
}
|
514 |
|
515 |
+
/**
|
516 |
+
* @todo Move this to a base service provider shared between Free and Pro
|
517 |
+
*/
|
518 |
+
private function preventDirectoryListing()
|
519 |
+
{
|
520 |
+
if (is_admin() && !wp_doing_ajax()) {
|
521 |
+
/** @var DirectoryListing $directoryListing */
|
522 |
+
$directoryListing = $this->getContainer()->make(DirectoryListing::class);
|
523 |
+
$directoryListing->protectPluginUploadDirectory();
|
524 |
+
}
|
525 |
+
}
|
526 |
+
|
527 |
}
|
Entity/DatabaseSettings.php
DELETED
@@ -1,54 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
//TODO PHP7.x; declare(strict_types=1);
|
4 |
-
//TODO PHP7.x; type-hints and return types
|
5 |
-
// TODO PHP7.1; constant visibility
|
6 |
-
|
7 |
-
namespace WPStaging\Entity;
|
8 |
-
|
9 |
-
use WPStaging\Framework\Entity\AbstractEntity;
|
10 |
-
|
11 |
-
class DatabaseSettings extends AbstractEntity
|
12 |
-
{
|
13 |
-
const DEFAULT_COPY_QUERY_LIMIT = 10000;
|
14 |
-
|
15 |
-
const DEFAULT_SEARCH_REPLACE_LIMIT = 5000;
|
16 |
-
|
17 |
-
/** @var int */
|
18 |
-
private $copyQueryLimit;
|
19 |
-
|
20 |
-
/** @var int */
|
21 |
-
private $searchReplaceLimit;
|
22 |
-
|
23 |
-
/**
|
24 |
-
* @return int
|
25 |
-
*/
|
26 |
-
public function getCopyQueryLimit()
|
27 |
-
{
|
28 |
-
return $this->copyQueryLimit?: self::DEFAULT_COPY_QUERY_LIMIT;
|
29 |
-
}
|
30 |
-
|
31 |
-
/**
|
32 |
-
* @param int $copyQueryLimit
|
33 |
-
*/
|
34 |
-
public function setCopyQueryLimit($copyQueryLimit)
|
35 |
-
{
|
36 |
-
$this->copyQueryLimit = $copyQueryLimit;
|
37 |
-
}
|
38 |
-
|
39 |
-
/**
|
40 |
-
* @return int
|
41 |
-
*/
|
42 |
-
public function getSearchReplaceLimit()
|
43 |
-
{
|
44 |
-
return $this->searchReplaceLimit?: self::DEFAULT_SEARCH_REPLACE_LIMIT;
|
45 |
-
}
|
46 |
-
|
47 |
-
/**
|
48 |
-
* @param int $searchReplaceLimit
|
49 |
-
*/
|
50 |
-
public function setSearchReplaceLimit($searchReplaceLimit)
|
51 |
-
{
|
52 |
-
$this->searchReplaceLimit = $searchReplaceLimit;
|
53 |
-
}
|
54 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Entity/FilesystemSettings.php
DELETED
@@ -1,93 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
//TODO PHP7.x; declare(strict_types=1);
|
4 |
-
//TODO PHP7.x; type-hints and return types
|
5 |
-
// TODO PHP7.1; constant visibility
|
6 |
-
|
7 |
-
namespace WPStaging\Entity;
|
8 |
-
|
9 |
-
use WPStaging\Framework\Entity\AbstractEntity;
|
10 |
-
|
11 |
-
class FilesystemSettings extends AbstractEntity
|
12 |
-
{
|
13 |
-
const DEFAULT_FILE_COPY_LIMIT = 50;
|
14 |
-
const DEFAULT_MAX_FILE_SIZE = 8; // MB
|
15 |
-
const DEAULT_FILE_COPY_BATCH_SIZE = 2;
|
16 |
-
|
17 |
-
/** @var int */
|
18 |
-
private $fileCopyLimit;
|
19 |
-
|
20 |
-
// In MB
|
21 |
-
/** @var int */
|
22 |
-
private $maximumFileSize;
|
23 |
-
|
24 |
-
/** @var int */
|
25 |
-
private $fileCopyBatchSize;
|
26 |
-
|
27 |
-
/** @var bool */
|
28 |
-
private $checkDirectorySize;
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @return int
|
32 |
-
*/
|
33 |
-
public function getFileCopyLimit()
|
34 |
-
{
|
35 |
-
return $this->fileCopyLimit?: self::DEFAULT_FILE_COPY_LIMIT;
|
36 |
-
}
|
37 |
-
|
38 |
-
/**
|
39 |
-
* @param int $fileCopyLimit
|
40 |
-
*/
|
41 |
-
public function setFileCopyLimit($fileCopyLimit)
|
42 |
-
{
|
43 |
-
$this->fileCopyLimit = $fileCopyLimit;
|
44 |
-
}
|
45 |
-
|
46 |
-
/**
|
47 |
-
* @return int
|
48 |
-
*/
|
49 |
-
public function getMaximumFileSize()
|
50 |
-
{
|
51 |
-
return $this->maximumFileSize?: self::DEFAULT_MAX_FILE_SIZE;
|
52 |
-
}
|
53 |
-
|
54 |
-
/**
|
55 |
-
* @param int $maximumFileSize
|
56 |
-
*/
|
57 |
-
public function setMaximumFileSize($maximumFileSize)
|
58 |
-
{
|
59 |
-
$this->maximumFileSize = $maximumFileSize;
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* @return int
|
64 |
-
*/
|
65 |
-
public function getFileCopyBatchSize()
|
66 |
-
{
|
67 |
-
return $this->fileCopyBatchSize?: self::DEAULT_FILE_COPY_BATCH_SIZE;
|
68 |
-
}
|
69 |
-
|
70 |
-
/**
|
71 |
-
* @param int $fileCopyBatchSize
|
72 |
-
*/
|
73 |
-
public function setFileCopyBatchSize($fileCopyBatchSize)
|
74 |
-
{
|
75 |
-
$this->fileCopyBatchSize = $fileCopyBatchSize;
|
76 |
-
}
|
77 |
-
|
78 |
-
/**
|
79 |
-
* @return bool
|
80 |
-
*/
|
81 |
-
public function isCheckDirectorySize()
|
82 |
-
{
|
83 |
-
return $this->checkDirectorySize;
|
84 |
-
}
|
85 |
-
|
86 |
-
/**
|
87 |
-
* @param bool $checkDirectorySize
|
88 |
-
*/
|
89 |
-
public function setCheckDirectorySize($checkDirectorySize)
|
90 |
-
{
|
91 |
-
$this->checkDirectorySize = $checkDirectorySize;
|
92 |
-
}
|
93 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Entity/Settings.php
DELETED
@@ -1,289 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
//TODO PHP7.x; declare(strict_types=1);
|
4 |
-
//TODO PHP7.x; type-hints and return types
|
5 |
-
// TODO PHP7.1; constant visibility
|
6 |
-
|
7 |
-
namespace WPStaging\Entity;
|
8 |
-
|
9 |
-
use WPStaging\Framework\Entity\AbstractEntity;
|
10 |
-
use WPStaging\Framework\Traits\ArrayableTrait;
|
11 |
-
use WPStaging\Framework\Traits\HydrateTrait;
|
12 |
-
|
13 |
-
class Settings extends AbstractEntity
|
14 |
-
{
|
15 |
-
use ArrayableTrait {
|
16 |
-
toArray as traitToArray;
|
17 |
-
}
|
18 |
-
|
19 |
-
use HydrateTrait {
|
20 |
-
hydrate as traitHydrate;
|
21 |
-
}
|
22 |
-
|
23 |
-
const CPU_LOAD_HIGH = 'fast'; // 0 ms;
|
24 |
-
const CPU_LOAD_MEDIUM = 'medium'; // 250 ms
|
25 |
-
const CPU_LOAD_LOW = 'low'; // 500 ms
|
26 |
-
|
27 |
-
const DEFAULT_DELAY_BETWEEN_REQUESTS_IN_MS = 0;
|
28 |
-
|
29 |
-
const DEFAULT_MAX_EXECUTION_TIME_IN_SECONDS = 30;
|
30 |
-
const EXECUTION_TIME_GAP_IN_SECONDS = 5;
|
31 |
-
|
32 |
-
/** @var DatabaseSettings */
|
33 |
-
private $databaseSettings;
|
34 |
-
|
35 |
-
/** @var FilesystemSettings */
|
36 |
-
private $filesystemSettings;
|
37 |
-
|
38 |
-
// This is in milliseconds
|
39 |
-
/** @var int */
|
40 |
-
private $delayBetweenRequests;
|
41 |
-
|
42 |
-
/** @var bool */
|
43 |
-
private $keepPermaLinks;
|
44 |
-
|
45 |
-
/** @var bool */
|
46 |
-
private $debug;
|
47 |
-
|
48 |
-
/** @var bool */
|
49 |
-
private $optimizer;
|
50 |
-
|
51 |
-
/** @var bool */
|
52 |
-
private $removeDataOnUninstall;
|
53 |
-
|
54 |
-
/** @var array */
|
55 |
-
private $accessPermissions;
|
56 |
-
|
57 |
-
public function hydrate(array $data = [])
|
58 |
-
{
|
59 |
-
$compatible = [
|
60 |
-
'databaseSettings' => [
|
61 |
-
'copyQueryLimit' => !empty($data['queryLimit']) ? $data['queryLimit'] : null,
|
62 |
-
'searchReplaceLimit' => !empty($data['querySRLimit']) ? $data['querySRLimit'] : null,
|
63 |
-
],
|
64 |
-
'filesystemSettings' => [
|
65 |
-
'fileCopyLimit' => !empty($data['fileLimit']) ? $data['fileLimit'] : null,
|
66 |
-
'maximumFileSize' => !empty($data['maxFileSize']) ? $data['maxFileSize'] : null,
|
67 |
-
'fileCopyBatchSize' => !empty($data['batchSize']) ? $data['batchSize'] : null,
|
68 |
-
'checkDirectorySize' => !empty($data['checkDirectorySize']) ? $data['checkDirectorySize'] : null,
|
69 |
-
],
|
70 |
-
'delayBetweenRequests' => !empty($data['delayRequests']) ? $data['delayRequests'] : null,
|
71 |
-
'keepPermaLinks' => !empty($data['keepPermalinks']) ? $data['keepPermalinks'] : null,
|
72 |
-
'debug' => !empty($data['debugMode']) ? $data['debugMode'] : null,
|
73 |
-
'optimizer' => !empty($data['optimizer']) ? $data['optimizer'] : null,
|
74 |
-
'removeDataOnUninstall' => !empty($data['unInstallOnDelete']) ? $data['unInstallOnDelete'] : null,
|
75 |
-
'accessPermissions' => !empty($data['userRoles']) ? $data['userRoles'] : [],
|
76 |
-
];
|
77 |
-
|
78 |
-
return $this->traitHydrate($compatible);
|
79 |
-
}
|
80 |
-
|
81 |
-
public function toArray()
|
82 |
-
{
|
83 |
-
$data = $this->traitToArray();
|
84 |
-
if (isset($data['databaseSettings']) && $data['databaseSettings']) {
|
85 |
-
$data = array_merge($data, $data['databaseSettings']);
|
86 |
-
}
|
87 |
-
if (isset($data['filesystemSettings']) && $data['filesystemSettings']) {
|
88 |
-
$data = array_merge($data, $data['filesystemSettings']);
|
89 |
-
}
|
90 |
-
unset($data['databaseSettings'], $data['filesystemSettings']);
|
91 |
-
|
92 |
-
$compatibleKeys = [
|
93 |
-
'copyQueryLimit' => 'queryLimit',
|
94 |
-
'searchReplaceLimit' => 'querySRLimit',
|
95 |
-
|
96 |
-
'fileCopyLimit' => 'fileLimit',
|
97 |
-
'maximumFileSize' => 'maxFileSize',
|
98 |
-
'fileCopyBatchSize' => 'batchSize',
|
99 |
-
'checkDirectorySize' => 'checkDirectorySize',
|
100 |
-
|
101 |
-
'delayBetweenRequests' => 'delayRequests',
|
102 |
-
'keepPermaLinks' => 'keepPermalinks',
|
103 |
-
'debug' => 'debugMode',
|
104 |
-
'optimizer' => 'optimizer',
|
105 |
-
'removeDataOnUninstall' => 'unInstallOnDelete',
|
106 |
-
'accessPermissions' => 'userRoles',
|
107 |
-
];
|
108 |
-
|
109 |
-
foreach ($data as $key => $value) {
|
110 |
-
$compatibleKey = isset($compatibleKeys[$key])? $compatibleKeys[$key] : $key;
|
111 |
-
unset($data[$key]);
|
112 |
-
$data[$compatibleKey] = is_bool($value)? (string) (int) $value : $value;
|
113 |
-
}
|
114 |
-
|
115 |
-
return $data;
|
116 |
-
}
|
117 |
-
|
118 |
-
/**
|
119 |
-
* @return float|int
|
120 |
-
*/
|
121 |
-
public function findExecutionTimeLimit()
|
122 |
-
{
|
123 |
-
$executionTime = (int) ini_get('max_execution_time');
|
124 |
-
// TODO don't overwrite when CLI / SAPI and / or add setting to not overwrite for devs
|
125 |
-
if (!$executionTime || $executionTime > self::DEFAULT_MAX_EXECUTION_TIME_IN_SECONDS) {
|
126 |
-
$executionTime = self::DEFAULT_MAX_EXECUTION_TIME_IN_SECONDS;
|
127 |
-
}
|
128 |
-
return $executionTime - self::EXECUTION_TIME_GAP_IN_SECONDS;
|
129 |
-
}
|
130 |
-
|
131 |
-
/**
|
132 |
-
* @return DatabaseSettings
|
133 |
-
*/
|
134 |
-
public function getDatabaseSettings()
|
135 |
-
{
|
136 |
-
if (!$this->databaseSettings) {
|
137 |
-
$this->databaseSettings = new DatabaseSettings;
|
138 |
-
}
|
139 |
-
return $this->databaseSettings;
|
140 |
-
}
|
141 |
-
|
142 |
-
/**
|
143 |
-
* @param DatabaseSettings $databaseSettings
|
144 |
-
*/
|
145 |
-
public function setDatabaseSettings(DatabaseSettings $databaseSettings)
|
146 |
-
{
|
147 |
-
$this->databaseSettings = $databaseSettings;
|
148 |
-
}
|
149 |
-
|
150 |
-
/**
|
151 |
-
* @return FilesystemSettings
|
152 |
-
*/
|
153 |
-
public function getFilesystemSettings()
|
154 |
-
{
|
155 |
-
if (!$this->filesystemSettings) {
|
156 |
-
$this->filesystemSettings = new FilesystemSettings;
|
157 |
-
}
|
158 |
-
return $this->filesystemSettings;
|
159 |
-
}
|
160 |
-
|
161 |
-
/**
|
162 |
-
* @param FilesystemSettings $filesystemSettings
|
163 |
-
*/
|
164 |
-
public function setFilesystemSettings(FilesystemSettings $filesystemSettings)
|
165 |
-
{
|
166 |
-
$this->filesystemSettings = $filesystemSettings;
|
167 |
-
}
|
168 |
-
|
169 |
-
/**
|
170 |
-
* @return int
|
171 |
-
*/
|
172 |
-
public function getDelayBetweenRequests()
|
173 |
-
{
|
174 |
-
return $this->delayBetweenRequests?: self::DEFAULT_DELAY_BETWEEN_REQUESTS_IN_MS;
|
175 |
-
}
|
176 |
-
|
177 |
-
/**
|
178 |
-
* @param int $delayBetweenRequests
|
179 |
-
*/
|
180 |
-
public function setDelayBetweenRequests($delayBetweenRequests)
|
181 |
-
{
|
182 |
-
$this->delayBetweenRequests = $delayBetweenRequests;
|
183 |
-
}
|
184 |
-
|
185 |
-
/**
|
186 |
-
* @return bool
|
187 |
-
*/
|
188 |
-
public function isKeepPermaLinks()
|
189 |
-
{
|
190 |
-
return $this->keepPermaLinks;
|
191 |
-
}
|
192 |
-
|
193 |
-
/**
|
194 |
-
* @param bool $keepPermaLinks
|
195 |
-
*/
|
196 |
-
public function setKeepPermaLinks($keepPermaLinks)
|
197 |
-
{
|
198 |
-
if (!is_bool($keepPermaLinks)) {
|
199 |
-
$keepPermaLinks = $keepPermaLinks === 'true' || $keepPermaLinks === '1' || $keepPermaLinks === 1;
|
200 |
-
}
|
201 |
-
$this->keepPermaLinks = $keepPermaLinks;
|
202 |
-
}
|
203 |
-
|
204 |
-
/**
|
205 |
-
* @return bool
|
206 |
-
*/
|
207 |
-
public function isDebug()
|
208 |
-
{
|
209 |
-
return $this->debug;
|
210 |
-
}
|
211 |
-
|
212 |
-
/**
|
213 |
-
* @param bool $debug
|
214 |
-
*/
|
215 |
-
public function setDebug($debug)
|
216 |
-
{
|
217 |
-
if (!is_bool($debug)) {
|
218 |
-
$debug = $debug === 'true' || $debug === '1' || $debug === 1;
|
219 |
-
}
|
220 |
-
$this->debug = $debug;
|
221 |
-
}
|
222 |
-
|
223 |
-
/**
|
224 |
-
* @return bool
|
225 |
-
*/
|
226 |
-
public function isOptimizer()
|
227 |
-
{
|
228 |
-
return $this->optimizer;
|
229 |
-
}
|
230 |
-
|
231 |
-
/**
|
232 |
-
* @param bool $optimizer
|
233 |
-
*/
|
234 |
-
public function setOptimizer($optimizer)
|
235 |
-
{
|
236 |
-
if (!is_bool($optimizer)) {
|
237 |
-
$optimizer = $optimizer === 'true' || $optimizer === '1' || $optimizer === 1;
|
238 |
-
}
|
239 |
-
$this->optimizer = $optimizer;
|
240 |
-
}
|
241 |
-
|
242 |
-
/**
|
243 |
-
* @return bool
|
244 |
-
*/
|
245 |
-
public function isRemoveDataOnUninstall()
|
246 |
-
{
|
247 |
-
return $this->removeDataOnUninstall;
|
248 |
-
}
|
249 |
-
|
250 |
-
/**
|
251 |
-
* @param bool $removeDataOnUninstall
|
252 |
-
*/
|
253 |
-
public function setRemoveDataOnUninstall($removeDataOnUninstall)
|
254 |
-
{
|
255 |
-
if (!is_bool($removeDataOnUninstall)) {
|
256 |
-
$removeDataOnUninstall = $removeDataOnUninstall === 'true' || $removeDataOnUninstall === '1' || $removeDataOnUninstall === 1;
|
257 |
-
}
|
258 |
-
$this->removeDataOnUninstall = $removeDataOnUninstall;
|
259 |
-
}
|
260 |
-
|
261 |
-
/**
|
262 |
-
* @return array
|
263 |
-
*/
|
264 |
-
public function getAccessPermissions()
|
265 |
-
{
|
266 |
-
return $this->accessPermissions?: [];
|
267 |
-
}
|
268 |
-
|
269 |
-
/**
|
270 |
-
* @param array $accessPermissions
|
271 |
-
*/
|
272 |
-
public function setAccessPermissions(array $accessPermissions = null)
|
273 |
-
{
|
274 |
-
$this->accessPermissions = $accessPermissions;
|
275 |
-
}
|
276 |
-
|
277 |
-
// TODO PHP5.6; const array
|
278 |
-
/**
|
279 |
-
* @return array
|
280 |
-
*/
|
281 |
-
public function getAvailableCpuLoads()
|
282 |
-
{
|
283 |
-
return [
|
284 |
-
self::CPU_LOAD_HIGH,
|
285 |
-
self::CPU_LOAD_MEDIUM,
|
286 |
-
self::CPU_LOAD_LOW,
|
287 |
-
];
|
288 |
-
}
|
289 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Framework/Adapter/Directory.php
CHANGED
@@ -2,8 +2,6 @@
|
|
2 |
|
3 |
namespace WPStaging\Framework\Adapter;
|
4 |
|
5 |
-
use RuntimeException;
|
6 |
-
|
7 |
class Directory
|
8 |
{
|
9 |
/** @var string|null */
|
@@ -42,18 +40,13 @@ class Directory
|
|
42 |
return $this->uploadDir;
|
43 |
}
|
44 |
|
45 |
-
// Get
|
46 |
-
//
|
47 |
-
|
48 |
-
$
|
49 |
|
50 |
-
|
51 |
-
if ($dir['error']) {
|
52 |
-
throw new RuntimeException($dir['error']);
|
53 |
-
}
|
54 |
|
55 |
-
// Get absolute path to wordpress uploads directory e.g /var/www/wp-content/uploads/
|
56 |
-
$this->uploadDir = trailingslashit($dir['basedir']);
|
57 |
return $this->uploadDir;
|
58 |
}
|
59 |
|
2 |
|
3 |
namespace WPStaging\Framework\Adapter;
|
4 |
|
|
|
|
|
5 |
class Directory
|
6 |
{
|
7 |
/** @var string|null */
|
40 |
return $this->uploadDir;
|
41 |
}
|
42 |
|
43 |
+
// Get absolute path to wordpress uploads directory e.g /var/www/wp-content/uploads/
|
44 |
+
// Default is ABSPATH . 'wp-content/uploads', but it can be customized by the db option upload_path or the constant UPLOADS
|
45 |
+
$uploadDir = wp_upload_dir(null, false, null)['basedir'];
|
46 |
+
$uploadDir = trim(trailingslashit($uploadDir));
|
47 |
|
48 |
+
$this->uploadDir = $uploadDir;
|
|
|
|
|
|
|
49 |
|
|
|
|
|
50 |
return $this->uploadDir;
|
51 |
}
|
52 |
|
Framework/CloningProcess/Data/DBCloningService.php
CHANGED
@@ -38,18 +38,22 @@ abstract class DBCloningService extends CloningService
|
|
38 |
*/
|
39 |
protected function skipTable($table)
|
40 |
{
|
|
|
|
|
|
|
|
|
41 |
// Skip - Table does not exist
|
42 |
-
if (!$this->tableExists($
|
43 |
-
$this->log("Table " . $
|
44 |
return true;
|
45 |
}
|
46 |
-
//
|
47 |
-
//
|
48 |
-
//
|
49 |
-
|
50 |
-
$this->log("Table " . $
|
51 |
return true;
|
52 |
-
}
|
53 |
|
54 |
return false;
|
55 |
}
|
38 |
*/
|
39 |
protected function skipTable($table)
|
40 |
{
|
41 |
+
// during cloning process we are appending underscore to the staging prefix if it is not there
|
42 |
+
// @see WPStaging/Backend/Modules/Jobs/Cloning.php#L293
|
43 |
+
// code below solves this issue https://github.com/WP-Staging/wp-staging-pro/issues/385
|
44 |
+
$prefix = rtrim($this->dto->getPrefix(), '_') . '_';
|
45 |
// Skip - Table does not exist
|
46 |
+
if (!$this->tableExists($prefix . $table)) {
|
47 |
+
$this->log("Table " . $prefix . $table . ' not found. Skipping');
|
48 |
return true;
|
49 |
}
|
50 |
+
// during update process option table was not skipped even though it was not selected
|
51 |
+
// that was causing problem if staging site prefix is basically something string appended to,
|
52 |
+
// production site prefix i.e. staging prefix: wp_stagging_ and production prefix: wp_
|
53 |
+
if (!in_array($prefix . $table, $this->dto->getTables())) {
|
54 |
+
$this->log("Table " . $prefix . $table . ' not selected/updated. Skipping');
|
55 |
return true;
|
56 |
+
}
|
57 |
|
58 |
return false;
|
59 |
}
|
Framework/CloningProcess/Data/UpdateStagingOptionsTable.php
CHANGED
@@ -23,7 +23,7 @@ class UpdateStagingOptionsTable extends DBCloningService
|
|
23 |
'wpstg_rmpermalinks_executed' => ' ',
|
24 |
'blog_public' => 0,
|
25 |
FirstRun::FIRST_RUN_KEY => 'true',
|
26 |
-
|
27 |
];
|
28 |
if(!$this->keepPermalinks()) {
|
29 |
$updateOrInsert['rewrite_rules'] = null;
|
23 |
'wpstg_rmpermalinks_executed' => ' ',
|
24 |
'blog_public' => 0,
|
25 |
FirstRun::FIRST_RUN_KEY => 'true',
|
26 |
+
FirstRun::MAILS_DISABLED_KEY => !((bool) $this->dto->getJob()->getOptions()->emailsAllowed),
|
27 |
];
|
28 |
if(!$this->keepPermalinks()) {
|
29 |
$updateOrInsert['rewrite_rules'] = null;
|
Framework/CloningProcess/Data/UpdateWpConfigTablePrefix.php
CHANGED
@@ -21,8 +21,9 @@ class UpdateWpConfigTablePrefix extends FileCloningService
|
|
21 |
|
22 |
$oldUrl = (!$this->dto->isMultisite()) ? $this->dto->getHomeUrl() : $this->dto->getBaseUrl();
|
23 |
|
24 |
-
//
|
25 |
-
|
|
|
26 |
$replacement = '$table_prefix = \'' . $prefix . '\'; // Changed by WP Staging';
|
27 |
$content = preg_replace($pattern, $replacement, $content);
|
28 |
|
21 |
|
22 |
$oldUrl = (!$this->dto->isMultisite()) ? $this->dto->getHomeUrl() : $this->dto->getBaseUrl();
|
23 |
|
24 |
+
// Don't update the table prefix if the line starts with //, /* or * (ignoring space before them),
|
25 |
+
// Otherwise replace table prefix
|
26 |
+
$pattern = '/^\s*((?!\/\/|\/\*|\*))\$table_prefix\s*=\s*(.*)/m';
|
27 |
$replacement = '$table_prefix = \'' . $prefix . '\'; // Changed by WP Staging';
|
28 |
$content = preg_replace($pattern, $replacement, $content);
|
29 |
|
Framework/CloningProcess/Database/DatabaseCloningService.php
CHANGED
@@ -53,8 +53,10 @@ class DatabaseCloningService
|
|
53 |
foreach ($rows as $row) {
|
54 |
$escaped_values = $this->mysqlEscapeMimic(array_values($row));
|
55 |
$values = implode("', '", $escaped_values);
|
56 |
-
|
|
|
57 |
$this->log("Can not insert data into table {$new}");
|
|
|
58 |
}
|
59 |
}
|
60 |
// Commit transaction
|
@@ -166,6 +168,17 @@ class DatabaseCloningService
|
|
166 |
$this->dto->getJob()->log($prependString . $message, $type);
|
167 |
}
|
168 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
169 |
/**
|
170 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
171 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
53 |
foreach ($rows as $row) {
|
54 |
$escaped_values = $this->mysqlEscapeMimic(array_values($row));
|
55 |
$values = implode("', '", $escaped_values);
|
56 |
+
$query = "INSERT INTO `{$new}` VALUES ('{$values}')";
|
57 |
+
if ($stagingDb->query($query) === false) {
|
58 |
$this->log("Can not insert data into table {$new}");
|
59 |
+
$this->debugLog("Failed Query: " . $query . " Error: " . $stagingDb->last_error);
|
60 |
}
|
61 |
}
|
62 |
// Commit transaction
|
168 |
$this->dto->getJob()->log($prependString . $message, $type);
|
169 |
}
|
170 |
|
171 |
+
|
172 |
+
/**
|
173 |
+
* @param string $message
|
174 |
+
* @param string $type
|
175 |
+
*/
|
176 |
+
protected function debugLog($message, $type = Logger::TYPE_INFO)
|
177 |
+
{
|
178 |
+
$prependString = $this->dto->isExternal() ? "DB External Copy: " : "DB Copy: ";
|
179 |
+
$this->dto->getJob()->debugLog($prependString . $message, $type);
|
180 |
+
}
|
181 |
+
|
182 |
/**
|
183 |
* Mimics the mysql_real_escape_string function. Adapted from a post by 'feedr' on php.net.
|
184 |
* @link http://php.net/manual/en/function.mysql-real-escape-string.php#101248
|
Framework/DI/Container.php
CHANGED
@@ -31,6 +31,54 @@ class Container extends \WPStaging\Vendor\tad_DI52_Container
|
|
31 |
}
|
32 |
}
|
33 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
34 |
|
35 |
/**
|
36 |
* Overloads bind definition binding the prefix as well so that the DI container works locally.
|
31 |
}
|
32 |
}
|
33 |
|
34 |
+
/**
|
35 |
+
* You can use this to store an array of data in the container, without having to worry
|
36 |
+
* if the array was already initialized or not.
|
37 |
+
*
|
38 |
+
* @param $arrayName string The name of the array. If it doesn't exist yet, it will be created.
|
39 |
+
* @param $value mixed The value to add to the array.
|
40 |
+
*
|
41 |
+
* @return bool True if the value was added to the array. False if value already existed in the array.
|
42 |
+
*/
|
43 |
+
public function pushToArray($arrayName, $value)
|
44 |
+
{
|
45 |
+
try {
|
46 |
+
$arrayValues = (array)$this->offsetGet($arrayName);
|
47 |
+
|
48 |
+
if (in_array($value, $arrayValues)) {
|
49 |
+
// Do nothing, as the item already exists in this array.
|
50 |
+
return false;
|
51 |
+
}
|
52 |
+
} catch (\Exception $e) {
|
53 |
+
// If nothing is set in the container yet, create an empty one.
|
54 |
+
$this->setVar($arrayName, []);
|
55 |
+
$arrayValues = [];
|
56 |
+
}
|
57 |
+
|
58 |
+
// Add this value to the array.
|
59 |
+
$arrayValues[] = $value;
|
60 |
+
|
61 |
+
$this->setVar($arrayName, $arrayValues);
|
62 |
+
|
63 |
+
return true;
|
64 |
+
}
|
65 |
+
|
66 |
+
/**
|
67 |
+
* You can use this to get an array of data in the container, without having to worry
|
68 |
+
* if the array was already initialized or not.
|
69 |
+
*
|
70 |
+
* @param $arrayName string The name of the array. If it doesn't exist yet, an empty array will be returned.
|
71 |
+
*
|
72 |
+
* @return array The array of data requested, or an empty array if it's not set.
|
73 |
+
*/
|
74 |
+
public function getFromArray($arrayName)
|
75 |
+
{
|
76 |
+
try {
|
77 |
+
return (array)$this->offsetGet($arrayName);
|
78 |
+
} catch (\Exception $e) {
|
79 |
+
return [];
|
80 |
+
}
|
81 |
+
}
|
82 |
|
83 |
/**
|
84 |
* Overloads bind definition binding the prefix as well so that the DI container works locally.
|
Framework/Filesystem/DirectoryListing.php
ADDED
@@ -0,0 +1,172 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Framework\Filesystem;
|
4 |
+
|
5 |
+
use RuntimeException;
|
6 |
+
use WPStaging\Backend\Notices\Notices;
|
7 |
+
use WPStaging\Core\Utils\Htaccess;
|
8 |
+
use WPStaging\Core\Utils\IISWebConfig;
|
9 |
+
use WPStaging\Core\WPStaging;
|
10 |
+
use WPStaging\Framework\Adapter\Directory;
|
11 |
+
|
12 |
+
/**
|
13 |
+
* Class DirectoryListing
|
14 |
+
*
|
15 |
+
* Protect sensitive folders from directory listings.
|
16 |
+
*
|
17 |
+
* @package WPStaging\Framework\Filesystem
|
18 |
+
*/
|
19 |
+
class DirectoryListing
|
20 |
+
{
|
21 |
+
private $directory;
|
22 |
+
private $htaccess;
|
23 |
+
private $webConfig;
|
24 |
+
|
25 |
+
public function __construct(Directory $directory, Htaccess $htaccess, IISWebConfig $webConfig)
|
26 |
+
{
|
27 |
+
$this->directory = $directory;
|
28 |
+
$this->htaccess = $htaccess;
|
29 |
+
$this->webConfig = $webConfig;
|
30 |
+
}
|
31 |
+
|
32 |
+
/**
|
33 |
+
* Protect the WPStaging upload folder from directory listing.
|
34 |
+
*/
|
35 |
+
public function protectPluginUploadDirectory()
|
36 |
+
{
|
37 |
+
$lastChecked = get_transient('wpstg.directory_listing.last_checked');
|
38 |
+
$now = current_time('timestamp');
|
39 |
+
|
40 |
+
if (!empty($lastChecked)) {
|
41 |
+
if (($now - $lastChecked) < $this->getInterval()) {
|
42 |
+
// Early bail: Last check happened not long ago...
|
43 |
+
return;
|
44 |
+
}
|
45 |
+
}
|
46 |
+
|
47 |
+
set_transient('wpstg.directory_listing.last_checked', $now);
|
48 |
+
|
49 |
+
try {
|
50 |
+
$it = new \RecursiveDirectoryIterator($this->directory->getPluginUploadsDirectory());
|
51 |
+
$it = new \RecursiveIteratorIterator($it);
|
52 |
+
|
53 |
+
$dirsToProtect = [];
|
54 |
+
|
55 |
+
/** @var \SplFileInfo $item */
|
56 |
+
foreach ($it as $item) {
|
57 |
+
if ($item->isDir() && $item->getBasename() !== '..') {
|
58 |
+
$dirsToProtect[] = $item->getRealPath();
|
59 |
+
}
|
60 |
+
}
|
61 |
+
|
62 |
+
$dirsToProtect = array_unique($dirsToProtect);
|
63 |
+
|
64 |
+
foreach ($dirsToProtect as $dir) {
|
65 |
+
try {
|
66 |
+
$this->preventDirectoryListing($dir);
|
67 |
+
} catch (\Exception $e) {
|
68 |
+
/**
|
69 |
+
* Enqueue this error. All enqueued errors will be shown as a single notice.
|
70 |
+
*
|
71 |
+
* @see \WPStaging\Backend\Notices\Notices::showDirectoryListingWarningNotice
|
72 |
+
*/
|
73 |
+
WPStaging::getInstance()->getContainer()->pushToArray(Notices::$directoryListingErrors, $e->getMessage());
|
74 |
+
}
|
75 |
+
}
|
76 |
+
} catch (\Exception $e) {
|
77 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
78 |
+
error_log('WPSTAGING: Could not open plugin upload directory to protect from directory listing. ' . $e->getMessage());
|
79 |
+
}
|
80 |
+
}
|
81 |
+
}
|
82 |
+
|
83 |
+
/**
|
84 |
+
* Directory listing protection is very fast. In a high-end computer
|
85 |
+
* with a NVMe hard-drive running Linux, it completes in 0.0057 seconds.
|
86 |
+
*
|
87 |
+
* However, with slow HDDs and more folders this could take longer.
|
88 |
+
*
|
89 |
+
* Since this runs on every request, and disks are the slowest thing in computing,
|
90 |
+
* we micro-optimize this code for performance, avoiding hitting the disk while we can.
|
91 |
+
*
|
92 |
+
* Thus we only run these checks after an interval, which is by default, once every 15 minutes.
|
93 |
+
*
|
94 |
+
* @return int How many seconds to wait between each check for directory listing protection.
|
95 |
+
*/
|
96 |
+
private function getInterval()
|
97 |
+
{
|
98 |
+
return (int)apply_filters('wpstg.directory_listing.interval_check', 15 * 60);
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @param string $path The path to prevent directory listing.
|
103 |
+
*
|
104 |
+
* @throws RuntimeException When could not prevent directory listing on the given path.
|
105 |
+
*
|
106 |
+
* @return void
|
107 |
+
*/
|
108 |
+
public function preventDirectoryListing($path)
|
109 |
+
{
|
110 |
+
$path = trailingslashit(wp_normalize_path($path));
|
111 |
+
|
112 |
+
// Earliest bail: Directory listing is already prevented.
|
113 |
+
if (file_exists($path . 'index.php')) {
|
114 |
+
return;
|
115 |
+
}
|
116 |
+
|
117 |
+
// Early bail: Not a directory.
|
118 |
+
if (!is_dir($path)) {
|
119 |
+
return;
|
120 |
+
}
|
121 |
+
|
122 |
+
// If it's not writable, check if directory listing is prevented. If both fail, bail.
|
123 |
+
if (!is_writable($path) && !file_exists($path . 'index.php')) {
|
124 |
+
throw new RuntimeException(__(sprintf("Could not prevent directory listing on %s (Reason: Directory is not writable and does not contain an index file)", untrailingslashit($path)), 'wp-staging'));
|
125 |
+
}
|
126 |
+
|
127 |
+
// index.php
|
128 |
+
if (!file_exists($path . 'index.php')) {
|
129 |
+
$indexPhpCreated = file_put_contents($path . 'index.php', <<<PHP
|
130 |
+
<?php
|
131 |
+
/**
|
132 |
+
* WPSTAGING automatically places this index file on all folders it creates to prevent
|
133 |
+
* directory listing on servers that might have directory listing enabled.
|
134 |
+
*
|
135 |
+
* You might have Directory Listing disabled already. If you do, feel free to ignore this file.
|
136 |
+
*
|
137 |
+
* @link https://www.google.com/search?q=directory+listing+vulnerability
|
138 |
+
* Read more about why Directory Listing can be a security risk.
|
139 |
+
*
|
140 |
+
* @link https://www.google.com/search?q=disable+directory+listing+apache
|
141 |
+
* How to disable Directory Listing on Apache.
|
142 |
+
*
|
143 |
+
* @link https://www.google.com/search?q=disable+directory+listing+nginx
|
144 |
+
* How to disable Directory Listing on Nginx.
|
145 |
+
*/
|
146 |
+
PHP
|
147 |
+
);
|
148 |
+
|
149 |
+
if ($indexPhpCreated === false) {
|
150 |
+
throw new RuntimeException(__(sprintf('Could not prevent directory listing on %s (Reason: Failed to create index.php)', untrailingslashit($path)), 'wp-staging'));
|
151 |
+
}
|
152 |
+
}
|
153 |
+
|
154 |
+
// index.html
|
155 |
+
if (!file_exists($path . 'index.html')) {
|
156 |
+
file_put_contents($path . 'index.html', '');
|
157 |
+
// We'll not throw if index.html fails to write, as this is just an additional protection layer.
|
158 |
+
}
|
159 |
+
|
160 |
+
// .htaccess
|
161 |
+
if (!file_exists($path . '.htaccess')) {
|
162 |
+
$this->htaccess->create($path . '.htaccess');
|
163 |
+
// We'll not throw if .htaccess fails to write, as this is just an additional protection layer.
|
164 |
+
}
|
165 |
+
|
166 |
+
// web.config
|
167 |
+
if (!file_exists($path . 'web.config')) {
|
168 |
+
$this->webConfig->create($path . 'web.config');
|
169 |
+
// We'll not throw if web.config fails to write, as this is just an additional protection layer.
|
170 |
+
}
|
171 |
+
}
|
172 |
+
}
|
Framework/Filesystem/DirectoryScanner.php
CHANGED
@@ -1,133 +1,60 @@
|
|
1 |
<?php
|
2 |
|
3 |
-
// TODO PHP7.x; declare(
|
4 |
-
// TODO PHP7.x;
|
5 |
-
// TODO PHP7.1; constant visibility
|
6 |
|
7 |
namespace WPStaging\Framework\Filesystem;
|
8 |
|
9 |
-
use RuntimeException;
|
10 |
-
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
11 |
-
use WPStaging\Framework\Queue\FinishedQueueException;
|
12 |
-
use WPStaging\Framework\Queue\Queue;
|
13 |
-
use WPStaging\Framework\Queue\Storage\BufferedCacheStorage;
|
14 |
-
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
15 |
-
|
16 |
class DirectoryScanner
|
17 |
{
|
18 |
-
const DATA_CACHE_FILE = 'filesystem_scanner_directory_data';
|
19 |
-
const QUEUE_CACHE_FILE = 'directory_scanner';
|
20 |
-
|
21 |
-
/** @var BufferedCache */
|
22 |
-
private $cache;
|
23 |
-
|
24 |
-
/** @var BufferedCacheStorage */
|
25 |
-
private $storage;
|
26 |
-
|
27 |
-
/** @var DirectoryService */
|
28 |
-
private $service;
|
29 |
-
|
30 |
-
/** @var Queue|null */
|
31 |
-
private $queue;
|
32 |
-
|
33 |
-
/** @var array */
|
34 |
-
private $newQueueItems;
|
35 |
-
|
36 |
-
public function __construct(BufferedCache $cache, BufferedCacheStorage $storage, DirectoryService $service)
|
37 |
-
{
|
38 |
-
$this->newQueueItems = [];
|
39 |
-
$this->cache = clone $cache;
|
40 |
-
$this->storage = clone $storage;
|
41 |
-
$this->service = $service;
|
42 |
-
}
|
43 |
-
|
44 |
-
public function __destruct()
|
45 |
-
{
|
46 |
-
if ($this->newQueueItems && $this->queue) {
|
47 |
-
$this->queue->pushAsArray($this->newQueueItems);
|
48 |
-
}
|
49 |
-
}
|
50 |
-
|
51 |
-
/**
|
52 |
-
* @param string $name
|
53 |
-
*/
|
54 |
-
public function setQueueByName($name = self::QUEUE_CACHE_FILE)
|
55 |
-
{
|
56 |
-
$this->queue = new Queue;
|
57 |
-
$this->queue->setName($name);
|
58 |
-
$this->queue->setStorage($this->storage);
|
59 |
-
}
|
60 |
-
|
61 |
-
/**
|
62 |
-
* @param array|null $excluded
|
63 |
-
* @param int $depth
|
64 |
-
* @return Finder|null
|
65 |
-
*/
|
66 |
-
public function scanCurrentPath(array $excluded = null, $depth = 0)
|
67 |
-
{
|
68 |
-
$path = $this->getPathFromQueue();
|
69 |
-
if ($path === null) {
|
70 |
-
throw new FinishedQueueException('Directory Scanner Queue is Finished');
|
71 |
-
}
|
72 |
-
|
73 |
-
$path = ABSPATH . $path;
|
74 |
-
return $this->service->scan($path, $depth, $excluded);
|
75 |
-
}
|
76 |
-
|
77 |
/**
|
78 |
-
* @
|
|
|
|
|
|
|
79 |
*/
|
80 |
-
public function
|
81 |
{
|
82 |
-
|
83 |
-
|
|
|
|
|
84 |
}
|
85 |
|
86 |
-
|
87 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
88 |
}
|
89 |
|
90 |
-
return
|
91 |
-
}
|
92 |
-
|
93 |
-
/**
|
94 |
-
* @param string $item
|
95 |
-
*/
|
96 |
-
public function addToNewQueue($item)
|
97 |
-
{
|
98 |
-
$this->newQueueItems[] = $item;
|
99 |
-
}
|
100 |
-
|
101 |
-
/**
|
102 |
-
* @return BufferedCache
|
103 |
-
*/
|
104 |
-
public function getCache()
|
105 |
-
{
|
106 |
-
return $this->cache;
|
107 |
-
}
|
108 |
-
|
109 |
-
/**
|
110 |
-
* @return Queue
|
111 |
-
*/
|
112 |
-
public function getQueue()
|
113 |
-
{
|
114 |
-
if (!$this->queue) {
|
115 |
-
// TODO Custom Exception
|
116 |
-
throw new RuntimeException('DirectoryScanner Queue is not set');
|
117 |
-
}
|
118 |
-
return $this->queue;
|
119 |
-
}
|
120 |
-
|
121 |
-
public function setNewQueueItems(array $items = null)
|
122 |
-
{
|
123 |
-
$this->newQueueItems = $items;
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
* @return DirectoryService
|
128 |
-
*/
|
129 |
-
public function getService()
|
130 |
-
{
|
131 |
-
return $this->service;
|
132 |
}
|
133 |
}
|
1 |
<?php
|
2 |
|
3 |
+
// TODO PHP7.x; declare(strict_types=1);
|
4 |
+
// TODO PHP7.x; return types && type-hints
|
|
|
5 |
|
6 |
namespace WPStaging\Framework\Filesystem;
|
7 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
8 |
class DirectoryScanner
|
9 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
/**
|
11 |
+
* @param string $directory
|
12 |
+
* @param array $excludedDirectories
|
13 |
+
*
|
14 |
+
* @return array
|
15 |
*/
|
16 |
+
public function scan($directory, array $excludedDirectories = [])
|
17 |
{
|
18 |
+
try {
|
19 |
+
$it = new \DirectoryIterator($directory);
|
20 |
+
} catch (\Exception $e) {
|
21 |
+
return [];
|
22 |
}
|
23 |
|
24 |
+
/*
|
25 |
+
* Normalize the excluded directories to maximize the chances
|
26 |
+
* of matching a excluded directory if we mean to.
|
27 |
+
*
|
28 |
+
* Exclusion: /var/www/single/wp-content/plugins/WooCommerce/
|
29 |
+
* Becomes: /var/www/single/wp-content/plugins/woocommerce
|
30 |
+
*
|
31 |
+
* So that any of these exclusions matches:
|
32 |
+
* /var/www/single/wp-content/plugins/woocommerce
|
33 |
+
* /var/www/single/wp-content/plugins/woocommerce/
|
34 |
+
* /var/www/single/wp-content/plugins/WooCommerce
|
35 |
+
* /var/www/single/wp-content/plugins/WooCommerce/
|
36 |
+
*/
|
37 |
+
$excludedDirectories = array_map(function ($item) {
|
38 |
+
return untrailingslashit(strtolower($item));
|
39 |
+
}, $excludedDirectories);
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Allow user to filter the excluded directories in a site export.
|
43 |
+
* @todo Should we add UI for this?
|
44 |
+
*/
|
45 |
+
$excludedDirectories = (array)apply_filters('wpstg.export.site.directory.excluded', $excludedDirectories);
|
46 |
+
|
47 |
+
$dirs = [];
|
48 |
+
|
49 |
+
/** @var \SplFileInfo $item */
|
50 |
+
foreach ($it as $item) {
|
51 |
+
if ($item->isDir() && $item->getFilename() != "." && $item->getFilename() != "..") {
|
52 |
+
if (!in_array(untrailingslashit(strtolower($item->getRealPath())), $excludedDirectories)) {
|
53 |
+
$dirs[] = $item->getRealPath();
|
54 |
+
}
|
55 |
+
}
|
56 |
}
|
57 |
|
58 |
+
return $dirs;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
}
|
60 |
}
|
Framework/Filesystem/DirectoryScannerControl.php
ADDED
@@ -0,0 +1,146 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_type=1);
|
4 |
+
// TODO PHP7.x; type hints & return types
|
5 |
+
// TODO PHP7.1; constant visibility
|
6 |
+
|
7 |
+
namespace WPStaging\Framework\Filesystem;
|
8 |
+
|
9 |
+
use RuntimeException;
|
10 |
+
use WPStaging\Component\Task\Filesystem\DirectoryScannerTask;
|
11 |
+
use WPStaging\Framework\Adapter\Directory;
|
12 |
+
use WPStaging\Framework\Queue\FinishedQueueException;
|
13 |
+
use WPStaging\Framework\Queue\Queue;
|
14 |
+
use WPStaging\Framework\Queue\Storage\BufferedCacheStorage;
|
15 |
+
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
16 |
+
|
17 |
+
/**
|
18 |
+
* Class DirectoryScannerControl
|
19 |
+
*
|
20 |
+
* @see DirectoryScannerTask
|
21 |
+
*
|
22 |
+
* @package WPStaging\Framework\Filesystem
|
23 |
+
*/
|
24 |
+
class DirectoryScannerControl
|
25 |
+
{
|
26 |
+
const DATA_CACHE_FILE = 'filesystem_scanner_directory_data';
|
27 |
+
const QUEUE_CACHE_FILE = 'directory_scanner';
|
28 |
+
|
29 |
+
/** @var BufferedCache */
|
30 |
+
private $cache;
|
31 |
+
|
32 |
+
/** @var BufferedCacheStorage */
|
33 |
+
private $storage;
|
34 |
+
|
35 |
+
/** @var DirectoryScanner */
|
36 |
+
private $scanner;
|
37 |
+
|
38 |
+
/** @var Queue|null */
|
39 |
+
private $queue;
|
40 |
+
|
41 |
+
/** @var array */
|
42 |
+
private $newQueueItems;
|
43 |
+
|
44 |
+
/** @var Directory */
|
45 |
+
private $directory;
|
46 |
+
|
47 |
+
public function __construct(BufferedCache $cache, BufferedCacheStorage $storage, DirectoryScanner $scanner, Directory $directory)
|
48 |
+
{
|
49 |
+
$this->newQueueItems = [];
|
50 |
+
$this->cache = clone $cache;
|
51 |
+
$this->storage = clone $storage;
|
52 |
+
$this->scanner = $scanner;
|
53 |
+
$this->directory = $directory;
|
54 |
+
}
|
55 |
+
|
56 |
+
public function __destruct()
|
57 |
+
{
|
58 |
+
if ($this->newQueueItems && $this->queue) {
|
59 |
+
$this->queue->pushAsArray($this->newQueueItems);
|
60 |
+
}
|
61 |
+
}
|
62 |
+
|
63 |
+
/**
|
64 |
+
* @param string $name
|
65 |
+
*/
|
66 |
+
public function setQueueByName($name = self::QUEUE_CACHE_FILE)
|
67 |
+
{
|
68 |
+
$this->queue = new Queue;
|
69 |
+
$this->queue->setName($name);
|
70 |
+
$this->queue->setStorage($this->storage);
|
71 |
+
}
|
72 |
+
|
73 |
+
/**
|
74 |
+
* @param array $excluded
|
75 |
+
*
|
76 |
+
* @return array
|
77 |
+
*/
|
78 |
+
public function scanCurrentPath(array $excluded = [])
|
79 |
+
{
|
80 |
+
$path = $this->getPathFromQueue();
|
81 |
+
if ($path === null) {
|
82 |
+
throw new FinishedQueueException('Directory Scanner Queue is Finished');
|
83 |
+
}
|
84 |
+
|
85 |
+
$path = ABSPATH . $path;
|
86 |
+
|
87 |
+
return $this->scanner->scan($path, $excluded);
|
88 |
+
}
|
89 |
+
|
90 |
+
/**
|
91 |
+
* @return string|null
|
92 |
+
*/
|
93 |
+
public function getPathFromQueue()
|
94 |
+
{
|
95 |
+
if ($this->queue->count() > 0) {
|
96 |
+
return $this->queue->pop();
|
97 |
+
}
|
98 |
+
|
99 |
+
if ($this->newQueueItems) {
|
100 |
+
return array_shift($this->newQueueItems);
|
101 |
+
}
|
102 |
+
|
103 |
+
return null;
|
104 |
+
}
|
105 |
+
|
106 |
+
/**
|
107 |
+
* @param string $item
|
108 |
+
*/
|
109 |
+
public function addToNewQueue($item)
|
110 |
+
{
|
111 |
+
$this->newQueueItems[] = $item;
|
112 |
+
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
* @return BufferedCache
|
116 |
+
*/
|
117 |
+
public function getCache()
|
118 |
+
{
|
119 |
+
return $this->cache;
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
* @return Queue
|
124 |
+
*/
|
125 |
+
public function getQueue()
|
126 |
+
{
|
127 |
+
if (!$this->queue) {
|
128 |
+
// TODO Custom Exception
|
129 |
+
throw new RuntimeException('DirectoryScannerControl Queue is not set');
|
130 |
+
}
|
131 |
+
return $this->queue;
|
132 |
+
}
|
133 |
+
|
134 |
+
public function setNewQueueItems(array $items = null)
|
135 |
+
{
|
136 |
+
$this->newQueueItems = $items;
|
137 |
+
}
|
138 |
+
|
139 |
+
/**
|
140 |
+
* @return Directory
|
141 |
+
*/
|
142 |
+
public function getDirectory()
|
143 |
+
{
|
144 |
+
return $this->directory;
|
145 |
+
}
|
146 |
+
}
|
Framework/Filesystem/DirectoryService.php
DELETED
@@ -1,65 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// TODO PHP7.x; declare(strict_types=1);
|
4 |
-
// TODO PHP7.x; return types && type-hints
|
5 |
-
|
6 |
-
namespace WPStaging\Framework\Filesystem;
|
7 |
-
|
8 |
-
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
9 |
-
use WPStaging\Framework\Adapter\Directory;
|
10 |
-
|
11 |
-
class DirectoryService
|
12 |
-
{
|
13 |
-
|
14 |
-
/** @var Directory */
|
15 |
-
private $directory;
|
16 |
-
|
17 |
-
public function __construct(Directory $directory)
|
18 |
-
{
|
19 |
-
$this->directory = $directory;
|
20 |
-
}
|
21 |
-
|
22 |
-
/**
|
23 |
-
* @param string $directory
|
24 |
-
* @param string $depth
|
25 |
-
* @param array|null $excludedDirectories
|
26 |
-
*
|
27 |
-
* @return Finder|null
|
28 |
-
*/
|
29 |
-
public function scan($directory, $depth = null, array $excludedDirectories = null)
|
30 |
-
{
|
31 |
-
$finder = (new Finder)
|
32 |
-
->ignoreUnreadableDirs()
|
33 |
-
->directories()
|
34 |
-
->in($directory)
|
35 |
-
;
|
36 |
-
|
37 |
-
if ($excludedDirectories) {
|
38 |
-
foreach($excludedDirectories as $excludedDirectory) {
|
39 |
-
$notPath = str_replace($directory, null, $excludedDirectory);
|
40 |
-
$notPath = '#' . trim($notPath, '#') . '#';
|
41 |
-
$finder->notPath($notPath);
|
42 |
-
}
|
43 |
-
}
|
44 |
-
|
45 |
-
if ($depth !== null) {
|
46 |
-
$finder->depth($depth);
|
47 |
-
}
|
48 |
-
|
49 |
-
$finderHasResults = count($finder) > 0;
|
50 |
-
|
51 |
-
if (!$finderHasResults) {
|
52 |
-
return null;
|
53 |
-
}
|
54 |
-
|
55 |
-
return $finder;
|
56 |
-
}
|
57 |
-
|
58 |
-
/**
|
59 |
-
* @return Directory
|
60 |
-
*/
|
61 |
-
public function getDirectory()
|
62 |
-
{
|
63 |
-
return $this->directory;
|
64 |
-
}
|
65 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Framework/Filesystem/FileScanner.php
CHANGED
@@ -6,125 +6,93 @@
|
|
6 |
|
7 |
namespace WPStaging\Framework\Filesystem;
|
8 |
|
9 |
-
use
|
10 |
-
use RuntimeException;
|
11 |
-
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
12 |
-
use WPStaging\Framework\Queue\FinishedQueueException;
|
13 |
-
use WPStaging\Framework\Queue\Queue;
|
14 |
-
use WPStaging\Framework\Queue\Storage\BufferedCacheStorage;
|
15 |
-
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
16 |
|
17 |
class FileScanner
|
18 |
{
|
19 |
-
|
20 |
-
|
21 |
|
22 |
-
|
23 |
-
private $cache;
|
24 |
-
|
25 |
-
/** @var BufferedCacheStorage */
|
26 |
-
private $storage;
|
27 |
-
|
28 |
-
/** @var DirectoryService */
|
29 |
-
private $service;
|
30 |
-
|
31 |
-
/** @var Queue|null */
|
32 |
-
private $queue;
|
33 |
-
|
34 |
-
/** @var array */
|
35 |
-
private $newQueueItems;
|
36 |
-
|
37 |
-
public function __construct(BufferedCache $cache, BufferedCacheStorage $storage, FileService $service)
|
38 |
{
|
39 |
-
$this->
|
40 |
-
$this->
|
41 |
-
$this->storage = clone $storage;
|
42 |
-
$this->service = $service;
|
43 |
-
}
|
44 |
-
|
45 |
-
public function __destruct()
|
46 |
-
{
|
47 |
-
if ($this->newQueueItems && $this->queue) {
|
48 |
-
$this->queue->pushAsArray($this->newQueueItems);
|
49 |
-
}
|
50 |
}
|
51 |
|
52 |
/**
|
53 |
-
* @param string $
|
|
|
|
|
|
|
54 |
*/
|
55 |
-
public function
|
56 |
{
|
57 |
-
$this->queue = new Queue;
|
58 |
-
$this->queue->setName($name);
|
59 |
-
$this->queue->setStorage($this->storage);
|
60 |
-
}
|
61 |
-
|
62 |
-
/**
|
63 |
-
* @param array|null $excluded
|
64 |
-
* @param int $depth
|
65 |
-
* @return Finder|null
|
66 |
-
*/
|
67 |
-
public function scanCurrentPath(array $excluded = null, $depth = 0)
|
68 |
-
{
|
69 |
-
$path = $this->getPathFromQueue();
|
70 |
-
if ($path === null) {
|
71 |
-
throw new FinishedQueueException('File Scanner Queue is Finished');
|
72 |
-
}
|
73 |
-
|
74 |
-
$path = ABSPATH . $path;
|
75 |
try {
|
76 |
-
|
77 |
-
} catch(
|
78 |
-
return
|
79 |
}
|
80 |
-
}
|
81 |
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
89 |
}
|
90 |
|
91 |
-
|
92 |
-
return array_shift($this->newQueueItems);
|
93 |
-
}
|
94 |
-
|
95 |
-
return null;
|
96 |
-
}
|
97 |
-
|
98 |
-
/**
|
99 |
-
* @param string $item
|
100 |
-
*/
|
101 |
-
public function addToNewQueue($item)
|
102 |
-
{
|
103 |
-
$this->newQueueItems[] = $item;
|
104 |
-
}
|
105 |
-
|
106 |
-
/**
|
107 |
-
* @return BufferedCache
|
108 |
-
*/
|
109 |
-
public function getCache()
|
110 |
-
{
|
111 |
-
return $this->cache;
|
112 |
-
}
|
113 |
-
|
114 |
-
/**
|
115 |
-
* @return Queue
|
116 |
-
*/
|
117 |
-
public function getQueue()
|
118 |
-
{
|
119 |
-
if (!$this->queue) {
|
120 |
-
// TODO Custom Exception
|
121 |
-
throw new RuntimeException('FileScanner Queue is not set');
|
122 |
-
}
|
123 |
-
return $this->queue;
|
124 |
-
}
|
125 |
-
|
126 |
-
public function setNewQueueItems(array $items = null)
|
127 |
-
{
|
128 |
-
$this->newQueueItems = $items;
|
129 |
}
|
130 |
}
|
6 |
|
7 |
namespace WPStaging\Framework\Filesystem;
|
8 |
|
9 |
+
use WPStaging\Framework\Adapter\Directory;
|
|
|
|
|
|
|
|
|
|
|
|
|
10 |
|
11 |
class FileScanner
|
12 |
{
|
13 |
+
private $directory;
|
14 |
+
private $filesystem;
|
15 |
|
16 |
+
public function __construct(Directory $directory, Filesystem $filesystem)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
{
|
18 |
+
$this->directory = $directory;
|
19 |
+
$this->filesystem = $filesystem;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
20 |
}
|
21 |
|
22 |
/**
|
23 |
+
* @param string $directory
|
24 |
+
* @param bool $includeOtherFilesInWpContent
|
25 |
+
*
|
26 |
+
* @return array
|
27 |
*/
|
28 |
+
public function scan($directory, $includeOtherFilesInWpContent)
|
29 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
30 |
try {
|
31 |
+
$it = new \DirectoryIterator($directory);
|
32 |
+
} catch (\Exception $e) {
|
33 |
+
return [];
|
34 |
}
|
|
|
35 |
|
36 |
+
/**
|
37 |
+
* Allow user to exclude certain file extensions from being exported.
|
38 |
+
*/
|
39 |
+
$excludedFileExtensions = (array)apply_filters('wpstg.export.site.file_extension.excluded', []);
|
40 |
+
|
41 |
+
/**
|
42 |
+
* Allow user to exclude files larger than given size from being exported.
|
43 |
+
*/
|
44 |
+
$ignoreFilesBiggerThan = (int)apply_filters('wpstg.export.site.file.max_size_in_bytes', PHP_INT_MAX);
|
45 |
+
|
46 |
+
/*
|
47 |
+
* If "Include Other Files in WP Content" is false, only the files inside
|
48 |
+
* these folders will be added to the export.
|
49 |
+
*
|
50 |
+
* @todo: Do we want to add the commitment of a filter for this?
|
51 |
+
*/
|
52 |
+
$defaultWpContentFolders = [
|
53 |
+
WP_PLUGIN_DIR,
|
54 |
+
$this->directory->getUploadsDirectory(),
|
55 |
+
get_theme_root(),
|
56 |
+
WPMU_PLUGIN_DIR,
|
57 |
+
];
|
58 |
+
|
59 |
+
$files = [];
|
60 |
+
|
61 |
+
/** @var \SplFileInfo $item */
|
62 |
+
foreach ($it as $item) {
|
63 |
+
$shouldScan = $item->isFile() &&
|
64 |
+
!$item->isLink() &&
|
65 |
+
$item->getFilename() != "." &&
|
66 |
+
$item->getFilename() != "..";
|
67 |
+
|
68 |
+
if ($shouldScan) {
|
69 |
+
if (in_array($item->getExtension(), $excludedFileExtensions)) {
|
70 |
+
// Early bail: File has an ignored extension
|
71 |
+
continue;
|
72 |
+
}
|
73 |
+
|
74 |
+
if ($item->getSize() > $ignoreFilesBiggerThan) {
|
75 |
+
// Early bail: File is larger than max allowed size.
|
76 |
+
continue;
|
77 |
+
}
|
78 |
+
|
79 |
+
$path = $this->filesystem->safePath($item->getPathname());
|
80 |
+
|
81 |
+
if (!$includeOtherFilesInWpContent) {
|
82 |
+
foreach ($defaultWpContentFolders as $defaultFolder) {
|
83 |
+
/*
|
84 |
+
* Only include files that are inside allowed folders.
|
85 |
+
*/
|
86 |
+
if (strpos($path, trailingslashit($defaultFolder)) === 0) {
|
87 |
+
$files[] = $path;
|
88 |
+
}
|
89 |
+
}
|
90 |
+
} else {
|
91 |
+
$files[] = $path;
|
92 |
+
}
|
93 |
+
}
|
94 |
}
|
95 |
|
96 |
+
return $files;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
97 |
}
|
98 |
}
|
Framework/Filesystem/FileScannerControl.php
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// TODO PHP7.x; declare(strict_type=1);
|
4 |
+
// TODO PHP7.x; type hints & return types
|
5 |
+
// TODO PHP7.1; constant visibility
|
6 |
+
|
7 |
+
namespace WPStaging\Framework\Filesystem;
|
8 |
+
|
9 |
+
use RuntimeException;
|
10 |
+
use WPStaging\Framework\Queue\FinishedQueueException;
|
11 |
+
use WPStaging\Framework\Queue\Queue;
|
12 |
+
use WPStaging\Framework\Queue\Storage\BufferedCacheStorage;
|
13 |
+
use WPStaging\Framework\Utils\Cache\BufferedCache;
|
14 |
+
|
15 |
+
class FileScannerControl
|
16 |
+
{
|
17 |
+
const DATA_CACHE_FILE = 'filesystem_scanner_file_data';
|
18 |
+
const QUEUE_CACHE_FILE = 'file_scanner';
|
19 |
+
|
20 |
+
/** @var BufferedCache */
|
21 |
+
private $cache;
|
22 |
+
|
23 |
+
/** @var BufferedCacheStorage */
|
24 |
+
private $storage;
|
25 |
+
|
26 |
+
/** @var FileScanner */
|
27 |
+
private $scanner;
|
28 |
+
|
29 |
+
/** @var Queue|null */
|
30 |
+
private $queue;
|
31 |
+
|
32 |
+
/** @var array */
|
33 |
+
private $newQueueItems;
|
34 |
+
|
35 |
+
public function __construct(BufferedCache $cache, BufferedCacheStorage $storage, FileScanner $scanner)
|
36 |
+
{
|
37 |
+
$this->newQueueItems = [];
|
38 |
+
$this->cache = clone $cache;
|
39 |
+
$this->storage = clone $storage;
|
40 |
+
$this->scanner = $scanner;
|
41 |
+
}
|
42 |
+
|
43 |
+
public function __destruct()
|
44 |
+
{
|
45 |
+
if ($this->newQueueItems && $this->queue) {
|
46 |
+
$this->queue->pushAsArray($this->newQueueItems);
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
/**
|
51 |
+
* @param string $name
|
52 |
+
*/
|
53 |
+
public function setQueueByName($name = self::QUEUE_CACHE_FILE)
|
54 |
+
{
|
55 |
+
$this->queue = new Queue;
|
56 |
+
$this->queue->setName($name);
|
57 |
+
$this->queue->setStorage($this->storage);
|
58 |
+
}
|
59 |
+
|
60 |
+
/**
|
61 |
+
* @param bool $includeOtherFilesInWpContent
|
62 |
+
*
|
63 |
+
* @return array
|
64 |
+
*/
|
65 |
+
public function scanCurrentPath($includeOtherFilesInWpContent)
|
66 |
+
{
|
67 |
+
$path = $this->getPathFromQueue();
|
68 |
+
if ($path === null) {
|
69 |
+
throw new FinishedQueueException('File Scanner Queue is Finished');
|
70 |
+
}
|
71 |
+
|
72 |
+
$path = ABSPATH . $path;
|
73 |
+
|
74 |
+
return $this->scanner->scan($path, $includeOtherFilesInWpContent);
|
75 |
+
}
|
76 |
+
|
77 |
+
/**
|
78 |
+
* @return string|null
|
79 |
+
*/
|
80 |
+
public function getPathFromQueue()
|
81 |
+
{
|
82 |
+
if ($this->queue->count() > 0) {
|
83 |
+
return $this->queue->pop();
|
84 |
+
}
|
85 |
+
|
86 |
+
if ($this->newQueueItems) {
|
87 |
+
return array_shift($this->newQueueItems);
|
88 |
+
}
|
89 |
+
|
90 |
+
return null;
|
91 |
+
}
|
92 |
+
|
93 |
+
/**
|
94 |
+
* @param string $item
|
95 |
+
*/
|
96 |
+
public function addToNewQueue($item)
|
97 |
+
{
|
98 |
+
$this->newQueueItems[] = $item;
|
99 |
+
}
|
100 |
+
|
101 |
+
/**
|
102 |
+
* @return BufferedCache
|
103 |
+
*/
|
104 |
+
public function getCache()
|
105 |
+
{
|
106 |
+
return $this->cache;
|
107 |
+
}
|
108 |
+
|
109 |
+
/**
|
110 |
+
* @return Queue
|
111 |
+
*/
|
112 |
+
public function getQueue()
|
113 |
+
{
|
114 |
+
if (!$this->queue) {
|
115 |
+
// TODO Custom Exception
|
116 |
+
throw new RuntimeException('FileScannerControl Queue is not set');
|
117 |
+
}
|
118 |
+
|
119 |
+
return $this->queue;
|
120 |
+
}
|
121 |
+
|
122 |
+
public function setNewQueueItems(array $items = null)
|
123 |
+
{
|
124 |
+
$this->newQueueItems = $items;
|
125 |
+
}
|
126 |
+
}
|
Framework/Filesystem/FileService.php
DELETED
@@ -1,115 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// TODO PHP7.x; declare(strict_types=1);
|
4 |
-
// TODO PHP7.x; return types && type-hints
|
5 |
-
|
6 |
-
namespace WPStaging\Framework\Filesystem;
|
7 |
-
|
8 |
-
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
9 |
-
|
10 |
-
class FileService
|
11 |
-
{
|
12 |
-
/**
|
13 |
-
* @param string $directory
|
14 |
-
* @param string $depth
|
15 |
-
* @param array|null $excludedFileNames
|
16 |
-
*
|
17 |
-
* @return Finder|null
|
18 |
-
*/
|
19 |
-
public function scan($directory, $depth = null, array $excludedFileNames = null)
|
20 |
-
{
|
21 |
-
$finder = (new Finder)
|
22 |
-
->files()
|
23 |
-
->in($directory)
|
24 |
-
;
|
25 |
-
|
26 |
-
if ($excludedFileNames) {
|
27 |
-
/** @noinspection PhpParamsInspection */
|
28 |
-
$finder->notName($excludedFileNames);
|
29 |
-
}
|
30 |
-
|
31 |
-
if ($depth !== null) {
|
32 |
-
$finder->depth($depth);
|
33 |
-
}
|
34 |
-
|
35 |
-
$finderHasResults = count($finder) > 0;
|
36 |
-
|
37 |
-
if (!$finderHasResults) {
|
38 |
-
return null;
|
39 |
-
}
|
40 |
-
|
41 |
-
return $finder;
|
42 |
-
}
|
43 |
-
|
44 |
-
/**
|
45 |
-
* @param string $file full path + filename
|
46 |
-
* @param array $excludedFiles List of filenames. Can be wildcard pattern like data.php, data*.php, *.php, .php
|
47 |
-
* @return boolean
|
48 |
-
*/
|
49 |
-
public function isFilenameExcluded($file, $excludedFiles)
|
50 |
-
{
|
51 |
-
$filename = basename($file);
|
52 |
-
|
53 |
-
// Regular filenames
|
54 |
-
if (in_array($filename, $excludedFiles, true)) {
|
55 |
-
return true;
|
56 |
-
}
|
57 |
-
|
58 |
-
// Wildcards
|
59 |
-
foreach ($excludedFiles as $pattern) {
|
60 |
-
if ($this->fnmatch($pattern, $filename)) {
|
61 |
-
return true;
|
62 |
-
}
|
63 |
-
}
|
64 |
-
return false;
|
65 |
-
}
|
66 |
-
|
67 |
-
/**
|
68 |
-
* Checks if the passed string would match the given shell wildcard pattern.
|
69 |
-
* This function emulates [[fnmatch()]], which may be unavailable at certain environment, using PCRE.
|
70 |
-
* @param string $pattern the shell wildcard pattern.
|
71 |
-
* @param string $string the tested string.
|
72 |
-
* @param array $options options for matching. Valid options are:
|
73 |
-
*
|
74 |
-
* - caseSensitive: bool, whether pattern should be case sensitive. Defaults to `true`.
|
75 |
-
* - escape: bool, whether backslash escaping is enabled. Defaults to `true`.
|
76 |
-
* - filePath: bool, whether slashes in string only matches slashes in the given pattern. Defaults to `false`.
|
77 |
-
*
|
78 |
-
* @return bool whether the string matches pattern or not.
|
79 |
-
*/
|
80 |
-
protected function fnmatch($pattern, $string, $options = [])
|
81 |
-
{
|
82 |
-
if ($pattern === '*' && empty($options['filePath'])) {
|
83 |
-
return true;
|
84 |
-
}
|
85 |
-
|
86 |
-
$replacements = [
|
87 |
-
'\\\\\\\\' => '\\\\',
|
88 |
-
'\\\\\\*' => '[*]',
|
89 |
-
'\\\\\\?' => '[?]',
|
90 |
-
'\*' => '.*',
|
91 |
-
'\?' => '.',
|
92 |
-
'\[\!' => '[^',
|
93 |
-
'\[' => '[',
|
94 |
-
'\]' => ']',
|
95 |
-
'\-' => '-',
|
96 |
-
];
|
97 |
-
|
98 |
-
if (isset($options['escape']) && !$options['escape']) {
|
99 |
-
unset($replacements['\\\\\\\\'], $replacements['\\\\\\*'], $replacements['\\\\\\?']);
|
100 |
-
}
|
101 |
-
|
102 |
-
if (!empty($options['filePath'])) {
|
103 |
-
$replacements['\*'] = '[^/\\\\]*';
|
104 |
-
$replacements['\?'] = '[^/\\\\]';
|
105 |
-
}
|
106 |
-
|
107 |
-
$pattern = strtr(preg_quote($pattern, '#'), $replacements);
|
108 |
-
$pattern = '#^' . $pattern . '$#us';
|
109 |
-
if (isset($options['caseSensitive']) && !$options['caseSensitive']) {
|
110 |
-
$pattern .= 'i';
|
111 |
-
}
|
112 |
-
|
113 |
-
return preg_match($pattern, $string) === 1;
|
114 |
-
}
|
115 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Framework/Filesystem/Filesystem.php
CHANGED
@@ -2,9 +2,13 @@
|
|
2 |
|
3 |
namespace WPStaging\Framework\Filesystem;
|
4 |
|
|
|
|
|
|
|
|
|
|
|
5 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
6 |
use RuntimeException;
|
7 |
-
use WPStaging\Vendor\Symfony\Component\Filesystem\Exception\IOException;
|
8 |
use WPStaging\Vendor\Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
|
9 |
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
10 |
|
@@ -45,11 +49,11 @@ class Filesystem extends FilterableDirectoryIterator
|
|
45 |
}
|
46 |
|
47 |
foreach ($this->getNotPath() as $exclude) {
|
48 |
-
$finder->notPath($exclude);
|
49 |
}
|
50 |
|
51 |
foreach ($this->getFileNames() as $fileName) {
|
52 |
-
$finder->name($fileName);
|
53 |
}
|
54 |
|
55 |
$finder_has_results = count($finder) > 0;
|
@@ -139,6 +143,76 @@ class Filesystem extends FilterableDirectoryIterator
|
|
139 |
return $this->delete(null, false);
|
140 |
}
|
141 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
142 |
/**
|
143 |
* @param string $source
|
144 |
* @param string $target
|
@@ -162,20 +236,49 @@ class Filesystem extends FilterableDirectoryIterator
|
|
162 |
}
|
163 |
|
164 |
/**
|
165 |
-
* @param string|null $path
|
166 |
*
|
167 |
-
* @return string
|
168 |
*/
|
169 |
-
public function mkdir($path)
|
170 |
{
|
171 |
$path = $this->findPath($path);
|
|
|
172 |
if (!wp_mkdir_p($path)) {
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
174 |
}
|
175 |
|
176 |
return trailingslashit($path);
|
177 |
}
|
178 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
179 |
public function copy($source, $destination)
|
180 |
{
|
181 |
$fs = new SymfonyFilesystem;
|
@@ -184,6 +287,70 @@ class Filesystem extends FilterableDirectoryIterator
|
|
184 |
return $fs->exists($destination);
|
185 |
}
|
186 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
187 |
/**
|
188 |
* @param string
|
189 |
* @return bool
|
@@ -247,12 +414,12 @@ class Filesystem extends FilterableDirectoryIterator
|
|
247 |
|
248 |
if ($isUseNotPath) {
|
249 |
foreach ($this->getNotPath() as $exclude) {
|
250 |
-
$iterator->notPath($exclude);
|
251 |
}
|
252 |
}
|
253 |
|
254 |
foreach ($this->getFileNames() as $fileName) {
|
255 |
-
$iterator->name($fileName);
|
256 |
}
|
257 |
|
258 |
$iteratorHasResults = count($iterator) > 0;
|
@@ -292,6 +459,27 @@ class Filesystem extends FilterableDirectoryIterator
|
|
292 |
$this->log('Permission Error: Can not delete file ' . $path);
|
293 |
return false;
|
294 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
295 |
return true;
|
296 |
}
|
297 |
|
@@ -325,7 +513,7 @@ class Filesystem extends FilterableDirectoryIterator
|
|
325 |
if (!$this->isEmptyDir($path)) {
|
326 |
return false;
|
327 |
}
|
328 |
-
|
329 |
// Delete the empty directory itself and finish execution
|
330 |
if (is_dir($path)){
|
331 |
if (!rmdir($path)){
|
@@ -336,6 +524,105 @@ class Filesystem extends FilterableDirectoryIterator
|
|
336 |
return true;
|
337 |
}
|
338 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
339 |
/**
|
340 |
* @param $path
|
341 |
* @return string|null
|
@@ -473,17 +760,23 @@ class Filesystem extends FilterableDirectoryIterator
|
|
473 |
protected function deleteItem($item)
|
474 |
{
|
475 |
$path = $item->getPathname();
|
476 |
-
|
477 |
-
|
478 |
-
|
479 |
-
}
|
480 |
|
481 |
if ($item->isLink()) {
|
482 |
if(!unlink($path)) {
|
483 |
$this->log('Permission Error: Can not delete link ' . $path);
|
484 |
throw new RuntimeException('Permission Error: Can not delete link ' . $path);
|
485 |
}
|
486 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
487 |
if (!$this->isEmptyDir($path)) {
|
488 |
return false;
|
489 |
}
|
@@ -505,11 +798,56 @@ class Filesystem extends FilterableDirectoryIterator
|
|
505 |
/**
|
506 |
* @param $string
|
507 |
*/
|
508 |
-
protected function log($string)
|
|
|
509 |
if ($this->logger instanceof LoggerInterface) {
|
510 |
$this->logger->warning($string);
|
511 |
}
|
512 |
}
|
513 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
514 |
|
515 |
}
|
2 |
|
3 |
namespace WPStaging\Framework\Filesystem;
|
4 |
|
5 |
+
use WPStaging\Backend\Notices\Notices;
|
6 |
+
use WPStaging\Core\Utils\Htaccess;
|
7 |
+
use WPStaging\Core\Utils\IISWebConfig;
|
8 |
+
use WPStaging\Core\WPStaging;
|
9 |
+
use WPStaging\Framework\DI\Container;
|
10 |
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
11 |
use RuntimeException;
|
|
|
12 |
use WPStaging\Vendor\Symfony\Component\Filesystem\Filesystem as SymfonyFilesystem;
|
13 |
use WPStaging\Vendor\Symfony\Component\Finder\Finder;
|
14 |
|
49 |
}
|
50 |
|
51 |
foreach ($this->getNotPath() as $exclude) {
|
52 |
+
$finder->notPath(untrailingslashit($exclude));
|
53 |
}
|
54 |
|
55 |
foreach ($this->getFileNames() as $fileName) {
|
56 |
+
$finder->name(untrailingslashit($fileName));
|
57 |
}
|
58 |
|
59 |
$finder_has_results = count($finder) > 0;
|
143 |
return $this->delete(null, false);
|
144 |
}
|
145 |
|
146 |
+
/**
|
147 |
+
* Move content from one path to another
|
148 |
+
* This is better than $this->rename() method as this use custom fileiterator and $this->deleteNew()
|
149 |
+
* @param string $source
|
150 |
+
* @param string $target
|
151 |
+
*
|
152 |
+
* @return boolean Whether the move was successful or not.
|
153 |
+
*/
|
154 |
+
public function move($source, $target)
|
155 |
+
{
|
156 |
+
// if $source is link or file, move it and stop execution
|
157 |
+
if(is_link($source) || is_file($source)) {
|
158 |
+
return $this->renameDirect($source, $target);
|
159 |
+
}
|
160 |
+
|
161 |
+
// if $source is empty dir
|
162 |
+
if ($this->isEmptyDir($source)) {
|
163 |
+
return wp_mkdir_p($target) && @rmdir($source);
|
164 |
+
}
|
165 |
+
|
166 |
+
$this->setDirectory($source);
|
167 |
+
$iterator = null;
|
168 |
+
try {
|
169 |
+
$iterator = $this->setIteratorMode(\RecursiveIteratorIterator::CHILD_FIRST)->get();
|
170 |
+
} catch (FilesystemExceptions $e) {
|
171 |
+
$this->log('Permission Error: Can not create recursive iterator for ' . $source);
|
172 |
+
return false;
|
173 |
+
}
|
174 |
+
|
175 |
+
$basePath = trailingslashit($target);
|
176 |
+
foreach ($iterator as $item) {
|
177 |
+
if ($item->isDir() && !$this->isEmptyDir($item->getPathname())) {
|
178 |
+
continue;
|
179 |
+
}
|
180 |
+
|
181 |
+
$relativeFilePath = $iterator->getFilename();
|
182 |
+
if ($this->isIteratorRecursive()) {
|
183 |
+
$relativeFilePath = $iterator->getSubPathName();
|
184 |
+
}
|
185 |
+
|
186 |
+
$destination = $basePath . $relativeFilePath;
|
187 |
+
if (file_exists($destination)) {
|
188 |
+
continue;
|
189 |
+
}
|
190 |
+
|
191 |
+
$result = false;
|
192 |
+
// if empty dir
|
193 |
+
if ($item->isDir()) {
|
194 |
+
$result = wp_mkdir_p($destination) && @rmdir($item->getPathname());
|
195 |
+
} else { // if file or link
|
196 |
+
$result = $this->renameDirect($item->getPathname(), $destination);
|
197 |
+
}
|
198 |
+
|
199 |
+
if (!$result || !is_callable($this->shouldStop)) {
|
200 |
+
continue;
|
201 |
+
}
|
202 |
+
|
203 |
+
if (call_user_func($this->shouldStop)) {
|
204 |
+
return false;
|
205 |
+
}
|
206 |
+
}
|
207 |
+
|
208 |
+
$deleteSelf = true;
|
209 |
+
if (count($this->getExcludePaths()) > 0 || !$this->isIteratorRecursive()) {
|
210 |
+
$deleteSelf = false;
|
211 |
+
}
|
212 |
+
|
213 |
+
return $this->deleteNew($source, $deleteSelf);
|
214 |
+
}
|
215 |
+
|
216 |
/**
|
217 |
* @param string $source
|
218 |
* @param string $target
|
236 |
}
|
237 |
|
238 |
/**
|
239 |
+
* @param string|null $path The path to the new folder, or null to use FileSystem's path.
|
240 |
*
|
241 |
+
* @return string Path to newly created folder, or empty string if couldn't create it.
|
242 |
*/
|
243 |
+
public function mkdir($path, $preventDirectoryListing = false)
|
244 |
{
|
245 |
$path = $this->findPath($path);
|
246 |
+
|
247 |
if (!wp_mkdir_p($path)) {
|
248 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
249 |
+
error_log("Failed to create directory $path");
|
250 |
+
}
|
251 |
+
|
252 |
+
return '';
|
253 |
+
}
|
254 |
+
|
255 |
+
if ($preventDirectoryListing) {
|
256 |
+
/** @var DirectoryListing $directoryListing */
|
257 |
+
$directoryListing = WPStaging::getInstance()->getContainer()->make(DirectoryListing::class);
|
258 |
+
try {
|
259 |
+
$directoryListing->preventDirectoryListing($path);
|
260 |
+
} catch(\Exception $e) {
|
261 |
+
/**
|
262 |
+
* Enqueue this error. All enqueued errors will be shown as a single notice.
|
263 |
+
*
|
264 |
+
* @see \WPStaging\Backend\Notices\Notices::showDirectoryListingWarningNotice
|
265 |
+
*/
|
266 |
+
WPStaging::getInstance()->getContainer()->pushToArray(Notices::$directoryListingErrors, $e->getMessage());
|
267 |
+
}
|
268 |
}
|
269 |
|
270 |
return trailingslashit($path);
|
271 |
}
|
272 |
|
273 |
+
/**
|
274 |
+
* Copy file
|
275 |
+
*
|
276 |
+
* @param string $source
|
277 |
+
* @param string $destination
|
278 |
+
* @return boolean
|
279 |
+
*
|
280 |
+
* @todo update this to allow copying big files
|
281 |
+
*/
|
282 |
public function copy($source, $destination)
|
283 |
{
|
284 |
$fs = new SymfonyFilesystem;
|
287 |
return $fs->exists($destination);
|
288 |
}
|
289 |
|
290 |
+
/**
|
291 |
+
* The new copy method which works for files, links and directories
|
292 |
+
*
|
293 |
+
* @param string $source
|
294 |
+
* @param string $target
|
295 |
+
* @return boolean
|
296 |
+
*/
|
297 |
+
public function copyNew($source, $target)
|
298 |
+
{
|
299 |
+
// if $source is link or file, move it and stop execution
|
300 |
+
if(is_link($source) || is_file($source)) {
|
301 |
+
return $this->copy($source, $target);
|
302 |
+
}
|
303 |
+
|
304 |
+
// if $source is empty dir
|
305 |
+
if ($this->isEmptyDir($source)) {
|
306 |
+
return wp_mkdir_p($target);
|
307 |
+
}
|
308 |
+
|
309 |
+
$this->setDirectory($source);
|
310 |
+
$iterator = null;
|
311 |
+
try {
|
312 |
+
$iterator = $this->setIteratorMode(\RecursiveIteratorIterator::CHILD_FIRST)->get();
|
313 |
+
} catch (FilesystemExceptions $e) {
|
314 |
+
$this->log('Permission Error: Can not create recursive iterator for ' . $source);
|
315 |
+
return false;
|
316 |
+
}
|
317 |
+
|
318 |
+
$basePath = trailingslashit($target);
|
319 |
+
foreach ($iterator as $item) {
|
320 |
+
if ($item->isDir() && !$this->isEmptyDir($item->getPathname())) {
|
321 |
+
continue;
|
322 |
+
}
|
323 |
+
|
324 |
+
$relativeFilePath = $iterator->getFilename();
|
325 |
+
if ($this->isIteratorRecursive()) {
|
326 |
+
$relativeFilePath = $iterator->getSubPathName();
|
327 |
+
}
|
328 |
+
|
329 |
+
$destination = $basePath . $relativeFilePath;
|
330 |
+
if (file_exists($destination)) {
|
331 |
+
continue;
|
332 |
+
}
|
333 |
+
|
334 |
+
$result = false;
|
335 |
+
// if empty dir
|
336 |
+
if ($item->isDir()) {
|
337 |
+
$result = wp_mkdir_p($destination);
|
338 |
+
} else { // if file or link
|
339 |
+
$result = $this->copy($item->getPathname(), $destination);
|
340 |
+
}
|
341 |
+
|
342 |
+
if (!$result || !is_callable($this->shouldStop)) {
|
343 |
+
continue;
|
344 |
+
}
|
345 |
+
|
346 |
+
if (call_user_func($this->shouldStop)) {
|
347 |
+
return false;
|
348 |
+
}
|
349 |
+
}
|
350 |
+
|
351 |
+
return true;
|
352 |
+
}
|
353 |
+
|
354 |
/**
|
355 |
* @param string
|
356 |
* @return bool
|
414 |
|
415 |
if ($isUseNotPath) {
|
416 |
foreach ($this->getNotPath() as $exclude) {
|
417 |
+
$iterator->notPath(untrailingslashit($exclude));
|
418 |
}
|
419 |
}
|
420 |
|
421 |
foreach ($this->getFileNames() as $fileName) {
|
422 |
+
$iterator->name(untrailingslashit($fileName));
|
423 |
}
|
424 |
|
425 |
$iteratorHasResults = count($iterator) > 0;
|
459 |
$this->log('Permission Error: Can not delete file ' . $path);
|
460 |
return false;
|
461 |
}
|
462 |
+
|
463 |
+
return true;
|
464 |
+
}
|
465 |
+
|
466 |
+
// Assume it is already deleted
|
467 |
+
if (!is_dir($path)){
|
468 |
+
return true;
|
469 |
+
}
|
470 |
+
|
471 |
+
// delete the directory if it is empty and deleteSelf was true
|
472 |
+
if (is_dir($path) && $this->isEmptyDir($path) && $deleteSelf) {
|
473 |
+
if (!@rmdir($path)){
|
474 |
+
$this->log('Permission Error: Can not delete directory ' . $path);
|
475 |
+
return false;
|
476 |
+
}
|
477 |
+
|
478 |
+
return true;
|
479 |
+
}
|
480 |
+
|
481 |
+
// return since directory was empty and deleteSelf was false
|
482 |
+
if (is_dir($path) && $this->isEmptyDir($path) && !$deleteSelf) {
|
483 |
return true;
|
484 |
}
|
485 |
|
513 |
if (!$this->isEmptyDir($path)) {
|
514 |
return false;
|
515 |
}
|
516 |
+
|
517 |
// Delete the empty directory itself and finish execution
|
518 |
if (is_dir($path)){
|
519 |
if (!rmdir($path)){
|
524 |
return true;
|
525 |
}
|
526 |
|
527 |
+
/**
|
528 |
+
* @param string $file full path + filename
|
529 |
+
* @param array $excludedFiles List of filenames. Can be wildcard pattern like data.php, data*.php, *.php, .php
|
530 |
+
* @return boolean
|
531 |
+
*/
|
532 |
+
public function isFilenameExcluded($file, $excludedFiles)
|
533 |
+
{
|
534 |
+
$filename = basename($file);
|
535 |
+
|
536 |
+
// Regular filenames
|
537 |
+
if (in_array($filename, $excludedFiles, true)) {
|
538 |
+
return true;
|
539 |
+
}
|
540 |
+
|
541 |
+
// Wildcards
|
542 |
+
foreach ($excludedFiles as $pattern) {
|
543 |
+
if ($this->fnmatch($pattern, $filename)) {
|
544 |
+
return true;
|
545 |
+
}
|
546 |
+
}
|
547 |
+
return false;
|
548 |
+
}
|
549 |
+
|
550 |
+
/**
|
551 |
+
* Checks if the passed string would match the given shell wildcard pattern.
|
552 |
+
* This function emulates [[fnmatch()]], which may be unavailable at certain environment, using PCRE.
|
553 |
+
* @param string $pattern the shell wildcard pattern.
|
554 |
+
* @param string $string the tested string.
|
555 |
+
* @param array $options options for matching. Valid options are:
|
556 |
+
*
|
557 |
+
* - caseSensitive: bool, whether pattern should be case sensitive. Defaults to `true`.
|
558 |
+
* - escape: bool, whether backslash escaping is enabled. Defaults to `true`.
|
559 |
+
* - filePath: bool, whether slashes in string only matches slashes in the given pattern. Defaults to `false`.
|
560 |
+
*
|
561 |
+
* @return bool whether the string matches pattern or not.
|
562 |
+
*/
|
563 |
+
protected function fnmatch($pattern, $string, $options = [])
|
564 |
+
{
|
565 |
+
if ($pattern === '*' && empty($options['filePath'])) {
|
566 |
+
return true;
|
567 |
+
}
|
568 |
+
|
569 |
+
$replacements = [
|
570 |
+
'\\\\\\\\' => '\\\\',
|
571 |
+
'\\\\\\*' => '[*]',
|
572 |
+
'\\\\\\?' => '[?]',
|
573 |
+
'\*' => '.*',
|
574 |
+
'\?' => '.',
|
575 |
+
'\[\!' => '[^',
|
576 |
+
'\[' => '[',
|
577 |
+
'\]' => ']',
|
578 |
+
'\-' => '-',
|
579 |
+
];
|
580 |
+
|
581 |
+
if (isset($options['escape']) && !$options['escape']) {
|
582 |
+
unset($replacements['\\\\\\\\'], $replacements['\\\\\\*'], $replacements['\\\\\\?']);
|
583 |
+
}
|
584 |
+
|
585 |
+
if (!empty($options['filePath'])) {
|
586 |
+
$replacements['\*'] = '[^/\\\\]*';
|
587 |
+
$replacements['\?'] = '[^/\\\\]';
|
588 |
+
}
|
589 |
+
|
590 |
+
$pattern = strtr(preg_quote($pattern, '#'), $replacements);
|
591 |
+
$pattern = '#^' . $pattern . '$#us';
|
592 |
+
if (isset($options['caseSensitive']) && !$options['caseSensitive']) {
|
593 |
+
$pattern .= 'i';
|
594 |
+
}
|
595 |
+
|
596 |
+
return preg_match($pattern, $string) === 1;
|
597 |
+
}
|
598 |
+
|
599 |
+
/**
|
600 |
+
* @param array $paths
|
601 |
+
* @return boolean
|
602 |
+
*/
|
603 |
+
public function deletePaths($paths)
|
604 |
+
{
|
605 |
+
foreach ($paths as $path) {
|
606 |
+
// only delete the dir if empty
|
607 |
+
// helpful when we exclude path(s) during delete
|
608 |
+
if (is_dir($path) && $this->isEmptyDir($path)) {
|
609 |
+
if (!@rmdir($path)){
|
610 |
+
$this->log('Permission Error: Can not delete directory ' . $path);
|
611 |
+
throw new RuntimeException('Permission Error: Can not delete directory ' . $path);
|
612 |
+
}
|
613 |
+
|
614 |
+
continue;
|
615 |
+
}
|
616 |
+
|
617 |
+
// force to not delete the parent path itself
|
618 |
+
if (!$this->deleteNew($path, false)) {
|
619 |
+
return false;
|
620 |
+
}
|
621 |
+
}
|
622 |
+
|
623 |
+
return true;
|
624 |
+
}
|
625 |
+
|
626 |
/**
|
627 |
* @param $path
|
628 |
* @return string|null
|
760 |
protected function deleteItem($item)
|
761 |
{
|
762 |
$path = $item->getPathname();
|
763 |
+
|
764 |
+
$perms = substr(sprintf('%o', fileperms($path)), -4);
|
765 |
+
$this->log('Permission Error: Can not delete link ' . $perms);
|
|
|
766 |
|
767 |
if ($item->isLink()) {
|
768 |
if(!unlink($path)) {
|
769 |
$this->log('Permission Error: Can not delete link ' . $path);
|
770 |
throw new RuntimeException('Permission Error: Can not delete link ' . $path);
|
771 |
}
|
772 |
+
}
|
773 |
+
|
774 |
+
// Checks whether that file or directory exists
|
775 |
+
if (!file_exists($path)) {
|
776 |
+
return true;
|
777 |
+
}
|
778 |
+
|
779 |
+
if ($item->isDir()) {
|
780 |
if (!$this->isEmptyDir($path)) {
|
781 |
return false;
|
782 |
}
|
798 |
/**
|
799 |
* @param $string
|
800 |
*/
|
801 |
+
protected function log($string)
|
802 |
+
{
|
803 |
if ($this->logger instanceof LoggerInterface) {
|
804 |
$this->logger->warning($string);
|
805 |
}
|
806 |
}
|
807 |
|
808 |
+
/**
|
809 |
+
* Create a file with content
|
810 |
+
*
|
811 |
+
* @param string $path Path to the file
|
812 |
+
* @param string $content Content of the file
|
813 |
+
* @return boolean
|
814 |
+
*/
|
815 |
+
public function create( $path, $content ) {
|
816 |
+
if( !@file_exists( $path ) ) {
|
817 |
+
if( !@is_writable( dirname( $path ) ) ) {
|
818 |
+
return false;
|
819 |
+
}
|
820 |
+
|
821 |
+
if( !@touch( $path ) ) {
|
822 |
+
return false;
|
823 |
+
}
|
824 |
+
} elseif( !@is_writable( $path ) ) {
|
825 |
+
return false;
|
826 |
+
}
|
827 |
+
|
828 |
+
$written = false;
|
829 |
+
if( ( $handle = @fopen( $path, 'w' ) ) !== false ) {
|
830 |
+
if( @fwrite( $handle, $content ) !== false ) {
|
831 |
+
$written = true;
|
832 |
+
}
|
833 |
+
|
834 |
+
@fclose( $handle );
|
835 |
+
}
|
836 |
+
|
837 |
+
return $written;
|
838 |
+
}
|
839 |
+
|
840 |
+
/**
|
841 |
+
* Create a file with marker and content
|
842 |
+
*
|
843 |
+
* @param string $path Path to the file
|
844 |
+
* @param string $marker Name of the marker
|
845 |
+
* @param string $content Content of the file
|
846 |
+
* @return boolean
|
847 |
+
*/
|
848 |
+
public function createWithMarkers( $path, $marker, $content ) {
|
849 |
+
return @insert_with_markers( $path, $marker, $content );
|
850 |
+
}
|
851 |
+
|
852 |
|
853 |
}
|
Framework/Filesystem/Permissions.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
|
4 |
+
namespace WPStaging\Framework\Filesystem;
|
5 |
+
|
6 |
+
|
7 |
+
class Permissions
|
8 |
+
{
|
9 |
+
/**
|
10 |
+
* @return int
|
11 |
+
*/
|
12 |
+
public function getDirectoryOctal()
|
13 |
+
{
|
14 |
+
$octal = 0755;
|
15 |
+
if (defined('FS_CHMOD_DIR')) {
|
16 |
+
$octal = FS_CHMOD_DIR;
|
17 |
+
}
|
18 |
+
|
19 |
+
return apply_filters('wpstg_folder_permission', $octal);
|
20 |
+
}
|
21 |
+
|
22 |
+
/**
|
23 |
+
* @return int
|
24 |
+
*/
|
25 |
+
public function getFilesOctal()
|
26 |
+
{
|
27 |
+
if (defined('FS_CHMOD_FILE')) {
|
28 |
+
return FS_CHMOD_FILE;
|
29 |
+
}
|
30 |
+
|
31 |
+
return 0644;
|
32 |
+
}
|
33 |
+
|
34 |
+
|
35 |
+
}
|
Framework/Filesystem/WpUploadsFolderSymlinker.php
CHANGED
@@ -60,9 +60,9 @@ class WpUploadsFolderSymlinker
|
|
60 |
|
61 |
$uploadPath = $this->wpDirectories->getUploadPath();
|
62 |
|
63 |
-
|
64 |
|
65 |
-
if (
|
66 |
$this->error = "Can not symlink " . $uploadPath . "to " . $this->stagingUploadPath;
|
67 |
return false;
|
68 |
}
|
@@ -78,21 +78,4 @@ class WpUploadsFolderSymlinker
|
|
78 |
{
|
79 |
return $this->error;
|
80 |
}
|
81 |
-
|
82 |
-
/**
|
83 |
-
* Create staging sites upload directory ready to be connected via symlink to the production site
|
84 |
-
* Directory must exist before i
|
85 |
-
*/
|
86 |
-
protected function createDirectory($path)
|
87 |
-
{
|
88 |
-
$dirname = dirname($path);
|
89 |
-
$directories = explode(DIRECTORY_SEPARATOR, $dirname);
|
90 |
-
$currentDirectory = '';
|
91 |
-
foreach ($directories as $directory) {
|
92 |
-
$currentDirectory .= $directory . DIRECTORY_SEPARATOR;
|
93 |
-
if (!file_exists($currentDirectory)) {
|
94 |
-
mkdir($currentDirectory, 0755);
|
95 |
-
}
|
96 |
-
}
|
97 |
-
}
|
98 |
-
}
|
60 |
|
61 |
$uploadPath = $this->wpDirectories->getUploadPath();
|
62 |
|
63 |
+
(new Filesystem)->mkdir(dirname($this->stagingUploadPath));
|
64 |
|
65 |
+
if (!symlink($uploadPath, $this->stagingUploadPath)) {
|
66 |
$this->error = "Can not symlink " . $uploadPath . "to " . $this->stagingUploadPath;
|
67 |
return false;
|
68 |
}
|
78 |
{
|
79 |
return $this->error;
|
80 |
}
|
81 |
+
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Framework/Mails/Report/Report.php
CHANGED
@@ -20,6 +20,14 @@ class Report
|
|
20 |
*/
|
21 |
const EMAIL_SUBJECT = "Report Issue!";
|
22 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
23 |
/**
|
24 |
* Send customer issue report
|
25 |
*
|
@@ -55,7 +63,6 @@ class Report
|
|
55 |
}
|
56 |
|
57 |
$attachments = [];
|
58 |
-
$maxFileSize = 512 * 1024;
|
59 |
if ($provider) {
|
60 |
$message .= "\n\n'Hosting provider: " . $provider;
|
61 |
}
|
@@ -63,13 +70,13 @@ class Report
|
|
63 |
if (!empty($syslog)) {
|
64 |
$message .= "\n\n'" . $this->getSyslog();
|
65 |
$debugLogFile = WP_CONTENT_DIR . '/debug.log';
|
66 |
-
if (
|
67 |
$attachments[] = $debugLogFile;
|
68 |
}
|
69 |
}
|
70 |
|
71 |
$transient = new ReportSubmitTransient();
|
72 |
-
if ($transient->getTransient()
|
73 |
// to show alert using js
|
74 |
$errors[] = [
|
75 |
"status" => 'already_submitted',
|
20 |
*/
|
21 |
const EMAIL_SUBJECT = "Report Issue!";
|
22 |
|
23 |
+
/**
|
24 |
+
* Maximum attachment file size of 5MB
|
25 |
+
*
|
26 |
+
* @var int
|
27 |
+
*
|
28 |
+
*/
|
29 |
+
const ATTACHMENT_MAX_FILE_SIZE = 5242880;
|
30 |
+
|
31 |
/**
|
32 |
* Send customer issue report
|
33 |
*
|
63 |
}
|
64 |
|
65 |
$attachments = [];
|
|
|
66 |
if ($provider) {
|
67 |
$message .= "\n\n'Hosting provider: " . $provider;
|
68 |
}
|
70 |
if (!empty($syslog)) {
|
71 |
$message .= "\n\n'" . $this->getSyslog();
|
72 |
$debugLogFile = WP_CONTENT_DIR . '/debug.log';
|
73 |
+
if (file_exists($debugLogFile) && self::ATTACHMENT_MAX_FILE_SIZE > filesize($debugLogFile)) {
|
74 |
$attachments[] = $debugLogFile;
|
75 |
}
|
76 |
}
|
77 |
|
78 |
$transient = new ReportSubmitTransient();
|
79 |
+
if (!$forceSend && $transient->getTransient() ) {
|
80 |
// to show alert using js
|
81 |
$errors[] = [
|
82 |
"status" => 'already_submitted',
|
Framework/Security/Auth.php
ADDED
@@ -0,0 +1,67 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Framework\Security;
|
4 |
+
|
5 |
+
/**
|
6 |
+
* Class Auth
|
7 |
+
*
|
8 |
+
* This class provide helping methods for authentication different kinds of request
|
9 |
+
* like ajax, non-ajax etc
|
10 |
+
*
|
11 |
+
* @package WPStaging\Framework\Security
|
12 |
+
*/
|
13 |
+
class Auth
|
14 |
+
{
|
15 |
+
/**
|
16 |
+
* @var Capabilities
|
17 |
+
*/
|
18 |
+
protected $capabilities;
|
19 |
+
|
20 |
+
/**
|
21 |
+
* @var AccessToken
|
22 |
+
*/
|
23 |
+
protected $accessToken;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* @var Nonce
|
27 |
+
*/
|
28 |
+
protected $nonce;
|
29 |
+
|
30 |
+
/**
|
31 |
+
* @param Capabilities $capabilities
|
32 |
+
* @param AccessToken $accessToken
|
33 |
+
* @param Nonce $nonce
|
34 |
+
*/
|
35 |
+
public function __construct(Capabilities $capabilities, AccessToken $accessToken, Nonce $nonce)
|
36 |
+
{
|
37 |
+
$this->capabilities = $capabilities;
|
38 |
+
$this->accessToken = $accessToken;
|
39 |
+
$this->nonce = $nonce;
|
40 |
+
}
|
41 |
+
|
42 |
+
/**
|
43 |
+
* Validate (ajax) request with wpstg nonce or access token.
|
44 |
+
* Criteria to be a valid request should satisfy any point below:
|
45 |
+
*
|
46 |
+
* A. User must be logged in and must have capability to manage WP Staging.
|
47 |
+
* WP Staging Nonce must be valid
|
48 |
+
* or
|
49 |
+
* B. WP Staging Access Token must be valid
|
50 |
+
*
|
51 |
+
*
|
52 |
+
* @param string $nonce
|
53 |
+
* @return bool
|
54 |
+
*/
|
55 |
+
public function isValid($nonce = Nonce::WPSTG_NONCE)
|
56 |
+
{
|
57 |
+
if (
|
58 |
+
$this->nonce->requestHasValidNonce($nonce) &&
|
59 |
+
current_user_can($this->capabilities->manageWPSTG())
|
60 |
+
|
61 |
+
) {
|
62 |
+
return true;
|
63 |
+
}
|
64 |
+
|
65 |
+
return $this->accessToken->requestHasValidToken();
|
66 |
+
}
|
67 |
+
}
|
Framework/Staging/FirstRun.php
CHANGED
@@ -20,14 +20,19 @@ class FirstRun
|
|
20 |
*/
|
21 |
const FIRST_RUN_KEY = 'wpstg_execute';
|
22 |
|
|
|
|
|
|
|
|
|
|
|
23 |
|
24 |
public function init()
|
25 |
{
|
26 |
-
if (
|
27 |
return;
|
28 |
}
|
29 |
|
30 |
-
if (
|
31 |
return;
|
32 |
}
|
33 |
|
@@ -48,6 +53,11 @@ class FirstRun
|
|
48 |
// Enable the disabled cache notice to be shown on the staging site admin.
|
49 |
(new DisabledCacheNotice())->enable();
|
50 |
|
|
|
|
|
|
|
|
|
|
|
51 |
// Allow users to attach custom actions by using this hook
|
52 |
do_action('wpstg.clone_first_run');
|
53 |
|
20 |
*/
|
21 |
const FIRST_RUN_KEY = 'wpstg_execute';
|
22 |
|
23 |
+
/**
|
24 |
+
* The option_name that is stored in the database to check whether mails are disabled or not
|
25 |
+
*/
|
26 |
+
const MAILS_DISABLED_KEY = 'wpstg_emails_disabled';
|
27 |
+
|
28 |
|
29 |
public function init()
|
30 |
{
|
31 |
+
if (!(new SiteInfo)->isStaging()) {
|
32 |
return;
|
33 |
}
|
34 |
|
35 |
+
if (!get_option(self::FIRST_RUN_KEY)) {
|
36 |
return;
|
37 |
}
|
38 |
|
53 |
// Enable the disabled cache notice to be shown on the staging site admin.
|
54 |
(new DisabledCacheNotice())->enable();
|
55 |
|
56 |
+
// Enable the disabled mail notice to be shown on the staging site admin.
|
57 |
+
if (defined('WPSTGPRO_VERSION')) {
|
58 |
+
(new \WPStaging\Backend\Pro\Notices\DisabledMailNotice())->enable();
|
59 |
+
}
|
60 |
+
|
61 |
// Allow users to attach custom actions by using this hook
|
62 |
do_action('wpstg.clone_first_run');
|
63 |
|
Framework/Traits/BenchmarkTrait.php
ADDED
@@ -0,0 +1,42 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
namespace WPStaging\Framework\Traits;
|
4 |
+
|
5 |
+
use WPStaging\Core\Utils\Logger;
|
6 |
+
use WPStaging\Core\WPStaging;
|
7 |
+
use WPStaging\Vendor\Psr\Log\LoggerInterface;
|
8 |
+
|
9 |
+
trait BenchmarkTrait
|
10 |
+
{
|
11 |
+
private $benchmarkLogger;
|
12 |
+
private $benchmarkStart = 0;
|
13 |
+
|
14 |
+
private function startBenchmark()
|
15 |
+
{
|
16 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
17 |
+
/** @var Logger $logger */
|
18 |
+
$this->benchmarkLogger = clone WPStaging::getInstance()->get(Logger::class);
|
19 |
+
|
20 |
+
// Eg: JobSiteExport_Benchmark
|
21 |
+
$filename = sanitize_file_name(sprintf('%s_Benchmark',
|
22 |
+
(new \ReflectionClass($this))->getShortName()
|
23 |
+
));
|
24 |
+
|
25 |
+
$this->benchmarkLogger->setFileName($filename);
|
26 |
+
$this->benchmarkStart = microtime(true);
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
private function finishBenchmark($context)
|
31 |
+
{
|
32 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG && $this->benchmarkLogger instanceof LoggerInterface) {
|
33 |
+
$message = sprintf(
|
34 |
+
'Finished %s in %s seconds',
|
35 |
+
$context,
|
36 |
+
microtime(true) - $this->benchmarkStart
|
37 |
+
);
|
38 |
+
|
39 |
+
$this->benchmarkLogger->info($message);
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
Framework/Traits/HydrateTrait.php
CHANGED
@@ -25,7 +25,13 @@ trait HydrateTrait
|
|
25 |
{
|
26 |
foreach ($data as $key => $value) {
|
27 |
/** @noinspection PhpUnhandledExceptionInspection */
|
28 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
29 |
}
|
30 |
|
31 |
return $this;
|
@@ -40,7 +46,10 @@ trait HydrateTrait
|
|
40 |
private function hydrateByMethod($method, $value)
|
41 |
{
|
42 |
if (!method_exists($this, $method)) {
|
43 |
-
|
|
|
|
|
|
|
44 |
}
|
45 |
|
46 |
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
25 |
{
|
26 |
foreach ($data as $key => $value) {
|
27 |
/** @noinspection PhpUnhandledExceptionInspection */
|
28 |
+
try {
|
29 |
+
$this->hydrateByMethod('set' . ucfirst($key), $value);
|
30 |
+
} catch(Exception $e) {
|
31 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
32 |
+
error_log($e->getMessage());
|
33 |
+
}
|
34 |
+
}
|
35 |
}
|
36 |
|
37 |
return $this;
|
46 |
private function hydrateByMethod($method, $value)
|
47 |
{
|
48 |
if (!method_exists($this, $method)) {
|
49 |
+
if (!is_string($value)) {
|
50 |
+
$value = wp_json_encode($value);
|
51 |
+
}
|
52 |
+
throw new Exception(sprintf('Trying to hydrate DTO with value that does not exist. \n %s \n %s \n %s', get_class($this), $method, $value));
|
53 |
}
|
54 |
|
55 |
/** @noinspection CallableParameterUseCaseInTypeContextInspection */
|
Framework/Traits/ResourceTrait.php
CHANGED
@@ -2,23 +2,18 @@
|
|
2 |
|
3 |
namespace WPStaging\Framework\Traits;
|
4 |
|
5 |
-
use WPStaging\Entity\Settings;
|
6 |
use WPStaging\Framework\Utils\Size;
|
7 |
-
use WPStaging\Repository\SettingsRepository;
|
8 |
|
9 |
trait ResourceTrait
|
10 |
{
|
11 |
use TimerTrait;
|
12 |
|
13 |
-
/** @var SettingsRepository */
|
14 |
-
protected $settingsRepository;
|
15 |
-
|
16 |
-
/** @var Settings */
|
17 |
-
protected $settings;
|
18 |
-
|
19 |
/** @var int|null */
|
20 |
protected $timeLimit;
|
21 |
|
|
|
|
|
|
|
22 |
/**
|
23 |
* @return bool
|
24 |
*/
|
@@ -32,6 +27,15 @@ trait ResourceTrait
|
|
32 |
*/
|
33 |
public function isMemoryLimit()
|
34 |
{
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
35 |
$limit = (new Size)->toBytes(ini_get('memory_limit'));
|
36 |
|
37 |
if (!is_int($limit) || $limit < 64000000){
|
@@ -46,7 +50,17 @@ trait ResourceTrait
|
|
46 |
*/
|
47 |
public function isTimeLimit()
|
48 |
{
|
49 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
50 |
|
51 |
if ($this->timeLimit !== null) {
|
52 |
$timeLimit = $this->timeLimit;
|
@@ -55,6 +69,19 @@ trait ResourceTrait
|
|
55 |
}
|
56 |
// TODO Recursion for xDebug? Recursion is bad idea will cause more resource usage, need to avoid it.
|
57 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
/**
|
59 |
* @param bool $realUsage
|
60 |
* @return int
|
@@ -73,36 +100,6 @@ trait ResourceTrait
|
|
73 |
return memory_get_peak_usage($realUsage);
|
74 |
}
|
75 |
|
76 |
-
/**
|
77 |
-
* @return SettingsRepository
|
78 |
-
*/
|
79 |
-
public function getSettingsRepository()
|
80 |
-
{
|
81 |
-
if (!$this->settingsRepository) {
|
82 |
-
$this->settingsRepository = new SettingsRepository;
|
83 |
-
}
|
84 |
-
return $this->settingsRepository;
|
85 |
-
}
|
86 |
-
|
87 |
-
/**
|
88 |
-
* @param SettingsRepository $settingsRepository
|
89 |
-
*/
|
90 |
-
public function setSettingsRepository(SettingsRepository $settingsRepository)
|
91 |
-
{
|
92 |
-
$this->settingsRepository = $settingsRepository;
|
93 |
-
}
|
94 |
-
|
95 |
-
/**
|
96 |
-
* @return Settings
|
97 |
-
*/
|
98 |
-
public function getSettings()
|
99 |
-
{
|
100 |
-
if (!$this->settings) {
|
101 |
-
$this->settings = $this->getSettingsRepository()->find();
|
102 |
-
}
|
103 |
-
return $this->settings;
|
104 |
-
}
|
105 |
-
|
106 |
/**
|
107 |
* @return int|null
|
108 |
*/
|
2 |
|
3 |
namespace WPStaging\Framework\Traits;
|
4 |
|
|
|
5 |
use WPStaging\Framework\Utils\Size;
|
|
|
6 |
|
7 |
trait ResourceTrait
|
8 |
{
|
9 |
use TimerTrait;
|
10 |
|
|
|
|
|
|
|
|
|
|
|
|
|
11 |
/** @var int|null */
|
12 |
protected $timeLimit;
|
13 |
|
14 |
+
private static $default_max_execution_time_in_seconds = 30;
|
15 |
+
private static $execution_time_gap_in_seconds = 5;
|
16 |
+
|
17 |
/**
|
18 |
* @return bool
|
19 |
*/
|
27 |
*/
|
28 |
public function isMemoryLimit()
|
29 |
{
|
30 |
+
/**
|
31 |
+
* Overriding this filter to return true allows someone to ignore memory limits.
|
32 |
+
*/
|
33 |
+
$ignoreTimeLimit = (bool)apply_filters('wpstg.resources.ignoreMemoryLimit', false);
|
34 |
+
|
35 |
+
if ($ignoreTimeLimit) {
|
36 |
+
return false;
|
37 |
+
}
|
38 |
+
|
39 |
$limit = (new Size)->toBytes(ini_get('memory_limit'));
|
40 |
|
41 |
if (!is_int($limit) || $limit < 64000000){
|
50 |
*/
|
51 |
public function isTimeLimit()
|
52 |
{
|
53 |
+
/**
|
54 |
+
* Overriding this filter to return true allows someone to ignore time limits.
|
55 |
+
* Useful for developers using xdebug, for instance.
|
56 |
+
*/
|
57 |
+
$ignoreTimeLimit = (bool)apply_filters('wpstg.resources.ignoreTimeLimit', false);
|
58 |
+
|
59 |
+
if ($ignoreTimeLimit) {
|
60 |
+
return false;
|
61 |
+
}
|
62 |
+
|
63 |
+
$timeLimit = $this->findExecutionTimeLimit();
|
64 |
|
65 |
if ($this->timeLimit !== null) {
|
66 |
$timeLimit = $this->timeLimit;
|
69 |
}
|
70 |
// TODO Recursion for xDebug? Recursion is bad idea will cause more resource usage, need to avoid it.
|
71 |
|
72 |
+
/**
|
73 |
+
* @return float|int
|
74 |
+
*/
|
75 |
+
public function findExecutionTimeLimit()
|
76 |
+
{
|
77 |
+
$executionTime = (int) ini_get('max_execution_time');
|
78 |
+
// TODO don't overwrite when CLI / SAPI and / or add setting to not overwrite for devs
|
79 |
+
if (!$executionTime || $executionTime > static::$default_max_execution_time_in_seconds) {
|
80 |
+
$executionTime = static::$default_max_execution_time_in_seconds;
|
81 |
+
}
|
82 |
+
return $executionTime - static::$execution_time_gap_in_seconds;
|
83 |
+
}
|
84 |
+
|
85 |
/**
|
86 |
* @param bool $realUsage
|
87 |
* @return int
|
100 |
return memory_get_peak_usage($realUsage);
|
101 |
}
|
102 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
/**
|
104 |
* @return int|null
|
105 |
*/
|
Framework/Traits/TimerTrait.php
CHANGED
@@ -2,9 +2,6 @@
|
|
2 |
|
3 |
namespace WPStaging\Framework\Traits;
|
4 |
|
5 |
-
use WPStaging\Entity\Settings;
|
6 |
-
use WPStaging\Repository\SettingsRepository;
|
7 |
-
|
8 |
trait TimerTrait
|
9 |
{
|
10 |
/** @var float */
|
@@ -23,4 +20,4 @@ trait TimerTrait
|
|
23 |
{
|
24 |
return time() - $this->startTime;
|
25 |
}
|
26 |
-
}
|
2 |
|
3 |
namespace WPStaging\Framework\Traits;
|
4 |
|
|
|
|
|
|
|
5 |
trait TimerTrait
|
6 |
{
|
7 |
/** @var float */
|
20 |
{
|
21 |
return time() - $this->startTime;
|
22 |
}
|
23 |
+
}
|
Framework/Utils/Cache/AbstractCache.php
CHANGED
@@ -6,7 +6,7 @@
|
|
6 |
|
7 |
namespace WPStaging\Framework\Utils\Cache;
|
8 |
|
9 |
-
|
10 |
use WPStaging\Vendor\Symfony\Component\Filesystem\Exception\IOException;
|
11 |
use WPStaging\Framework\Adapter\Directory;
|
12 |
|
@@ -90,6 +90,9 @@ abstract class AbstractCache
|
|
90 |
public function setPath($path)
|
91 |
{
|
92 |
$this->path = $path;
|
|
|
|
|
|
|
93 |
$this->initializeFilePath();
|
94 |
}
|
95 |
|
6 |
|
7 |
namespace WPStaging\Framework\Utils\Cache;
|
8 |
|
9 |
+
use WPStaging\Framework\Filesystem\Filesystem;
|
10 |
use WPStaging\Vendor\Symfony\Component\Filesystem\Exception\IOException;
|
11 |
use WPStaging\Framework\Adapter\Directory;
|
12 |
|
90 |
public function setPath($path)
|
91 |
{
|
92 |
$this->path = $path;
|
93 |
+
|
94 |
+
(new Filesystem)->mkdir($path);
|
95 |
+
|
96 |
$this->initializeFilePath();
|
97 |
}
|
98 |
|
Framework/Utils/Cache/Cache.php
CHANGED
@@ -7,7 +7,6 @@
|
|
7 |
namespace WPStaging\Framework\Utils\Cache;
|
8 |
|
9 |
use WPStaging\Framework\Filesystem\File;
|
10 |
-
use WPStaging\Framework\Filesystem\Filesystem;
|
11 |
|
12 |
class Cache extends AbstractCache
|
13 |
{
|
7 |
namespace WPStaging\Framework\Utils\Cache;
|
8 |
|
9 |
use WPStaging\Framework\Filesystem\File;
|
|
|
10 |
|
11 |
class Cache extends AbstractCache
|
12 |
{
|
Framework/Utils/FileSystem.php
DELETED
@@ -1,57 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// TODO PHP7.x; declare(strict_types=1);
|
4 |
-
|
5 |
-
namespace WPStaging\Framework\Utils;
|
6 |
-
|
7 |
-
use FilesystemIterator;
|
8 |
-
|
9 |
-
/**
|
10 |
-
* Class FileSystem
|
11 |
-
*
|
12 |
-
* @todo Remove this class in favor of:
|
13 |
-
* @see \WPStaging\Framework\Filesystem\Filesystem
|
14 |
-
*
|
15 |
-
* @package WPStaging\Framework\Utils
|
16 |
-
*/
|
17 |
-
class FileSystem
|
18 |
-
{
|
19 |
-
/*
|
20 |
-
* Makes sure all paths contain linux directory separator forward slash (/). Windows supports backslash and slash where linux only understands forward slash
|
21 |
-
* Windows understands both / and \
|
22 |
-
*
|
23 |
-
*/
|
24 |
-
public function replaceWindowsDirSeparator($path)
|
25 |
-
{
|
26 |
-
if (DIRECTORY_SEPARATOR === '/') {
|
27 |
-
return $path;
|
28 |
-
}
|
29 |
-
|
30 |
-
return str_replace('/', DIRECTORY_SEPARATOR, $path);
|
31 |
-
}
|
32 |
-
|
33 |
-
/*
|
34 |
-
* Makes sure all paths contain linux directory separator forward slash (/). Windows supports backslash and slash where linux only understands forward slash
|
35 |
-
* Windows understands both / and \
|
36 |
-
*
|
37 |
-
* This does the same as replaceWindowsDirSeparator() but is probably not as performant as variant 1.
|
38 |
-
* Not tested it, yet. Keep it here for todo testing purposes
|
39 |
-
*/
|
40 |
-
public function replaceWindowsDirSeparator2($path)
|
41 |
-
{
|
42 |
-
return preg_replace('/[\\\\]+/', '/', $path);
|
43 |
-
}
|
44 |
-
|
45 |
-
/**
|
46 |
-
* @param string $dir
|
47 |
-
* @return bool True if directory is empty. False if empty or does not exist
|
48 |
-
*/
|
49 |
-
public function isEmptyDir($dir)
|
50 |
-
{
|
51 |
-
if (!is_dir($dir)) {
|
52 |
-
return false;
|
53 |
-
}
|
54 |
-
|
55 |
-
return (new FilesystemIterator($dir))->valid() === false;
|
56 |
-
}
|
57 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Framework/Utils/WpDefaultDirectories.php
CHANGED
@@ -14,6 +14,17 @@ class WpDefaultDirectories
|
|
14 |
const MULTI_OLD_UPLOADS_DIR = 'blogs.dir';
|
15 |
const MULTI_UPLOADS_DIR = 'sites';
|
16 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
/**
|
18 |
* Get path to the uploads folder, relatively to the wp root folder.
|
19 |
* Allows custom uploads folders.
|
@@ -29,7 +40,7 @@ class WpDefaultDirectories
|
|
29 |
*/
|
30 |
public function getRelativeUploadPath()
|
31 |
{
|
32 |
-
$relPath = str_replace(
|
33 |
|
34 |
return trim($relPath, '/');
|
35 |
}
|
@@ -50,8 +61,39 @@ class WpDefaultDirectories
|
|
50 |
// Adding slashes at before and end of absolute path to WordPress uploads directory
|
51 |
$uploadsAbsPath = trailingslashit($uploads['basedir']);
|
52 |
|
53 |
-
return
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
}
|
55 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
57 |
}
|
14 |
const MULTI_OLD_UPLOADS_DIR = 'blogs.dir';
|
15 |
const MULTI_UPLOADS_DIR = 'sites';
|
16 |
|
17 |
+
/**
|
18 |
+
* @var Strings
|
19 |
+
*/
|
20 |
+
private $strUtils;
|
21 |
+
|
22 |
+
public function __construct()
|
23 |
+
{
|
24 |
+
// @todo inject using DI
|
25 |
+
$this->strUtils = new Strings();
|
26 |
+
}
|
27 |
+
|
28 |
/**
|
29 |
* Get path to the uploads folder, relatively to the wp root folder.
|
30 |
* Allows custom uploads folders.
|
40 |
*/
|
41 |
public function getRelativeUploadPath()
|
42 |
{
|
43 |
+
$relPath = str_replace($this->strUtils->sanitizeDirectorySeparator(ABSPATH), null, $this->getUploadPath());
|
44 |
|
45 |
return trim($relPath, '/');
|
46 |
}
|
61 |
// Adding slashes at before and end of absolute path to WordPress uploads directory
|
62 |
$uploadsAbsPath = trailingslashit($uploads['basedir']);
|
63 |
|
64 |
+
return $this->strUtils->sanitizeDirectorySeparator($uploadsAbsPath);
|
65 |
+
}
|
66 |
+
|
67 |
+
/**
|
68 |
+
* Get the relative path of wp content directory
|
69 |
+
* @return string
|
70 |
+
*/
|
71 |
+
public function getRelativeWpContentPath()
|
72 |
+
{
|
73 |
+
$relPath = str_replace($this->strUtils->sanitizeDirectorySeparator(ABSPATH), null, WP_CONTENT_DIR);
|
74 |
+
|
75 |
+
return trim($relPath, '/');
|
76 |
}
|
77 |
|
78 |
+
/**
|
79 |
+
* Get the relative path of plugins directory
|
80 |
+
* @return string
|
81 |
+
*/
|
82 |
+
public function getRelativePluginPath()
|
83 |
+
{
|
84 |
+
$relPath = str_replace($this->strUtils->sanitizeDirectorySeparator(ABSPATH), null, WP_PLUGIN_DIR);
|
85 |
|
86 |
+
return trim($relPath, '/');
|
87 |
+
}
|
88 |
+
|
89 |
+
/**
|
90 |
+
* Get the relative path of themes directory
|
91 |
+
* @return string
|
92 |
+
*/
|
93 |
+
public function getRelativeThemePath()
|
94 |
+
{
|
95 |
+
$relWpContentPath = $this->getRelativeWpContentPath();
|
96 |
+
$relPath = $relWpContentPath . "/" . "themes";
|
97 |
+
return $this->strUtils->sanitizeDirectorySeparator($relPath);
|
98 |
+
}
|
99 |
}
|
Repository/SettingsRepository.php
DELETED
@@ -1,43 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// TODO PHP7.x; declare(strict_types=1);
|
4 |
-
// TODO PHP7.x type hints & return types
|
5 |
-
// TODO PHP7.1; constant visibility
|
6 |
-
|
7 |
-
namespace WPStaging\Repository;
|
8 |
-
|
9 |
-
use WPStaging\Entity\Settings;
|
10 |
-
|
11 |
-
class SettingsRepository
|
12 |
-
{
|
13 |
-
const OPTION_NAME = 'wpstg_settings';
|
14 |
-
|
15 |
-
/**
|
16 |
-
* @return Settings
|
17 |
-
*/
|
18 |
-
public function find()
|
19 |
-
{
|
20 |
-
$records = get_option(self::OPTION_NAME, []);
|
21 |
-
if (!$records || !is_array($records)) {
|
22 |
-
return new Settings;
|
23 |
-
}
|
24 |
-
|
25 |
-
/** @var Settings|null $settings */
|
26 |
-
$settings = (new Settings)->hydrate($records);
|
27 |
-
return $settings;
|
28 |
-
}
|
29 |
-
|
30 |
-
/**
|
31 |
-
* @param Settings $settings
|
32 |
-
* @return bool
|
33 |
-
*/
|
34 |
-
public function save(Settings $settings)
|
35 |
-
{
|
36 |
-
$data = $settings->toArray();
|
37 |
-
$existing = $this->find();
|
38 |
-
if ($existing && $data === $existing->toArray()) {
|
39 |
-
return true;
|
40 |
-
}
|
41 |
-
return update_option(self::OPTION_NAME, $data, false);
|
42 |
-
}
|
43 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_init.php
DELETED
@@ -1,57 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
use WPStaging\Core\WPStaging;
|
4 |
-
|
5 |
-
/**
|
6 |
-
* Do not show update notifications for WP STAGING Pro on the staging site
|
7 |
-
* @param object
|
8 |
-
* @return object
|
9 |
-
* @todo Move this to separate class, e.g. wpstaging/Core/Wpcore/PluginUpdateNotify()
|
10 |
-
*/
|
11 |
-
if (!function_exists('wpstg_filter_plugin_updates')) {
|
12 |
-
function wpstg_filter_plugin_updates($value)
|
13 |
-
{
|
14 |
-
if (wpstg_is_stagingsite()) {
|
15 |
-
if (isset($value->response['wp-staging-pro/wp-staging-pro.php'])) {
|
16 |
-
unset($value->response['wp-staging-pro/wp-staging-pro.php']);
|
17 |
-
}
|
18 |
-
}
|
19 |
-
return $value;
|
20 |
-
}
|
21 |
-
}
|
22 |
-
add_filter('site_transient_update_plugins', 'wpstg_filter_plugin_updates');
|
23 |
-
|
24 |
-
// Todo: Rename class to WPStaging\Core\WPStaging to comply with PSR-4
|
25 |
-
if (!class_exists('WPStaging\Core\WPStaging')) {
|
26 |
-
require_once plugin_dir_path(__FILE__) . "Core/WPStaging.php";
|
27 |
-
}
|
28 |
-
|
29 |
-
// Todo: Rename class to WPStaging\Core\Utils\WPSTG_Requirements_Check to comply with PSR-4
|
30 |
-
if (!class_exists('Wpstg_Requirements_Check')) {
|
31 |
-
include(__DIR__ . '/Core/Utils/requirements-check.php');
|
32 |
-
}
|
33 |
-
|
34 |
-
$pluginRequirements = new Wpstg_Requirements_Check([
|
35 |
-
'title' => 'WP STAGING',
|
36 |
-
'php' => '5.5',
|
37 |
-
'wp' => '4.0',
|
38 |
-
'file' => __FILE__,
|
39 |
-
]);
|
40 |
-
|
41 |
-
if ($pluginRequirements->passes()) {
|
42 |
-
|
43 |
-
$wpStaging = WPStaging::getInstance(new \WPStaging\Framework\DI\Container);
|
44 |
-
|
45 |
-
/*
|
46 |
-
* Set the WPSTG_COMPATIBLE constant in the container,
|
47 |
-
* so that we can change it for testing purposes.
|
48 |
-
*/
|
49 |
-
$wpStaging->set('WPSTG_COMPATIBLE', WPSTG_COMPATIBLE);
|
50 |
-
|
51 |
-
// Wordpress DB Object
|
52 |
-
global $wpdb;
|
53 |
-
|
54 |
-
if ($wpdb instanceof \wpdb) {
|
55 |
-
$wpStaging->set("wpdb", $wpdb);
|
56 |
-
}
|
57 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bootstrap/autoloader.php → autoloader.php
RENAMED
@@ -1,18 +1,14 @@
|
|
1 |
<?php
|
2 |
-
/**
|
3 |
-
* @var $this \WPStaging\Bootstrap\V1\WpstgBootstrap The context where this file is included.
|
4 |
-
*/
|
5 |
-
|
6 |
// Register the autoloader for the plugin source code, and for the prefixed vendors.
|
7 |
$class_map = array_merge(
|
8 |
-
|
9 |
-
|
10 |
);
|
11 |
|
12 |
spl_autoload_register(
|
13 |
function ($class) use ($class_map) {
|
14 |
if (isset($class_map[$class])) {
|
15 |
-
|
16 |
|
17 |
return true;
|
18 |
}
|
1 |
<?php
|
|
|
|
|
|
|
|
|
2 |
// Register the autoloader for the plugin source code, and for the prefixed vendors.
|
3 |
$class_map = array_merge(
|
4 |
+
include_once __DIR__ . '/vendor_wpstg/autoload/src.php',
|
5 |
+
include_once __DIR__ . '/vendor_wpstg/autoload/vendor.php'
|
6 |
);
|
7 |
|
8 |
spl_autoload_register(
|
9 |
function ($class) use ($class_map) {
|
10 |
if (isset($class_map[$class])) {
|
11 |
+
include_once $class_map[$class];
|
12 |
|
13 |
return true;
|
14 |
}
|
bootstrap.php
ADDED
@@ -0,0 +1,73 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @var string $pluginFilePath The absolute path to the main file of this plugin.
|
4 |
+
*/
|
5 |
+
|
6 |
+
use WPStaging\Core\WPStaging;
|
7 |
+
|
8 |
+
if (file_exists(__DIR__ . '/autoloader_dev.php')) {
|
9 |
+
include_once __DIR__ . '/autoloader_dev.php';
|
10 |
+
} else {
|
11 |
+
include_once __DIR__ . '/autoloader.php';
|
12 |
+
}
|
13 |
+
|
14 |
+
// Early bail: Unexpected behavior from the autoloader
|
15 |
+
if (!class_exists('\WPStaging\Core\WPStaging')) {
|
16 |
+
return;
|
17 |
+
}
|
18 |
+
|
19 |
+
// Register common constants.
|
20 |
+
if (!defined('WPSTG_PLUGIN_FILE')) {
|
21 |
+
define('WPSTG_PLUGIN_FILE', $pluginFilePath);
|
22 |
+
}
|
23 |
+
|
24 |
+
// Absolute path to plugin dir /var/www/.../plugins/wp-staging(-pro)
|
25 |
+
if (!defined('WPSTG_PLUGIN_DIR')) {
|
26 |
+
define('WPSTG_PLUGIN_DIR', plugin_dir_path($pluginFilePath));
|
27 |
+
}
|
28 |
+
|
29 |
+
// URL of the base folder
|
30 |
+
if (!defined('WPSTG_PLUGIN_URL')) {
|
31 |
+
define('WPSTG_PLUGIN_URL', plugin_dir_url($pluginFilePath));
|
32 |
+
}
|
33 |
+
|
34 |
+
// Expected version number of the must-use plugin 'optimizer'. Used for automatic updates of the mu-plugin
|
35 |
+
if (!defined('WPSTG_OPTIMIZER_MUVERSION')) {
|
36 |
+
define('WPSTG_OPTIMIZER_MUVERSION', 1.4);
|
37 |
+
}
|
38 |
+
|
39 |
+
// /var/www/single/wp-content/plugins/wp-staging-pro/wp-staging-pro.php => wp-staging-pro
|
40 |
+
if (!defined('WPSTG_PLUGIN_SLUG')) {
|
41 |
+
define('WPSTG_PLUGIN_SLUG', basename(dirname($pluginFilePath)));
|
42 |
+
}
|
43 |
+
|
44 |
+
// An identifier that is the same both for WPSTAGING Free and WPSTAGING Pro
|
45 |
+
if (!defined('WPSTG_PLUGIN_DOMAIN')) {
|
46 |
+
define('WPSTG_PLUGIN_DOMAIN', 'wp-staging');
|
47 |
+
}
|
48 |
+
|
49 |
+
/**
|
50 |
+
* Register specific Pro and Free constants. We register them here instead of on the
|
51 |
+
* entrypoint because we want to make sure we are defining constants for the plugins
|
52 |
+
* actually being bootstrapped.
|
53 |
+
*/
|
54 |
+
if (file_exists(__DIR__ . '/constantsPro.php')) {
|
55 |
+
include_once __DIR__ . '/constantsPro.php';
|
56 |
+
} elseif (file_exists(__DIR__ . '/constantsFree.php')) {
|
57 |
+
include_once __DIR__ . '/constantsFree.php';
|
58 |
+
}
|
59 |
+
|
60 |
+
$wpStaging = WPStaging::getInstance();
|
61 |
+
|
62 |
+
/*
|
63 |
+
* Set the WPSTG_COMPATIBLE constant in the container,
|
64 |
+
* so that we can change it for testing purposes.
|
65 |
+
*/
|
66 |
+
$wpStaging->set('WPSTG_COMPATIBLE', WPSTG_COMPATIBLE);
|
67 |
+
|
68 |
+
// Wordpress DB Object
|
69 |
+
global $wpdb;
|
70 |
+
|
71 |
+
if ($wpdb instanceof wpdb) {
|
72 |
+
$wpStaging->set("wpdb", $wpdb);
|
73 |
+
}
|
constants.php
DELETED
@@ -1,25 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
// Absolute path to plugin dir /var/www/.../plugins/wp-staging(-pro)
|
4 |
-
if (!defined('WPSTG_PLUGIN_DIR')) {
|
5 |
-
define('WPSTG_PLUGIN_DIR', plugin_dir_path(WPSTG_PLUGIN_FILE));
|
6 |
-
}
|
7 |
-
|
8 |
-
// URL of the base folder
|
9 |
-
if (!defined('WPSTG_PLUGIN_URL')) {
|
10 |
-
define('WPSTG_PLUGIN_URL', plugin_dir_url(WPSTG_PLUGIN_FILE));
|
11 |
-
}
|
12 |
-
|
13 |
-
// Expected version number of the must-use plugin 'optimizer'. Used for automatic updates of the mu-plugin
|
14 |
-
if (!defined('WPSTG_OPTIMIZER_MUVERSION')) {
|
15 |
-
define('WPSTG_OPTIMIZER_MUVERSION', 1.4);
|
16 |
-
}
|
17 |
-
|
18 |
-
if (!defined('WPSTG_PLUGIN_SLUG')) {
|
19 |
-
define('WPSTG_PLUGIN_SLUG', dirname(WPSTG_PLUGIN_FILE));
|
20 |
-
}
|
21 |
-
|
22 |
-
if (!defined('WPSTG_PLUGIN_DOMAIN')) {
|
23 |
-
// An identifier that is the same both for WPSTAGING Free and WPSTAGING Pro
|
24 |
-
define('WPSTG_PLUGIN_DOMAIN', 'wp-staging');
|
25 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constantsFree.php
ADDED
@@ -0,0 +1,10 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// WP STAGING version number
|
3 |
+
if (!defined('WPSTG_VERSION')) {
|
4 |
+
define('WPSTG_VERSION', '2.8.1');
|
5 |
+
}
|
6 |
+
|
7 |
+
// Compatible up to WordPress Version
|
8 |
+
if (!defined('WPSTG_COMPATIBLE')) {
|
9 |
+
define('WPSTG_COMPATIBLE', '5.6');
|
10 |
+
}
|
freeBootstrap.php
ADDED
@@ -0,0 +1,59 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* The purpose of the pre-bootstrap process is to make sure the environment is able to run
|
4 |
+
* the plugin without any errors, such as making sure there are no other WPSTAGING instances
|
5 |
+
* active at the same time.
|
6 |
+
*
|
7 |
+
* It works at a low level, without the autoloader, using anonymous callbacks and local variables
|
8 |
+
* to make sure we always use and execute the expected code.
|
9 |
+
*
|
10 |
+
* Since it uses closures, you can't dequeue those actions, but this is expected.
|
11 |
+
*
|
12 |
+
* @var string $pluginFilePath The absolute path to the main file of this plugin.
|
13 |
+
*/
|
14 |
+
|
15 |
+
add_action('plugins_loaded', function () use ($pluginFilePath) {
|
16 |
+
try {
|
17 |
+
require __DIR__ . '/runtimeRequirements.php';
|
18 |
+
require_once __DIR__ . '/bootstrap.php';
|
19 |
+
} catch (Exception $e) {
|
20 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
21 |
+
error_log('WPSTAGING: ' . $e->getMessage());
|
22 |
+
}
|
23 |
+
}
|
24 |
+
}, 11, 0); // The priority of this hook must be larger than 10 for the runtime requirement check to detect older versions of WPSTAGING.
|
25 |
+
|
26 |
+
register_activation_hook($pluginFilePath, function () use ($pluginFilePath) {
|
27 |
+
// Prevent WPSTAGING Free activation when Pro is active
|
28 |
+
if (is_multisite()) {
|
29 |
+
foreach (wp_get_active_network_plugins() as $networkActivePlugin) {
|
30 |
+
if (strpos($networkActivePlugin, 'wp-staging-pro.php') !== false) {
|
31 |
+
set_site_transient('wpstgActivatingFreeWhileProIsActive', true);
|
32 |
+
wp_safe_redirect(self_admin_url('plugins.php'));
|
33 |
+
exit;
|
34 |
+
}
|
35 |
+
}
|
36 |
+
}
|
37 |
+
foreach (wp_get_active_and_valid_plugins() as $sitewidePlugin) {
|
38 |
+
if (strpos($sitewidePlugin, 'wp-staging-pro.php') !== false) {
|
39 |
+
// Set a transient that Pro picks up to render a notice to the user.
|
40 |
+
set_site_transient('wpstgActivatingFreeWhileProIsActive', true);
|
41 |
+
|
42 |
+
// Redirects to prevent "Plugin could not be activated because it triggered a fatal error notice".
|
43 |
+
wp_safe_redirect(self_admin_url('plugins.php'));
|
44 |
+
|
45 |
+
// Prevents the activation of this plugin.
|
46 |
+
exit;
|
47 |
+
}
|
48 |
+
}
|
49 |
+
|
50 |
+
try {
|
51 |
+
require __DIR__ . '/runtimeRequirements.php';
|
52 |
+
require_once __DIR__ . '/bootstrap.php';
|
53 |
+
require_once __DIR__ . '/install.php';
|
54 |
+
} catch (Exception $e) {
|
55 |
+
if (defined('WPSTG_DEBUG') && WPSTG_DEBUG) {
|
56 |
+
error_log('WPSTAGING: ' . $e->getMessage());
|
57 |
+
}
|
58 |
+
}
|
59 |
+
});
|
install.php
CHANGED
@@ -1,82 +1,36 @@
|
|
1 |
<?php
|
2 |
-
|
3 |
-
|
|
|
|
|
|
|
|
|
4 |
|
5 |
use WPStaging\Backend\Optimizer\Optimizer;
|
6 |
-
use WPStaging\
|
7 |
-
use WPStaging\Core\Utils\IISWebConfig;
|
8 |
use WPStaging\Core\Utils\Htaccess;
|
9 |
-
use WPStaging\Core\Utils\Filesystem;
|
10 |
|
11 |
/**
|
12 |
-
*
|
13 |
-
*
|
14 |
*/
|
15 |
-
|
16 |
-
{
|
17 |
-
private $bootstrap;
|
18 |
-
|
19 |
-
public function __construct(WpstgBootstrap $bootstrap)
|
20 |
-
{
|
21 |
-
$this->bootstrap = $bootstrap;
|
22 |
-
}
|
23 |
-
|
24 |
-
public function activation()
|
25 |
-
{
|
26 |
-
$this->bootstrap->checkRequirements();
|
27 |
-
$this->bootstrap->bootstrap();
|
28 |
-
|
29 |
-
if ($this->bootstrap->passedRequirements()) {
|
30 |
-
$this->initCron();
|
31 |
-
$this->installOptimizer();
|
32 |
-
$this->createHtaccess();
|
33 |
-
$this->createIndex();
|
34 |
-
$this->createWebConfig();
|
35 |
-
}
|
36 |
-
}
|
37 |
-
|
38 |
-
private function initCron()
|
39 |
-
{
|
40 |
-
// Register cron job.
|
41 |
-
$cron = new \WPStaging\Core\Cron\Cron;
|
42 |
-
$cron->schedule_event();
|
43 |
-
}
|
44 |
-
|
45 |
-
private function installOptimizer()
|
46 |
-
{
|
47 |
|
48 |
-
|
49 |
-
|
50 |
-
|
51 |
-
|
52 |
-
if (!defined('WPSTGPRO_VERSION')) {
|
53 |
-
// Add the transient to redirect for class Welcome (not for multisites) and not for Pro version
|
54 |
-
set_transient('wpstg_activation_redirect', true, 3600);
|
55 |
-
}
|
56 |
-
}
|
57 |
-
|
58 |
-
private function createHtaccess()
|
59 |
-
{
|
60 |
-
$htaccess = new Htaccess();
|
61 |
-
$htaccess->create(trailingslashit(\WPStaging\Core\WPStaging::getContentDir()) . '.htaccess');
|
62 |
-
$htaccess->create(trailingslashit(\WPStaging\Core\WPStaging::getContentDir()) . 'logs/.htaccess');
|
63 |
-
|
64 |
-
if (extension_loaded('litespeed')) {
|
65 |
-
$htaccess->createLitespeed(ABSPATH . '.htaccess');
|
66 |
-
}
|
67 |
-
}
|
68 |
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
|
74 |
-
|
75 |
|
76 |
-
|
77 |
-
|
78 |
-
|
79 |
-
|
80 |
-
|
81 |
-
|
82 |
}
|
1 |
<?php
|
2 |
+
/**
|
3 |
+
* This file is hooked as the \register_activation_hook of the plugin,
|
4 |
+
* therefore it runs as a standalone script that needs to be bootstrapped.
|
5 |
+
*
|
6 |
+
* @var string $pluginFilePath The absolute path to the main file of this plugin.
|
7 |
+
*/
|
8 |
|
9 |
use WPStaging\Backend\Optimizer\Optimizer;
|
10 |
+
use WPStaging\Core\Cron\Cron;
|
|
|
11 |
use WPStaging\Core\Utils\Htaccess;
|
|
|
12 |
|
13 |
/**
|
14 |
+
* Register Cron Events
|
|
|
15 |
*/
|
16 |
+
$cron = (new Cron)->scheduleEvent();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
17 |
|
18 |
+
/**
|
19 |
+
* Install the Optimizer
|
20 |
+
*/
|
21 |
+
$optimizer = (new Optimizer)->installOptimizer();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
+
/**
|
24 |
+
* Add the transient to redirect for class Welcome (Not for multisites) and not for Pro version
|
25 |
+
*/
|
26 |
+
if (!defined('WPSTGPRO_VERSION')) {
|
27 |
+
set_transient('wpstg_activation_redirect', true, 3600);
|
28 |
+
}
|
29 |
|
30 |
+
/**
|
31 |
+
* Create Htaccess
|
32 |
+
*/
|
33 |
+
$htaccess = new Htaccess();
|
34 |
+
if (extension_loaded('litespeed')) {
|
35 |
+
$htaccess->createLitespeed(ABSPATH . '.htaccess');
|
36 |
}
|
readme.txt
CHANGED
@@ -1,4 +1,4 @@
|
|
1 |
-
=== WP STAGING -
|
2 |
|
3 |
Author URL: https://wordpress.org/plugins/wp-staging
|
4 |
Plugin URL: https://wordpress.org/plugins/wp-staging
|
@@ -6,13 +6,13 @@ 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:
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.6
|
12 |
-
Stable tag: 2.8.
|
13 |
Requires PHP: 5.5
|
14 |
|
15 |
-
A duplicator plugin - clone
|
16 |
|
17 |
== Description ==
|
18 |
|
@@ -34,7 +34,7 @@ WP STAGING can help you to prevent your website from being broken or unavailable
|
|
34 |
|
35 |
= Main Features =
|
36 |
|
37 |
-
*
|
38 |
* Easy to use! Create a clone of your site by clicking one button "CREATE NEW STAGING SITE".
|
39 |
* No Software as a Service - No account needed! All data belong to you only and stay on your server.
|
40 |
* No server timeouts on huge websites or/and small hosting servers
|
@@ -132,6 +132,17 @@ After installation, go to the settings page 'Staging' and do your adjustments th
|
|
132 |
|
133 |
== Frequently Asked Questions ==
|
134 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
135 |
* I can not log in to the staging / backup site
|
136 |
If you are using a security plugin like All In One WP Security & Firewall you need to install the latest version of WP STAGING to access your cloned backup site.
|
137 |
Go to WP STAGING > Settings and add the slug to the custom login page which you set up in All In One WP Security & Firewall plugin.
|
@@ -155,6 +166,17 @@ https://wp-staging.com
|
|
155 |
|
156 |
== Changelog ==
|
157 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
158 |
= 2.8.0 =
|
159 |
* Fix: Latest supported WP version is not reflected on wordpress.org plugin repo
|
160 |
* Enh: Show confirmation popup if user tries to send another support request within an hour
|
@@ -292,25 +314,16 @@ SKIP VERSION
|
|
292 |
* Fix: PDO instances can not be serialized or unserialized
|
293 |
* Fix: Can not update staging site db table if there are constraints in it
|
294 |
|
295 |
-
= 2.6.0 =
|
296 |
-
* New: Compatible up to WordPress 5.2.2
|
297 |
-
* New: Performance improvement for directory iterator using less server ressources
|
298 |
-
* New: Add filter wpstg_folder_permission to set a custom folder permission like 0755, allows to overwrite FS_CHMOD_DIR if it has been defined.
|
299 |
-
* Fix: Error conditions in class Data does not compare type strict (== vs. ==) resulting in interruption of clone process
|
300 |
-
* Fix: Excluded folders under wp-content level are not take into account on microsoft IIS servers
|
301 |
-
|
302 |
Full changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-staging.com/wp-staging-changelog)
|
303 |
|
304 |
== Upgrade Notice ==
|
305 |
-
*
|
306 |
-
*
|
307 |
-
*
|
308 |
-
*
|
309 |
-
*
|
310 |
-
*
|
311 |
-
*
|
312 |
-
*
|
313 |
-
*
|
314 |
-
* Dev: Prefix composer vendor libraries with PHP-Scoper
|
315 |
-
* Dev: Add more unit and webdriver tests to improve QA
|
316 |
|
1 |
+
=== WP STAGING - Backup Duplicator & Migration ===
|
2 |
|
3 |
Author URL: https://wordpress.org/plugins/wp-staging
|
4 |
Plugin URL: https://wordpress.org/plugins/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: backup, database backup, staging, duplication, clone
|
10 |
Requires at least: 3.6+
|
11 |
Tested up to: 5.6
|
12 |
+
Stable tag: 2.8.1
|
13 |
Requires PHP: 5.5
|
14 |
|
15 |
+
A backup & duplicator plugin - clone, move, duplicate & migrate websites to staging, backup and development sites for authorized users only.
|
16 |
|
17 |
== Description ==
|
18 |
|
34 |
|
35 |
= Main Features =
|
36 |
|
37 |
+
* WPSTAGING clones the whole production site into a subfolder like example.com/staging-site.
|
38 |
* Easy to use! Create a clone of your site by clicking one button "CREATE NEW STAGING SITE".
|
39 |
* No Software as a Service - No account needed! All data belong to you only and stay on your server.
|
40 |
* No server timeouts on huge websites or/and small hosting servers
|
132 |
|
133 |
== Frequently Asked Questions ==
|
134 |
|
135 |
+
* What is the Difference between WP STAGING and a Regular Backup Plugin?
|
136 |
+
You may have heard about other popular backup plugins like BackWPUp, BackupWordPress, Simple Backup, WordPress Backup to Dropbox or similar WordPress backup plugins and now wonder about the difference between WP STAGING and those backup tools.
|
137 |
+
Other backup plugins usually create a backup of your WordPress filesystem and a database backup which you can use to restore your website in case it became corrupted or you want to go back in time to a previous state.
|
138 |
+
The backup files are compressed and can not be executed directly. WP STAGING on the other hand creates a full backup of the whole file system and the database in a working state that you can open like your original production website.
|
139 |
+
|
140 |
+
Even though WP STAGING comes with some backup capabilities it's main purpose is to create a clone of your website which you can work on. It harmonies very well with all the mentioned backup plugins above and we recommend that you use it in conjunction with these backup plugins.
|
141 |
+
|
142 |
+
Note, that some free backup plugins are not able to support custom tables. (For instance the free version of Updraft plus backup plugin). In that case, your backup plugin is not able to create a backup of your staging site when it is executed on the production site.
|
143 |
+
The reason is that the tables created by WP STAGING are kind of custom tables beginning with another table prefix.
|
144 |
+
To bypass this limitation and to be able to create a backup of your staging site, you can setup your backup plugin on the staging site and create the backup from that location. This works well with every available WordPress backup plugin.
|
145 |
+
|
146 |
* I can not log in to the staging / backup site
|
147 |
If you are using a security plugin like All In One WP Security & Firewall you need to install the latest version of WP STAGING to access your cloned backup site.
|
148 |
Go to WP STAGING > Settings and add the slug to the custom login page which you set up in All In One WP Security & Firewall plugin.
|
166 |
|
167 |
== Changelog ==
|
168 |
|
169 |
+
= 2.8.1 =
|
170 |
+
* Feat: Show creator user name of staging site
|
171 |
+
* Enh: Show notice if sending mails are disabled
|
172 |
+
* Enh: Show message and stop execution if php version is lower than 5.5
|
173 |
+
* Enh: Abort cloning process if table already exists in external database
|
174 |
+
* Fix: Can not update database credentials in staging sites wp-config.php under rare circumstances
|
175 |
+
* Fix: During the update process if options table was not selected it didn't get skipped
|
176 |
+
* Fix: Error if WP is lower than 4.6
|
177 |
+
* Fix: Can not delete entire staging site on error
|
178 |
+
* Fix: Activating pro version does not properly disable free version
|
179 |
+
|
180 |
= 2.8.0 =
|
181 |
* Fix: Latest supported WP version is not reflected on wordpress.org plugin repo
|
182 |
* Enh: Show confirmation popup if user tries to send another support request within an hour
|
314 |
* Fix: PDO instances can not be serialized or unserialized
|
315 |
* Fix: Can not update staging site db table if there are constraints in it
|
316 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
317 |
Full changelog: [https://wp-staging.com/wp-staging-changelog](https://wp-staging.com/wp-staging-changelog)
|
318 |
|
319 |
== Upgrade Notice ==
|
320 |
+
* Feat: Show creator user name of staging site
|
321 |
+
* Enh: Show notice if sending mails are disabled
|
322 |
+
* Enh: Show message and stop execution if php version is lower than 5.5
|
323 |
+
* Enh: Abort cloning process if table already exists in external database
|
324 |
+
* Fix: Can not update database credentials in staging sites wp-config.php under rare circumstances
|
325 |
+
* Fix: During the update process if options table was not selected it didn't get skipped
|
326 |
+
* Fix: Error if WP is lower than 4.6
|
327 |
+
* Fix: Can not delete entire staging site on error
|
328 |
+
* Fix: Activating pro version does not properly disable free version
|
|
|
|
|
329 |
|
runtimeRequirements.php
ADDED
@@ -0,0 +1,79 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
/**
|
3 |
+
* @var string $pluginFilePath The absolute path to the main file of this plugin.
|
4 |
+
*/
|
5 |
+
|
6 |
+
/**
|
7 |
+
* Early bail: Activating another WPSTAGING Plugin.
|
8 |
+
* This is the only scenario where the plugin would be included after "plugins_loaded",
|
9 |
+
* therefore we need to detect earlier, from the context of the request, whether this is going to happen,
|
10 |
+
* to disable this plugin early and bail the bootstrap process to not conflict with the one being activated.
|
11 |
+
*
|
12 |
+
* Covers both clicking on the "Activate" button and selecting the "Activate" bulk-action.
|
13 |
+
*/
|
14 |
+
if (isset($_REQUEST['action'])) {
|
15 |
+
switch ($_REQUEST['action']):
|
16 |
+
case 'activate':
|
17 |
+
case 'error_scrape':
|
18 |
+
if (isset($_REQUEST['plugin'])) {
|
19 |
+
$plugin = (string)wp_unslash($_REQUEST['plugin']);
|
20 |
+
|
21 |
+
$isActivatingWpStaging = strpos($plugin, 'wp-staging.php') || strpos($plugin, 'wp-staging-pro.php');
|
22 |
+
$isActivatingAnotherWpStaging = plugin_basename($plugin) !== plugin_basename($pluginFilePath);
|
23 |
+
|
24 |
+
if ($isActivatingWpStaging && $isActivatingAnotherWpStaging && current_user_can('deactivate_plugin', plugin_basename($pluginFilePath))) {
|
25 |
+
throw new Exception("Activating another WPSTAGING Plugin. Plugin that bailed bootstrapping: $pluginFilePath");
|
26 |
+
}
|
27 |
+
}
|
28 |
+
break;
|
29 |
+
case 'activate-selected':
|
30 |
+
case 'activate-multi':
|
31 |
+
if (isset($_REQUEST['checked'])) {
|
32 |
+
$plugins = (array)wp_unslash($_REQUEST['checked']);
|
33 |
+
|
34 |
+
foreach ($plugins as $i => $plugin) {
|
35 |
+
$isActivatingWpStaging = strpos($plugin, 'wp-staging.php') || strpos($plugin, 'wp-staging-pro.php');
|
36 |
+
$isActivatingAnotherWpStaging = plugin_basename($plugin) !== plugin_basename($pluginFilePath);
|
37 |
+
|
38 |
+
if ($isActivatingWpStaging && $isActivatingAnotherWpStaging && current_user_can('deactivate_plugin', plugin_basename($pluginFilePath))) {
|
39 |
+
throw new Exception("Activating another WPSTAGING Plugin. Plugin that bailed bootstrapping: $pluginFilePath");
|
40 |
+
}
|
41 |
+
}
|
42 |
+
}
|
43 |
+
break;
|
44 |
+
endswitch;
|
45 |
+
}
|
46 |
+
|
47 |
+
/**
|
48 |
+
* Early bail: Another instance of WPSTAGING active.
|
49 |
+
*/
|
50 |
+
if (// WPSTAGING <= 2.7.5
|
51 |
+
class_exists('\WPStaging\WPStaging') ||
|
52 |
+
// WPSTAGING >= 2.7.6
|
53 |
+
class_exists('\WPStaging\Core\WPStaging')
|
54 |
+
) {
|
55 |
+
add_action(is_network_admin() ? 'network_admin_notices' : 'admin_notices', function () {
|
56 |
+
echo '<div class="notice-warning notice is-dismissible another-wpstaging-active">';
|
57 |
+
echo '<p style="font-weight: bold;">' . esc_html__('WP STAGING Already Active') . '</p>';
|
58 |
+
echo '<p>' . esc_html__('Another WP STAGING is already activated, please leave only one instance of the WP STAGING plugin active at the same time.', 'wp-staging') . '</p>';
|
59 |
+
echo '</div>';
|
60 |
+
});
|
61 |
+
|
62 |
+
throw new Exception("Another instance of WPSTAGING active. Plugin that bailed bootstrapping: $pluginFilePath");
|
63 |
+
}
|
64 |
+
|
65 |
+
/**
|
66 |
+
* Early bail: Unsupported WordPress version.
|
67 |
+
* We check on runtime instead of activation so we can display the notice.
|
68 |
+
*/
|
69 |
+
if (!version_compare($currentWordPressVersion = get_bloginfo('version'), $minimumWordPressVersion = '4.0', '>=')) {
|
70 |
+
add_action(is_network_admin() ? 'network_admin_notices' : 'admin_notices', function () use ($currentWordPressVersion, $minimumWordPressVersion) {
|
71 |
+
echo '<div class="notice-warning notice is-dismissible">';
|
72 |
+
echo '<p style="font-weight: bold;">' . esc_html__('WP STAGING') . '</p>';
|
73 |
+
echo '<p>' . esc_html__(sprintf('WPSTAGING requires at least WordPress %s to run. You have WordPress %s.', $minimumWordPressVersion, $currentWordPressVersion), 'wp-staging') . '</p>';
|
74 |
+
echo '</div>';
|
75 |
+
});
|
76 |
+
|
77 |
+
throw new Exception("Unsupported WordPress version. Plugin that bailed bootstrapping: $pluginFilePath");
|
78 |
+
}
|
79 |
+
|
template/.gitkeep
DELETED
File without changes
|
template/Component/Backend/Snapshot/listing.php
DELETED
@@ -1,102 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
use WPStaging\Framework\Collection\OptionCollection;
|
4 |
-
use WPStaging\Framework\TemplateEngine\TemplateEngine;
|
5 |
-
|
6 |
-
/** @var TemplateEngine $this */
|
7 |
-
/** @var OptionCollection $snapshots */
|
8 |
-
|
9 |
-
/**
|
10 |
-
* @todo See if we can unify this file with src/Pro/Snapshot/template/listing.php:12
|
11 |
-
*/
|
12 |
-
?>
|
13 |
-
<div class="wpstg-beta-notice">
|
14 |
-
<?php _e('WP Staging snapshots work well but is a new feature in beta status. Please use it on your own risk and have a backup of your site before using it. <br>If you experience an issue or you have a feature request <a href="#" id="wpstg-snapshots-report-issue-button">please give us some feedback.</a>','wp-staging')?>
|
15 |
-
</div>
|
16 |
-
<div id="wpstg-step-1">
|
17 |
-
<button id="wpstg-new-snapshot" class="wpstg-next-step-link wpstg-link-btn wpstg-blue-primary wpstg-button"
|
18 |
-
data-action="wpstg--snapshots--create">
|
19 |
-
<?php _e('Take New Snapshot', 'wp-staging') ?>
|
20 |
-
</button>
|
21 |
-
<div class="wpstg--tooltip"> <?php _e('What is this?', 'wp-staging'); ?>
|
22 |
-
|
23 |
-
<span class="wpstg--tooltiptext wpstg--tooltiptext-snapshots">
|
24 |
-
<?php _e('Snapshots are copies of the WordPress database tables at a particular point in time.
|
25 |
-
They can restore WordPress and roll back the database to another state.<br><br>
|
26 |
-
This is useful if you need to reset WordPress to the state before you\'ve pushed a staging site to live or if you want to revert other database changes
|
27 |
-
like activating a new theme or updating its settings.<br><br>
|
28 |
-
WP Staging Snapshots include all WordPress core tables and custom ones created by other plugins.
|
29 |
-
Restoring a snapshot will not affect other staging sites or snapshots. <br><br>
|
30 |
-
No files are included in snapshots! WP Staging snapshots are a quick way to roll back your site in time but for a full site backup it is recommended to use a dedicated backup plugin!
|
31 |
-
', 'wp-staging') ?>
|
32 |
-
<p></p>
|
33 |
-
<?php if (is_multisite()) {
|
34 |
-
echo '<strong>' . __('Multisite Users Only: ', 'wp-staging') . '</strong>';
|
35 |
-
echo '<p></p>';
|
36 |
-
echo __("- If you run the snapshot function on a multisite network site the snapshot will contain only the tables belonging to the particular network site. <p></p>It will not store all database tables of all network sites. So you are able to restore all network sites independently. <p></p>- If you create a snapshot on a multisite main site it will create a snapshot of <strong>all database tables</strong>.</p></p><strong>Take care:</strong> Restoring a multisite main snapshot will <strong>restore all children sites including the mainsite.</strong>", 'wp-staging');
|
37 |
-
} ?>
|
38 |
-
</span>
|
39 |
-
</div>
|
40 |
-
</div>
|
41 |
-
|
42 |
-
<div id="wpstg-existing-snapshots">
|
43 |
-
<h3>
|
44 |
-
<?php echo $snapshots ? __('Your Snapshots:', 'wp-staging') : '' ?>
|
45 |
-
</h3>
|
46 |
-
<?php foreach ($snapshots as $snapshot): ?>
|
47 |
-
<div id="<?php echo $snapshot->getId() ?>" class="wpstg-clone">
|
48 |
-
<span class="wpstg-clone-title"><?php echo $snapshot->getName() ?></span>
|
49 |
-
|
50 |
-
<a href="#" class="wpstg--snapshot--export wpstg-merge-clone wpstg-clone-action"
|
51 |
-
data-id="<?php echo $snapshot->getId() ?>"
|
52 |
-
title="<?php _e('Download backup as sql file to local system', 'wp-staging') ?>">
|
53 |
-
<?php _e('Export', 'wp-staging') ?>
|
54 |
-
</a>
|
55 |
-
|
56 |
-
<a href="#" class="wpstg--snapshot--restore wpstg-merge-clone wpstg-clone-action"
|
57 |
-
data-id="<?php echo $snapshot->getId() ?>"
|
58 |
-
title="<?php _e('Restore this snapshot to your live website!', 'wp-staging') ?>">
|
59 |
-
<?php _e('Restore', 'wp-staging') ?>
|
60 |
-
</a>
|
61 |
-
|
62 |
-
<a href="#" class="wpstg-remove-clone wpstg-clone-action wpstg-delete-snapshot"
|
63 |
-
data-id="<?php echo $snapshot->getId() ?>"
|
64 |
-
title="<?php _e('Delete this snapshot. This action can not be undone!', 'wp-staging') ?>">
|
65 |
-
<?php _e('Delete', 'wp-staging') ?>
|
66 |
-
</a>
|
67 |
-
|
68 |
-
<a href="#" class="wpstg--snapshot--edit wpstg-clone-action"
|
69 |
-
data-id="<?php echo $snapshot->getId() ?>"
|
70 |
-
data-name="<?php echo $snapshot->getName() ?>"
|
71 |
-
data-notes="<?php echo $snapshot->getNotes() ?>"
|
72 |
-
title="<?php _e('Edit backup name and / or notes', 'wp-staging') ?>">
|
73 |
-
<?php _e('Edit', 'wp-staging') ?>
|
74 |
-
</a>
|
75 |
-
|
76 |
-
<div class="wpstg-staging-info">
|
77 |
-
<ul>
|
78 |
-
<li>
|
79 |
-
<strong><?php _e('Table Prefix:', 'wp-staging') ?></strong>
|
80 |
-
<?php echo $snapshot->getId() ?>
|
81 |
-
</li>
|
82 |
-
<li>
|
83 |
-
<strong><?php _e('Created on:', 'wp-staging') ?></strong>
|
84 |
-
<?php echo $this->transformToWpFormat($snapshot->getCreatedAt()) ?>
|
85 |
-
<?php if ($snapshot->getUpdatedAt()): ?>
|
86 |
-
| <strong><?php _e('Updated on:', 'wp-staging') ?></strong>
|
87 |
-
<?php echo $this->transformToWpFormat($snapshot->getUpdatedAt()) ?>
|
88 |
-
<?php endif ?>
|
89 |
-
</li>
|
90 |
-
<?php if ($snapshot->getNotes()):?>
|
91 |
-
<li>
|
92 |
-
<strong><?php _e('Notes:', 'wp-staging') ?></strong><br/>
|
93 |
-
<?php echo nl2br($snapshot->getNotes()) ?>
|
94 |
-
</li>
|
95 |
-
<?php endif ?>
|
96 |
-
</ul>
|
97 |
-
</div>
|
98 |
-
</div>
|
99 |
-
<?php endforeach ?>
|
100 |
-
</div>
|
101 |
-
|
102 |
-
<div id="wpstg-delete-confirmation"></div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
uninstall.php
CHANGED
@@ -44,6 +44,7 @@ class uninstall
|
|
44 |
delete_option("wpstg_rmpermalinks_executed");
|
45 |
delete_option("wpstg_activation_redirect");
|
46 |
delete_option("wpstg_emails_disabled");
|
|
|
47 |
|
48 |
|
49 |
/* Do not delete these fields without actually deleting the staging site
|
44 |
delete_option("wpstg_rmpermalinks_executed");
|
45 |
delete_option("wpstg_activation_redirect");
|
46 |
delete_option("wpstg_emails_disabled");
|
47 |
+
delete_option("wpstg_disabled_cache_notice");
|
48 |
|
49 |
|
50 |
/* Do not delete these fields without actually deleting the staging site
|
vendor_wpstg/autoload/src.php
CHANGED
@@ -12,6 +12,7 @@ return array(
|
|
12 |
'WPStaging\\Backend\\Feedback\\Feedback' => $baseDir . '/Backend/Feedback/Feedback.php',
|
13 |
'WPStaging\\Backend\\Modules\\Jobs\\Cancel' => $baseDir . '/Backend/Modules/Jobs/Cancel.php',
|
14 |
'WPStaging\\Backend\\Modules\\Jobs\\CancelUpdate' => $baseDir . '/Backend/Modules/Jobs/CancelUpdate.php',
|
|
|
15 |
'WPStaging\\Backend\\Modules\\Jobs\\Cloning' => $baseDir . '/Backend/Modules/Jobs/Cloning.php',
|
16 |
'WPStaging\\Backend\\Modules\\Jobs\\CloningProcess' => $baseDir . '/Backend/Modules/Jobs/CloningProcess.php',
|
17 |
'WPStaging\\Backend\\Modules\\Jobs\\Data' => $baseDir . '/Backend/Modules/Jobs/Data.php',
|
@@ -41,13 +42,13 @@ return array(
|
|
41 |
'WPStaging\\Backend\\Modules\\SystemInfo' => $baseDir . '/Backend/Modules/SystemInfo.php',
|
42 |
'WPStaging\\Backend\\Modules\\Views\\Forms\\Settings' => $baseDir . '/Backend/Modules/Views/Forms/Settings.php',
|
43 |
'WPStaging\\Backend\\Modules\\Views\\Tabs\\Tabs' => $baseDir . '/Backend/Modules/Views/Tabs/Tabs.php',
|
|
|
44 |
'WPStaging\\Backend\\Notices\\DisabledCacheNotice' => $baseDir . '/Backend/Notices/DisabledCacheNotice.php',
|
45 |
'WPStaging\\Backend\\Notices\\Notices' => $baseDir . '/Backend/Notices/Notices.php',
|
46 |
'WPStaging\\Backend\\Optimizer\\Optimizer' => $baseDir . '/Backend/Optimizer/Optimizer.php',
|
47 |
'WPStaging\\Backend\\Pluginmeta\\Meta' => $baseDir . '/Backend/Pluginmeta/Meta.php',
|
48 |
'WPStaging\\Backend\\Pluginmeta\\Pluginmeta' => $baseDir . '/Backend/Pluginmeta/Pluginmeta.php',
|
49 |
'WPStaging\\Backend\\Upgrade\\Upgrade' => $baseDir . '/Backend/Upgrade/Upgrade.php',
|
50 |
-
'WPStaging\\Bootstrap\\V1\\WpstgBootstrap' => $baseDir . '/Bootstrap/V1/WpstgBootstrap.php',
|
51 |
'WPStaging\\Command\\Database\\Export\\ExportCommand' => $baseDir . '/Command/Database/Export/ExportCommand.php',
|
52 |
'WPStaging\\Command\\Database\\Export\\ExportDto' => $baseDir . '/Command/Database/Export/ExportDto.php',
|
53 |
'WPStaging\\Command\\Database\\Export\\ExportException' => $baseDir . '/Command/Database/Export/ExportException.php',
|
@@ -100,7 +101,6 @@ return array(
|
|
100 |
'WPStaging\\Core\\Utils\\Browser' => $baseDir . '/Core/Utils/Browser.php',
|
101 |
'WPStaging\\Core\\Utils\\Cache' => $baseDir . '/Core/Utils/Cache.php',
|
102 |
'WPStaging\\Core\\Utils\\Directories' => $baseDir . '/Core/Utils/Directories.php',
|
103 |
-
'WPStaging\\Core\\Utils\\Filesystem' => $baseDir . '/Core/Utils/Filesystem.php',
|
104 |
'WPStaging\\Core\\Utils\\Hash' => $baseDir . '/Core/Utils/Hash.php',
|
105 |
'WPStaging\\Core\\Utils\\Helper' => $baseDir . '/Core/Utils/Helper.php',
|
106 |
'WPStaging\\Core\\Utils\\Htaccess' => $baseDir . '/Core/Utils/Htaccess.php',
|
@@ -114,9 +114,6 @@ return array(
|
|
114 |
'WPStaging\\Core\\Utils\\Strings' => $baseDir . '/Core/Utils/Strings.php',
|
115 |
'WPStaging\\Core\\WPStaging' => $baseDir . '/Core/WPStaging.php',
|
116 |
'WPStaging\\Core\\thirdParty\\thirdPartyCompatibility' => $baseDir . '/Core/thirdParty/thirdPartyCompatibility.php',
|
117 |
-
'WPStaging\\Entity\\DatabaseSettings' => $baseDir . '/Entity/DatabaseSettings.php',
|
118 |
-
'WPStaging\\Entity\\FilesystemSettings' => $baseDir . '/Entity/FilesystemSettings.php',
|
119 |
-
'WPStaging\\Entity\\Settings' => $baseDir . '/Entity/Settings.php',
|
120 |
'WPStaging\\Framework\\Adapter\\Database' => $baseDir . '/Framework/Adapter/Database.php',
|
121 |
'WPStaging\\Framework\\Adapter\\Database\\AbstractDatabase' => $baseDir . '/Framework/Adapter/Database/AbstractDatabase.php',
|
122 |
'WPStaging\\Framework\\Adapter\\Database\\DatabaseException' => $baseDir . '/Framework/Adapter/Database/DatabaseException.php',
|
@@ -167,12 +164,13 @@ return array(
|
|
167 |
'WPStaging\\Framework\\Entity\\AbstractEntity' => $baseDir . '/Framework/Entity/AbstractEntity.php',
|
168 |
'WPStaging\\Framework\\Entity\\EntityException' => $baseDir . '/Framework/Entity/EntityException.php',
|
169 |
'WPStaging\\Framework\\Entity\\IdentifyableEntityInterface' => $baseDir . '/Framework/Entity/IdentifyableEntityInterface.php',
|
|
|
170 |
'WPStaging\\Framework\\Filesystem\\DirectoryScanner' => $baseDir . '/Framework/Filesystem/DirectoryScanner.php',
|
171 |
-
'WPStaging\\Framework\\Filesystem\\
|
172 |
'WPStaging\\Framework\\Filesystem\\DiskFullException' => $baseDir . '/Framework/Filesystem/DiskFullException.php',
|
173 |
'WPStaging\\Framework\\Filesystem\\File' => $baseDir . '/Framework/Filesystem/File.php',
|
174 |
'WPStaging\\Framework\\Filesystem\\FileScanner' => $baseDir . '/Framework/Filesystem/FileScanner.php',
|
175 |
-
'WPStaging\\Framework\\Filesystem\\
|
176 |
'WPStaging\\Framework\\Filesystem\\Filesystem' => $baseDir . '/Framework/Filesystem/Filesystem.php',
|
177 |
'WPStaging\\Framework\\Filesystem\\FilesystemExceptions' => $baseDir . '/Framework/Filesystem/FilesystemExceptions.php',
|
178 |
'WPStaging\\Framework\\Filesystem\\FilterableDirectoryIterator' => $baseDir . '/Framework/Filesystem/FilterableDirectoryIterator.php',
|
@@ -180,6 +178,7 @@ return array(
|
|
180 |
'WPStaging\\Framework\\Filesystem\\Filters\\ExtensionExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/ExtensionExcludeFilter.php',
|
181 |
'WPStaging\\Framework\\Filesystem\\Filters\\PathExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/PathExcludeFilter.php',
|
182 |
'WPStaging\\Framework\\Filesystem\\Filters\\RecursiveExtensionExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/RecursiveExtensionExcludeFilter.php',
|
|
|
183 |
'WPStaging\\Framework\\Filesystem\\WpUploadsFolderSymlinker' => $baseDir . '/Framework/Filesystem/WpUploadsFolderSymlinker.php',
|
184 |
'WPStaging\\Framework\\Interfaces\\ArrayableInterface' => $baseDir . '/Framework/Interfaces/ArrayableInterface.php',
|
185 |
'WPStaging\\Framework\\Interfaces\\HydrateableInterface' => $baseDir . '/Framework/Interfaces/HydrateableInterface.php',
|
@@ -196,6 +195,7 @@ return array(
|
|
196 |
'WPStaging\\Framework\\Queue\\Storage\\QueueStorageException' => $baseDir . '/Framework/Queue/Storage/QueueStorageException.php',
|
197 |
'WPStaging\\Framework\\Queue\\Storage\\StorageInterface' => $baseDir . '/Framework/Queue/Storage/StorageInterface.php',
|
198 |
'WPStaging\\Framework\\Security\\AccessToken' => $baseDir . '/Framework/Security/AccessToken.php',
|
|
|
199 |
'WPStaging\\Framework\\Security\\Capabilities' => $baseDir . '/Framework/Security/Capabilities.php',
|
200 |
'WPStaging\\Framework\\Security\\Nonce' => $baseDir . '/Framework/Security/Nonce.php',
|
201 |
'WPStaging\\Framework\\SiteInfo' => $baseDir . '/Framework/SiteInfo.php',
|
@@ -204,6 +204,7 @@ return array(
|
|
204 |
'WPStaging\\Framework\\TemplateEngine\\TemplateEngineException' => $baseDir . '/Framework/TemplateEngine/TemplateEngineException.php',
|
205 |
'WPStaging\\Framework\\TemplateEngine\\TemplateEngineInterface' => $baseDir . '/Framework/TemplateEngine/TemplateEngineInterface.php',
|
206 |
'WPStaging\\Framework\\Traits\\ArrayableTrait' => $baseDir . '/Framework/Traits/ArrayableTrait.php',
|
|
|
207 |
'WPStaging\\Framework\\Traits\\BooleanTransientTrait' => $baseDir . '/Framework/Traits/BooleanTransientTrait.php',
|
208 |
'WPStaging\\Framework\\Traits\\HydrateTrait' => $baseDir . '/Framework/Traits/HydrateTrait.php',
|
209 |
'WPStaging\\Framework\\Traits\\MaintenanceTrait' => $baseDir . '/Framework/Traits/MaintenanceTrait.php',
|
@@ -213,7 +214,6 @@ return array(
|
|
213 |
'WPStaging\\Framework\\Utils\\Cache\\AbstractCache' => $baseDir . '/Framework/Utils/Cache/AbstractCache.php',
|
214 |
'WPStaging\\Framework\\Utils\\Cache\\BufferedCache' => $baseDir . '/Framework/Utils/Cache/BufferedCache.php',
|
215 |
'WPStaging\\Framework\\Utils\\Cache\\Cache' => $baseDir . '/Framework/Utils/Cache/Cache.php',
|
216 |
-
'WPStaging\\Framework\\Utils\\FileSystem' => $baseDir . '/Framework/Utils/FileSystem.php',
|
217 |
'WPStaging\\Framework\\Utils\\Size' => $baseDir . '/Framework/Utils/Size.php',
|
218 |
'WPStaging\\Framework\\Utils\\Strings' => $baseDir . '/Framework/Utils/Strings.php',
|
219 |
'WPStaging\\Framework\\Utils\\Urls' => $baseDir . '/Framework/Utils/Urls.php',
|
@@ -221,5 +221,4 @@ return array(
|
|
221 |
'WPStaging\\Frontend\\Frontend' => $baseDir . '/Frontend/Frontend.php',
|
222 |
'WPStaging\\Frontend\\LoginForm' => $baseDir . '/Frontend/LoginForm.php',
|
223 |
'WPStaging\\Frontend\\LoginNotice' => $baseDir . '/Frontend/LoginNotice.php',
|
224 |
-
'WPStaging\\Repository\\SettingsRepository' => $baseDir . '/Repository/SettingsRepository.php',
|
225 |
);
|
12 |
'WPStaging\\Backend\\Feedback\\Feedback' => $baseDir . '/Backend/Feedback/Feedback.php',
|
13 |
'WPStaging\\Backend\\Modules\\Jobs\\Cancel' => $baseDir . '/Backend/Modules/Jobs/Cancel.php',
|
14 |
'WPStaging\\Backend\\Modules\\Jobs\\CancelUpdate' => $baseDir . '/Backend/Modules/Jobs/CancelUpdate.php',
|
15 |
+
'WPStaging\\Backend\\Modules\\Jobs\\Cleaners\\WpContentCleaner' => $baseDir . '/Backend/Modules/Jobs/Cleaners/WpContentCleaner.php',
|
16 |
'WPStaging\\Backend\\Modules\\Jobs\\Cloning' => $baseDir . '/Backend/Modules/Jobs/Cloning.php',
|
17 |
'WPStaging\\Backend\\Modules\\Jobs\\CloningProcess' => $baseDir . '/Backend/Modules/Jobs/CloningProcess.php',
|
18 |
'WPStaging\\Backend\\Modules\\Jobs\\Data' => $baseDir . '/Backend/Modules/Jobs/Data.php',
|
42 |
'WPStaging\\Backend\\Modules\\SystemInfo' => $baseDir . '/Backend/Modules/SystemInfo.php',
|
43 |
'WPStaging\\Backend\\Modules\\Views\\Forms\\Settings' => $baseDir . '/Backend/Modules/Views/Forms/Settings.php',
|
44 |
'WPStaging\\Backend\\Modules\\Views\\Tabs\\Tabs' => $baseDir . '/Backend/Modules/Views/Tabs/Tabs.php',
|
45 |
+
'WPStaging\\Backend\\Notices\\BooleanNotice' => $baseDir . '/Backend/Notices/BooleanNotice.php',
|
46 |
'WPStaging\\Backend\\Notices\\DisabledCacheNotice' => $baseDir . '/Backend/Notices/DisabledCacheNotice.php',
|
47 |
'WPStaging\\Backend\\Notices\\Notices' => $baseDir . '/Backend/Notices/Notices.php',
|
48 |
'WPStaging\\Backend\\Optimizer\\Optimizer' => $baseDir . '/Backend/Optimizer/Optimizer.php',
|
49 |
'WPStaging\\Backend\\Pluginmeta\\Meta' => $baseDir . '/Backend/Pluginmeta/Meta.php',
|
50 |
'WPStaging\\Backend\\Pluginmeta\\Pluginmeta' => $baseDir . '/Backend/Pluginmeta/Pluginmeta.php',
|
51 |
'WPStaging\\Backend\\Upgrade\\Upgrade' => $baseDir . '/Backend/Upgrade/Upgrade.php',
|
|
|
52 |
'WPStaging\\Command\\Database\\Export\\ExportCommand' => $baseDir . '/Command/Database/Export/ExportCommand.php',
|
53 |
'WPStaging\\Command\\Database\\Export\\ExportDto' => $baseDir . '/Command/Database/Export/ExportDto.php',
|
54 |
'WPStaging\\Command\\Database\\Export\\ExportException' => $baseDir . '/Command/Database/Export/ExportException.php',
|
101 |
'WPStaging\\Core\\Utils\\Browser' => $baseDir . '/Core/Utils/Browser.php',
|
102 |
'WPStaging\\Core\\Utils\\Cache' => $baseDir . '/Core/Utils/Cache.php',
|
103 |
'WPStaging\\Core\\Utils\\Directories' => $baseDir . '/Core/Utils/Directories.php',
|
|
|
104 |
'WPStaging\\Core\\Utils\\Hash' => $baseDir . '/Core/Utils/Hash.php',
|
105 |
'WPStaging\\Core\\Utils\\Helper' => $baseDir . '/Core/Utils/Helper.php',
|
106 |
'WPStaging\\Core\\Utils\\Htaccess' => $baseDir . '/Core/Utils/Htaccess.php',
|
114 |
'WPStaging\\Core\\Utils\\Strings' => $baseDir . '/Core/Utils/Strings.php',
|
115 |
'WPStaging\\Core\\WPStaging' => $baseDir . '/Core/WPStaging.php',
|
116 |
'WPStaging\\Core\\thirdParty\\thirdPartyCompatibility' => $baseDir . '/Core/thirdParty/thirdPartyCompatibility.php',
|
|
|
|
|
|
|
117 |
'WPStaging\\Framework\\Adapter\\Database' => $baseDir . '/Framework/Adapter/Database.php',
|
118 |
'WPStaging\\Framework\\Adapter\\Database\\AbstractDatabase' => $baseDir . '/Framework/Adapter/Database/AbstractDatabase.php',
|
119 |
'WPStaging\\Framework\\Adapter\\Database\\DatabaseException' => $baseDir . '/Framework/Adapter/Database/DatabaseException.php',
|
164 |
'WPStaging\\Framework\\Entity\\AbstractEntity' => $baseDir . '/Framework/Entity/AbstractEntity.php',
|
165 |
'WPStaging\\Framework\\Entity\\EntityException' => $baseDir . '/Framework/Entity/EntityException.php',
|
166 |
'WPStaging\\Framework\\Entity\\IdentifyableEntityInterface' => $baseDir . '/Framework/Entity/IdentifyableEntityInterface.php',
|
167 |
+
'WPStaging\\Framework\\Filesystem\\DirectoryListing' => $baseDir . '/Framework/Filesystem/DirectoryListing.php',
|
168 |
'WPStaging\\Framework\\Filesystem\\DirectoryScanner' => $baseDir . '/Framework/Filesystem/DirectoryScanner.php',
|
169 |
+
'WPStaging\\Framework\\Filesystem\\DirectoryScannerControl' => $baseDir . '/Framework/Filesystem/DirectoryScannerControl.php',
|
170 |
'WPStaging\\Framework\\Filesystem\\DiskFullException' => $baseDir . '/Framework/Filesystem/DiskFullException.php',
|
171 |
'WPStaging\\Framework\\Filesystem\\File' => $baseDir . '/Framework/Filesystem/File.php',
|
172 |
'WPStaging\\Framework\\Filesystem\\FileScanner' => $baseDir . '/Framework/Filesystem/FileScanner.php',
|
173 |
+
'WPStaging\\Framework\\Filesystem\\FileScannerControl' => $baseDir . '/Framework/Filesystem/FileScannerControl.php',
|
174 |
'WPStaging\\Framework\\Filesystem\\Filesystem' => $baseDir . '/Framework/Filesystem/Filesystem.php',
|
175 |
'WPStaging\\Framework\\Filesystem\\FilesystemExceptions' => $baseDir . '/Framework/Filesystem/FilesystemExceptions.php',
|
176 |
'WPStaging\\Framework\\Filesystem\\FilterableDirectoryIterator' => $baseDir . '/Framework/Filesystem/FilterableDirectoryIterator.php',
|
178 |
'WPStaging\\Framework\\Filesystem\\Filters\\ExtensionExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/ExtensionExcludeFilter.php',
|
179 |
'WPStaging\\Framework\\Filesystem\\Filters\\PathExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/PathExcludeFilter.php',
|
180 |
'WPStaging\\Framework\\Filesystem\\Filters\\RecursiveExtensionExcludeFilter' => $baseDir . '/Framework/Filesystem/Filters/RecursiveExtensionExcludeFilter.php',
|
181 |
+
'WPStaging\\Framework\\Filesystem\\Permissions' => $baseDir . '/Framework/Filesystem/Permissions.php',
|
182 |
'WPStaging\\Framework\\Filesystem\\WpUploadsFolderSymlinker' => $baseDir . '/Framework/Filesystem/WpUploadsFolderSymlinker.php',
|
183 |
'WPStaging\\Framework\\Interfaces\\ArrayableInterface' => $baseDir . '/Framework/Interfaces/ArrayableInterface.php',
|
184 |
'WPStaging\\Framework\\Interfaces\\HydrateableInterface' => $baseDir . '/Framework/Interfaces/HydrateableInterface.php',
|
195 |
'WPStaging\\Framework\\Queue\\Storage\\QueueStorageException' => $baseDir . '/Framework/Queue/Storage/QueueStorageException.php',
|
196 |
'WPStaging\\Framework\\Queue\\Storage\\StorageInterface' => $baseDir . '/Framework/Queue/Storage/StorageInterface.php',
|
197 |
'WPStaging\\Framework\\Security\\AccessToken' => $baseDir . '/Framework/Security/AccessToken.php',
|
198 |
+
'WPStaging\\Framework\\Security\\Auth' => $baseDir . '/Framework/Security/Auth.php',
|
199 |
'WPStaging\\Framework\\Security\\Capabilities' => $baseDir . '/Framework/Security/Capabilities.php',
|
200 |
'WPStaging\\Framework\\Security\\Nonce' => $baseDir . '/Framework/Security/Nonce.php',
|
201 |
'WPStaging\\Framework\\SiteInfo' => $baseDir . '/Framework/SiteInfo.php',
|
204 |
'WPStaging\\Framework\\TemplateEngine\\TemplateEngineException' => $baseDir . '/Framework/TemplateEngine/TemplateEngineException.php',
|
205 |
'WPStaging\\Framework\\TemplateEngine\\TemplateEngineInterface' => $baseDir . '/Framework/TemplateEngine/TemplateEngineInterface.php',
|
206 |
'WPStaging\\Framework\\Traits\\ArrayableTrait' => $baseDir . '/Framework/Traits/ArrayableTrait.php',
|
207 |
+
'WPStaging\\Framework\\Traits\\BenchmarkTrait' => $baseDir . '/Framework/Traits/BenchmarkTrait.php',
|
208 |
'WPStaging\\Framework\\Traits\\BooleanTransientTrait' => $baseDir . '/Framework/Traits/BooleanTransientTrait.php',
|
209 |
'WPStaging\\Framework\\Traits\\HydrateTrait' => $baseDir . '/Framework/Traits/HydrateTrait.php',
|
210 |
'WPStaging\\Framework\\Traits\\MaintenanceTrait' => $baseDir . '/Framework/Traits/MaintenanceTrait.php',
|
214 |
'WPStaging\\Framework\\Utils\\Cache\\AbstractCache' => $baseDir . '/Framework/Utils/Cache/AbstractCache.php',
|
215 |
'WPStaging\\Framework\\Utils\\Cache\\BufferedCache' => $baseDir . '/Framework/Utils/Cache/BufferedCache.php',
|
216 |
'WPStaging\\Framework\\Utils\\Cache\\Cache' => $baseDir . '/Framework/Utils/Cache/Cache.php',
|
|
|
217 |
'WPStaging\\Framework\\Utils\\Size' => $baseDir . '/Framework/Utils/Size.php',
|
218 |
'WPStaging\\Framework\\Utils\\Strings' => $baseDir . '/Framework/Utils/Strings.php',
|
219 |
'WPStaging\\Framework\\Utils\\Urls' => $baseDir . '/Framework/Utils/Urls.php',
|
221 |
'WPStaging\\Frontend\\Frontend' => $baseDir . '/Frontend/Frontend.php',
|
222 |
'WPStaging\\Frontend\\LoginForm' => $baseDir . '/Frontend/LoginForm.php',
|
223 |
'WPStaging\\Frontend\\LoginNotice' => $baseDir . '/Frontend/LoginNotice.php',
|
|
|
224 |
);
|
wp-staging.php
CHANGED
@@ -7,7 +7,7 @@
|
|
7 |
* Author: WP-STAGING
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi
|
10 |
-
* Version: 2.8.
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|
@@ -24,59 +24,28 @@
|
|
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
|
28 |
* @category Development, Migrating, Staging
|
29 |
-
* @author
|
30 |
*/
|
31 |
|
32 |
-
namespace WPStaging\Bootstrap\V1;
|
33 |
-
|
34 |
if (!defined("WPINC")) {
|
35 |
die;
|
36 |
}
|
37 |
|
38 |
-
if (
|
39 |
-
|
40 |
-
|
41 |
-
|
42 |
-
|
43 |
-
|
44 |
-
|
45 |
-
if (!class_exists(WpstgFreeBootstrap::class)) {
|
46 |
-
class WpstgFreeBootstrap extends WpstgBootstrap
|
47 |
-
{
|
48 |
-
protected function afterBootstrap()
|
49 |
{
|
50 |
-
|
51 |
-
|
52 |
-
|
53 |
-
|
54 |
-
// WP STAGING version number
|
55 |
-
if (!defined('WPSTG_VERSION')) {
|
56 |
-
define('WPSTG_VERSION', '2.8.0');
|
57 |
-
}
|
58 |
-
|
59 |
-
// Compatible up to WordPress Version
|
60 |
-
if (!defined('WPSTG_COMPATIBLE')) {
|
61 |
-
define('WPSTG_COMPATIBLE', '5.6');
|
62 |
-
}
|
63 |
-
|
64 |
-
require_once __DIR__ . '/constants.php';
|
65 |
-
|
66 |
-
require_once(__DIR__ . '/_init.php');
|
67 |
}
|
68 |
}
|
69 |
-
|
70 |
-
|
71 |
-
$bootstrap = new WpstgFreeBootstrap(__DIR__, new WpstgFreeRequirements(__FILE__));
|
72 |
-
|
73 |
-
add_action('plugins_loaded', [$bootstrap, 'checkRequirements'], 5);
|
74 |
-
add_action('plugins_loaded', [$bootstrap, 'bootstrap'], 10);
|
75 |
-
|
76 |
-
/** Installation Hooks */
|
77 |
-
if (!class_exists('WPStaging\Install')) {
|
78 |
-
require_once __DIR__ . "/install.php";
|
79 |
-
|
80 |
-
$install = new \WPStaging\Install($bootstrap);
|
81 |
-
register_activation_hook(__FILE__, [$install, 'activation']);
|
82 |
}
|
7 |
* Author: WP-STAGING
|
8 |
* Author URI: https://wp-staging.com
|
9 |
* Contributors: ReneHermi
|
10 |
+
* Version: 2.8.1
|
11 |
* Text Domain: wp-staging
|
12 |
* Domain Path: /languages/
|
13 |
*
|
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 Development, Migrating, Staging
|
29 |
+
* @author WP STAGING
|
30 |
*/
|
31 |
|
|
|
|
|
32 |
if (!defined("WPINC")) {
|
33 |
die;
|
34 |
}
|
35 |
|
36 |
+
if (version_compare(phpversion(), '5.5.0', '>=')) {
|
37 |
+
// The absolute path to the main file of this plugin.
|
38 |
+
$pluginFilePath = __FILE__;
|
39 |
+
include_once dirname(__FILE__) . '/freeBootstrap.php';
|
40 |
+
} else {
|
41 |
+
if (!function_exists('wpstg_unsupported_php_version')) {
|
42 |
+
function wpstg_unsupported_php_version()
|
|
|
|
|
|
|
|
|
43 |
{
|
44 |
+
echo '<div class="notice-warning notice is-dismissible">';
|
45 |
+
echo '<p style="font-weight: bold;">' . esc_html__('WP STAGING') . '</p>';
|
46 |
+
echo '<p>' . esc_html__(sprintf('WPSTAGING requires PHP %s or higher. Your site is running an outdated version of PHP (%s), which requires an update.', '5.5', phpversion()), 'wp-staging') . '</p>';
|
47 |
+
echo '</div>';
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
48 |
}
|
49 |
}
|
50 |
+
add_action('admin_notices', 'wpstg_unsupported_php_version');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
51 |
}
|