PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backup, Restore, Migration & Clone / 3.3.1
WP STAGING – WordPress Backup, Restore, Migration & Clone v3.3.1
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
Ajax 2 years ago CloneOptions.php 2 years ago FirstRun.php 3 years ago Sites.php 2 years ago
Sites.php
244 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 * The option that stores Godaddy the excluded files from cloning process
51 */
52 const STAGING_EXCLUDED_GD_FILES_OPTION = 'wpstg_clone_excluded_gd_files_list';
53
54 /**
55 * Return list of staging sites in descending order of their creation time.
56 *
57 * @return array
58 */
59 public function getSortedStagingSites()
60 {
61 $stagingSites = get_option(self::STAGING_SITES_OPTION, []);
62
63 // No need to sort if no sites or only one site
64 if (empty($stagingSites) || count($stagingSites) === 1) {
65 return $stagingSites;
66 }
67
68 // Sort staging sites in descending order
69 uasort($stagingSites, function ($site1, $site2) {
70 // If datetime is same, sort by directory name
71 // Will also work if both sites datetime are not set
72 if ($site1['datetime'] === $site2['datetime']) {
73 return strcmp($site2['directoryName'], $site1['directoryName']);
74 }
75
76 if (!isset($site1['datetime'])) {
77 return 1;
78 }
79
80 if (!isset($site2['datetime'])) {
81 return -1;
82 }
83
84 return $site2['datetime'] < $site1['datetime'] ? -1 : 1;
85 });
86
87 return $stagingSites;
88 }
89
90 /**
91 * Copy data from old staging site option wpstg_existing_clones_beta to new staging site option wpstg_staging_sites
92 *
93 * @see \WPStaging\Backend\Upgrade\Upgrade::upgrade2_8_7 (Free version)
94 * @see \WPStaging\Backend\Pro\Upgrade\Upgrade::upgrade4_0_5 (Pro version)
95 */
96 public function upgradeStagingSitesOption()
97 {
98 $newSitesOption = get_option(self::STAGING_SITES_OPTION, []);
99
100 // Early bail: If it's already populated and not empty do nothing. It has been migrated already.
101 if (!empty($newSiteOption)) {
102 return;
103 }
104
105 // If its no valid array, it is broken
106 if (!is_array($newSitesOption)) {
107 $newSitesOption = [];
108 }
109
110 // Get the staging sites from old option
111 $oldSitesOption = get_option(self::OLD_STAGING_SITES_OPTION, []);
112
113 // Early bail: No sites to migrate
114 if (empty($oldSitesOption)) {
115 return;
116 }
117
118 // Convert old format to new, including when there are staging sites in both formats
119 $allStagingSites = $newSitesOption;
120
121 foreach ($oldSitesOption as $oldSiteSlug => $oldSite) {
122 // Migrate old site to new format
123 if (!array_key_exists($oldSiteSlug, $allStagingSites)) {
124 $allStagingSites[$oldSiteSlug] = $oldSite;
125 continue;
126 }
127
128 // If key exists and path matches, skip
129 if ($allStagingSites[$oldSiteSlug]['path'] === $oldSite['path']) {
130 continue;
131 }
132
133 // Migrate old site to new format when site slug exists in both options
134 $i = 0;
135
136 do {
137 $oldSiteSlug = $oldSiteSlug . '_' . $i;
138 } while (array_key_exists($oldSiteSlug, $allStagingSites));
139
140 $allStagingSites[$oldSiteSlug] = $oldSite;
141 }
142
143 if (update_option(self::STAGING_SITES_OPTION, $allStagingSites)) {
144 // Keep a backup just in case
145 update_option(self::BACKUP_STAGING_SITES_OPTION, $oldSitesOption, false);
146 delete_option(self::OLD_STAGING_SITES_OPTION);
147 }
148 }
149
150 /**
151 * Will try getting staging sites from new option
152 * If that is empty, will get staging sites from old option
153 *
154 * @return array
155 */
156 public function tryGettingStagingSites()
157 {
158 $stagingSites = get_option(self::STAGING_SITES_OPTION, []);
159 if (!empty($stagingSites)) {
160 return $stagingSites;
161 }
162
163 return get_option(self::OLD_STAGING_SITES_OPTION, []);
164 }
165
166 /**
167 * Update staging sites option
168 *
169 * @param array $stagingSites
170 * @return bool
171 */
172 public function updateStagingSites($stagingSites)
173 {
174 return update_option(self::STAGING_SITES_OPTION, $stagingSites);
175 }
176
177 /**
178 * Upgrade the staging site data structure, add the missing cloneName, if not present
179 */
180 public function addMissingCloneNameUpgradeStructure()
181 {
182 $isAdded = get_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, false);
183 if ($isAdded) {
184 return;
185 }
186
187 // Current options
188 $sites = $this->tryGettingStagingSites();
189
190 // Early bail if no sites
191 if (empty($sites)) {
192 update_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, true);
193 return;
194 }
195
196 // Add missing cloneName if not exists
197 foreach ($sites as $key => $site) {
198 if (isset($sites[$key]['cloneName'])) {
199 continue;
200 }
201
202 $sites[$key]['cloneName'] = $sites[$key]['directoryName'];
203 }
204
205 $this->updateStagingSites($sites);
206 update_option(self::MISSING_CLONE_NAME_ROUTINE_EXECUTED, true);
207 }
208
209 /**
210 * Sanitize the clone name to be used as directory
211 *
212 * @param string $cloneName
213 * @return string
214 */
215 public function sanitizeDirectoryName($cloneName)
216 {
217 $cloneDirectoryName = preg_replace("#\W+#", '-', strtolower($cloneName));
218 return substr($cloneDirectoryName, 0, 16);
219 }
220
221 /**
222 * Return false if site not exists else return reason behind existing
223 *
224 * @param string $directoryName
225 * @return bool|string
226 */
227 public function isCloneExists($directoryName)
228 {
229 $cloneDirectoryPath = trailingslashit(get_home_path()) . $directoryName;
230 if (!wpstg_is_empty_dir($cloneDirectoryPath)) {
231 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);
232 }
233
234 $stagingSites = $this->tryGettingStagingSites();
235 foreach ($stagingSites as $site) {
236 if ($site['directoryName'] === $directoryName) {
237 return __("Site name is already in use, please choose another name for the staging site.", "wp-staging");
238 }
239 }
240
241 return false;
242 }
243 }
244