PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.6.4
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.6.4
1.6.4 1.6.3 1.6.2 1.6.1 1.6.0 1.5.4 1.5.5 1.5.3 1.5.2 1.5.1 1.5.0 1.4.2 1.4.1 1.4.0 1.3.28 1.3.27 1.3.26 1.3.25 1.3.23 1.3.22 1.3.21 1.3.20 1.3.19 trunk 1.2.0 All 47 releases
fluent-cart / app / Services / PluginInstaller / AddonManager.php

AddonManager.php in FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler 1.6.4, at app/Services/PluginInstaller/AddonManager.php

321 lines 10.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace FluentCart\App\Services\PluginInstaller;
4
5 class AddonManager
6 {
7 public function installAddon($sourceType, $sourceLink, $pluginSlug, $path = 'zipball_url')
8 {
9 if (!current_user_can('install_plugins')) {
10 return new \WP_Error('permission_denied', __('You do not have permission to install plugins.', 'fluent-cart'));
11 }
12
13 $backgroundInstaller = new BackgroundInstaller();
14 if ($sourceType === 'wordpress') {
15 $result = $backgroundInstaller->installPlugin($pluginSlug);
16 } else if ($sourceType === 'cdn') {
17 $result = $backgroundInstaller->installFromCdn($sourceLink, $pluginSlug);
18 } else if ($sourceType === 'github') {
19 $result = $backgroundInstaller->installFromGithub($sourceLink, $pluginSlug, $path);
20 } else {
21 return new \WP_Error('invalid_source', __('Invalid addon source type.', 'fluent-cart'));
22 }
23
24 return $result;
25 }
26
27 public function activateAddon($pluginFile)
28 {
29 if (!current_user_can('activate_plugins')) {
30 return new \WP_Error('permission_denied', __('You do not have permission to activate plugins.', 'fluent-cart'));
31 }
32
33 if (!function_exists('activate_plugin')) {
34 require_once ABSPATH . 'wp-admin/includes/plugin.php';
35 }
36
37 $result = activate_plugin($pluginFile);
38
39 if (is_wp_error($result)) {
40 return $result;
41 }
42
43 return true;
44 }
45
46 public static function getAddonStatus($pluginSlug, $pluginFile)
47 {
48 if (!function_exists('get_plugins')) {
49 require_once ABSPATH . 'wp-admin/includes/plugin.php';
50 }
51
52 if (!function_exists('is_plugin_active')) {
53 require_once ABSPATH . 'wp-admin/includes/plugin.php';
54 }
55
56 $all_plugins = get_plugins();
57 $is_installed = isset($all_plugins[$pluginFile]);
58 $is_active = is_plugin_active($pluginFile);
59
60 return [
61 'is_installed' => $is_installed,
62 'is_active' => $is_active,
63 'plugin_slug' => $pluginSlug,
64 'plugin_file' => $pluginFile
65 ];
66 }
67
68 /**
69 * Check for updates based on source type
70 *
71 * @param string $sourceType Source type (github, wordpress, other)
72 * @param string $sourceLink Source URL (for github, other sources)
73 * @param string $pluginFile Plugin file path
74 * @param string $pluginSlug Plugin slug (for wordpress)
75 * @return array|\WP_Error
76 */
77 public function checkForUpdate($sourceType, $sourceLink, $pluginFile, $pluginSlug = '')
78 {
79 if (!function_exists('get_plugin_data')) {
80 require_once ABSPATH . 'wp-admin/includes/plugin.php';
81 }
82
83 // Get current plugin version
84 $pluginPath = WP_PLUGIN_DIR . '/' . $pluginFile;
85 if (!file_exists($pluginPath)) {
86 return new \WP_Error('plugin_not_found', __('Plugin file not found.', 'fluent-cart'));
87 }
88
89 $pluginData = get_plugin_data($pluginPath);
90 $currentVersion = $pluginData['Version'] ?? '1.0.0';
91
92 // Route to appropriate update check method
93 switch ($sourceType) {
94 case 'github':
95 return $this->checkUpdateFromGitHub($sourceLink, $currentVersion);
96
97 case 'wordpress':
98 return $this->checkUpdateFromWordPress($pluginFile, $currentVersion);
99
100 default:
101 return $this->checkUpdateFromOther($sourceType, $sourceLink, $currentVersion);
102 }
103 }
104
105 /**
106 * Check for updates from GitHub
107 *
108 * @param string $sourceLink releases/latest URL
109 * @param string $currentVersion Current plugin version
110 * @return array|\WP_Error
111 */
112 private function checkUpdateFromGitHub($sourceLink, $currentVersion)
113 {
114 if (!$sourceLink) {
115 return new \WP_Error('invalid_url', __('Source link is required', 'fluent-cart'));
116 }
117
118 $latestVersionInfo = $this->getLatestGitHubVersion($sourceLink);
119
120 if (is_wp_error($latestVersionInfo)) {
121 return $latestVersionInfo;
122 }
123
124 $latestVersion = $latestVersionInfo['version'];
125 $hasUpdate = version_compare($latestVersion, $currentVersion, '>');
126
127 return [
128 'current_version' => $currentVersion,
129 'latest_version' => $latestVersion,
130 'has_update' => $hasUpdate,
131 'download_url' => $latestVersionInfo['download_url'],
132 'release_notes' => $latestVersionInfo['release_notes'] ?? '',
133 'source_type' => 'github'
134 ];
135 }
136
137 /**
138 * Check for updates from WordPress.org
139 *
140 * @param string $pluginFile Plugin file path
141 * @param string $currentVersion Current plugin version
142 * @return array|\WP_Error
143 */
144 private function checkUpdateFromWordPress($pluginFile, $currentVersion)
145 {
146 // Force refresh of update transients
147 wp_update_plugins();
148
149 // Get available updates
150 $update_plugins = get_site_transient('update_plugins');
151
152 if (!$update_plugins || !isset($update_plugins->response)) {
153 return new \WP_Error('no_updates', __('Unable to check for updates from WordPress.org', 'fluent-cart'));
154 }
155
156 // Check if this plugin has an update available
157 if (isset($update_plugins->response[$pluginFile])) {
158 $update = $update_plugins->response[$pluginFile];
159
160 return [
161 'current_version' => $currentVersion,
162 'latest_version' => $update->new_version,
163 'has_update' => true,
164 'download_url' => $update->package ?? '',
165 'release_notes' => $update->upgrade_notice ?? '',
166 'source_type' => 'wordpress'
167 ];
168 }
169
170 // No update available
171 return [
172 'current_version' => $currentVersion,
173 'latest_version' => $currentVersion,
174 'has_update' => false,
175 'download_url' => '',
176 'release_notes' => '',
177 'source_type' => 'wordpress'
178 ];
179 }
180
181 /**
182 * Check for updates from other sources (placeholder)
183 *
184 * @param string $sourceType Source type
185 * @param string $sourceLink Source link
186 * @param string $currentVersion Current plugin version
187 * @return array|\WP_Error
188 */
189 private function checkUpdateFromOther($sourceType, $sourceLink, $currentVersion)
190 {
191 return new \WP_Error(
192 'not_supported',
193 sprintf(
194 __('Update check for source type "%s" is not currently available.', 'fluent-cart'),
195 $sourceType
196 )
197 );
198 }
199
200 /**
201 * Get latest version info from GitHub
202 *
203 * @param string $releasesUrl GitHub releases URL
204 * @return array|\WP_Error
205 */
206 private function getLatestGitHubVersion($releasesUrl)
207 {
208 preg_match('#github\.com/([^/]+)/([^/]+)/releases#', $releasesUrl, $matches);
209
210 if (empty($matches[1]) || empty($matches[2])) {
211 return new \WP_Error('invalid_url', __('Invalid GitHub releases URL', 'fluent-cart'));
212 }
213
214 $owner = $matches[1];
215 $repo = $matches[2];
216
217 $api_url = "https://api.github.com/repos/{$owner}/{$repo}/releases/latest";
218
219 $response = wp_remote_get($api_url, [
220 'timeout' => 30,
221 'headers' => [
222 'Accept' => 'application/vnd.github.v3+json',
223 'User-Agent' => 'FluentCart/' . FLUENTCART_VERSION
224 ]
225 ]);
226
227 if (is_wp_error($response)) {
228 return new \WP_Error('api_error', $response->get_error_message());
229 }
230
231 $code = wp_remote_retrieve_response_code($response);
232 if ($code !== 200) {
233 /* translators: %1$s: HTTP status code */
234 return new \WP_Error('api_error', sprintf(__('Github API error with status code: %1$s', 'fluent-cart'), $code));
235 }
236
237 $body = wp_remote_retrieve_body($response);
238 $data = json_decode($body, true);
239
240 if (empty($data['tag_name']) || empty($data['zipball_url'])) {
241 return new \WP_Error('no_release', __('No release found. Please ensure the repository has published releases.', 'fluent-cart'));
242 }
243
244 // Extract version number from tag (remove 'v' prefix if present)
245 $version = ltrim($data['tag_name'], 'vV');
246
247 return [
248 'version' => $version,
249 'download_url' => $data['zipball_url'],
250 'release_notes' => $data['body'] ?? ''
251 ];
252 }
253
254
255 /**
256 * Update addon from WordPress.org
257 *
258 * @param string $pluginFile Plugin file path
259 * @return bool|\WP_Error
260 */
261 private function updateFromWordPress($pluginFile)
262 {
263 require_once ABSPATH . 'wp-admin/includes/file.php';
264 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
265 require_once ABSPATH . 'wp-admin/includes/plugin.php';
266
267 $was_active = is_plugin_active($pluginFile);
268
269 if ($was_active) {
270 deactivate_plugins($pluginFile, true); // true = silent
271 }
272
273 // Use WordPress native Plugin_Upgrader
274 $skin = new \WP_Ajax_Upgrader_Skin();
275 $upgrader = new \Plugin_Upgrader($skin);
276
277 // Perform the upgrade
278 $result = $upgrader->upgrade($pluginFile);
279
280 if (is_wp_error($result)) {
281 if ($was_active) {
282 activate_plugin($pluginFile, '', false, true); // true = silent
283 }
284 return $result;
285 }
286
287 if ($result === false) {
288 if ($was_active) {
289 activate_plugin($pluginFile, '', false, true);
290 }
291 return new \WP_Error('update_failed', __('Plugin update failed.', 'fluent-cart'));
292 }
293
294 if ($was_active) {
295 $activate_result = activate_plugin($pluginFile, '', false, true);
296
297 if (is_wp_error($activate_result)) {
298 return new \WP_Error('activation_failed', $activate_result->get_error_message());
299 }
300 }
301
302 return true;
303 }
304
305 /**
306 * Update addon from other sources (placeholder)
307 *
308 * @param string $sourceType Source type
309 * @return \WP_Error
310 */
311 private function updateFromOther($sourceType)
312 {
313 return new \WP_Error(
314 'not_supported',
315 sprintf(
316 __('Update for source type "%s" is not currently available.', 'fluent-cart'),
317 $sourceType
318 )
319 );
320 }
321 }