PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.0.2
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.0.2
4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Staging / Sites.php
wp-staging / Framework / Staging Last commit date
CloneOptions.php 4 years ago FirstRun.php 3 years ago Sites.php 3 years ago
Sites.php
239 lines
1 <?php
2
3 namespace WPStaging\Framework\Staging;
4
5 /**
6 * Class Sites
7 *
8 * This is used to manage settings on the staging site
9 *
10 * @package WPStaging\Framework\Staging
11 *
12 * @todo Manage staging sites option CRUD here?
13 */
14 class Sites
15 {
16 /**
17 * The option that stores the staging sites
18 */
19 const STAGING_SITES_OPTION = 'wpstg_staging_sites';
20
21 /**
22 * The option that stores login link settings
23 */
24 const STAGING_LOGIN_LINK_SETTINGS = 'wpstg_login_link_settings';
25
26 /**
27 * The old option that was used to store the staging sites
28 * @deprecated 4.0.5
29 */
30 const OLD_STAGING_SITES_OPTION = 'wpstg_existing_clones_beta';
31
32 /**
33 * Before upgrading structure, backup old staging site options
34 * @since 4.0.6
35 */
36 const BACKUP_STAGING_SITES_OPTION = 'wpstg_staging_sites_backup';
37
38 /**
39 * Missing cloneName routine executed
40 * @since 4.0.7
41 */
42 const MISSING_CLONE_NAME_ROUTINE_EXECUTED = 'wpstg_missing_cloneName_routine_executed';
43
44 /**
45 * The option that stores the excluded files from cloning process
46 */
47 const STAGING_EXCLUDED_FILES_OPTION = 'wpstg_clone_excluded_files_list';
48
49 /**
50 * Return list of staging sites in descending order of their creation time.
51 *
52 * @return array
53 */
54 public function getSortedStagingSites()
55 {
56 $stagingSites = get_option(self::STAGING_SITES_OPTION, []);
57
58 // No need to sort if no sites or only one site
59 if (empty($stagingSites) || count($stagingSites) === 1) {
60 return $stagingSites;
61 }
62
63 // Sort staging sites in descending order
64 uasort($stagingSites, function ($site1, $site2) {
65 // If datetime is same, sort by directory name
66 // Will also work if both sites datetime are not set
67 if ($site1['datetime'] === $site2['datetime']) {
68 return strcmp($site2['directoryName'], $site1['directoryName']);
69 }
70
71 if (!isset($site1['datetime'])) {
72 return 1;
73 }
74
75 if (!isset($site2['datetime'])) {
76 return -1;
77 }
78
79 return $site2['datetime'] < $site1['datetime'] ? -1 : 1;
80 });
81
82 return $stagingSites;
83 }
84
85 /**
86 * Copy data from old staging site option wpstg_existing_clones_beta to new staging site option wpstg_staging_sites
87 *
88 * @see \WPStaging\Backend\Upgrade\Upgrade::upgrade2_8_7 (Free version)
89 * @see \WPStaging\Backend\Pro\Upgrade\Upgrade::upgrade4_0_5 (Pro version)
90 */
91 public function upgradeStagingSitesOption()
92 {
93 $newSitesOption = get_option(self::STAGING_SITES_OPTION, []);
94
95 // Early bail: If it's already populated and not empty do nothing. It has been migrated already.
96 if (!empty($newSiteOption)) {
97 return;
98 }
99
100 // If its no valid array, it is broken
101 if (!is_array($newSitesOption)) {
102 $newSitesOption = [];
103 }
104
105 // Get the staging sites from old option
106 $oldSitesOption = get_option(self::OLD_STAGING_SITES_OPTION, []);
107
108 // Early bail: No sites to migrate
109 if (empty($oldSitesOption)) {
110 return;
111 }
112
113 // Convert old format to new, including when there are staging sites in both formats
114 $allStagingSites = $newSitesOption;
115
116 foreach ($oldSitesOption as $oldSiteSlug => $oldSite) {
117 // Migrate old site to new format
118 if (!array_key_exists($oldSiteSlug, $allStagingSites)) {
119 $allStagingSites[$oldSiteSlug] = $oldSite;
120 continue;
121 }
122
123 // If key exists and path matches, skip
124 if ($allStagingSites[$oldSiteSlug]['path'] === $oldSite['path']) {
125 continue;
126 }
127
128 // Migrate old site to new format when site slug exists in both options
129 $i = 0;
130
131 do {
132 $oldSiteSlug = $oldSiteSlug . '_' . $i;
133 } while (array_key_exists($oldSiteSlug, $allStagingSites));
134
135 $allStagingSites[$oldSiteSlug] = $oldSite;
136 }
137
138 if (update_option(self::STAGING_SITES_OPTION, $allStagingSites)) {
139 // Keep a backup just in case
140 update_option(self::BACKUP_STAGING_SITES_OPTION, $oldSitesOption, false);
141 delete_option(self::OLD_STAGING_SITES_OPTION);
142 }
143 }
144
145 /**
146 * Will try getting staging sites from new option
147 * If that is empty, will get staging sites from old option
148 *
149 * @return array
150 */
151 public function tryGettingStagingSites()
152 {
153 $stagingSites = get_option(self::STAGING_SITES_OPTION, []);
154 if (!empty($stagingSites)) {
155 return $stagingSites;
156 }
157
158 return get_option(self::OLD_STAGING_SITES_OPTION, []);
159 }
160
161 /**
162 * Update staging sites option
163 *
164 * @param array $stagingSites
165 * @return bool
166 */
167 public function updateStagingSites($stagingSites)
168 {
169 return update_option(self::STAGING_SITES_OPTION, $stagingSites);
170 }
171
172 /**
173 * Upgrade the staging site data structure, add the missing cloneName, if not present
174 */
175 public function addMissingCloneNameUpgradeStructure()
176 {
177 $isAdded = get_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, false);
178 if ($isAdded) {
179 return;
180 }
181
182 // Current options
183 $sites = $this->tryGettingStagingSites();
184
185 // Early bail if no sites
186 if (empty($sites)) {
187 update_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, true);
188 return;
189 }
190
191 // Add missing cloneName if not exists
192 foreach ($sites as $key => $site) {
193 if (isset($sites[$key]['cloneName'])) {
194 continue;
195 }
196
197 $sites[$key]['cloneName'] = $sites[$key]['directoryName'];
198 }
199
200 $this->updateStagingSites($sites);
201 update_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, true);
202 }
203
204 /**
205 * Sanitize the clone name to be used as directory
206 *
207 * @param string $cloneName
208 * @return string
209 */
210 public function sanitizeDirectoryName($cloneName)
211 {
212 $cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($cloneName));
213 return substr($cloneDirectoryName, 0, 16);
214 }
215
216 /**
217 * Return false if site not exists else return reason behind existing
218 *
219 * @param string $directoryName
220 * @return bool|string
221 */
222 public function isCloneExists($directoryName)
223 {
224 $cloneDirectoryPath = trailingslashit(get_home_path()) . $directoryName;
225 if (!wpstg_is_empty_dir($cloneDirectoryPath)) {
226 return sprintf(__("Warning: Use another site name! Clone destination directory %s already exists and is not empty. As default, WP STAGING uses the site name as subdirectory for the clone.", 'wp-staging'), $cloneDirectoryPath);
227 }
228
229 $stagingSites = $this->tryGettingStagingSites();
230 foreach ($stagingSites as $site) {
231 if ($site['directoryName'] === $directoryName) {
232 return __("Site name is already in use, please choose another name for the staging site.", "wp-staging");
233 }
234 }
235
236 return false;
237 }
238 }
239