PluginProbe
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler / 1.3.27
FluentCart A New Era of eCommerce – Faster, Lighter, and Simpler v1.3.27
1.6.6 1.6.5 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 All 49 releases
fluent-cart / app / Services / PluginInstaller / AddonManager.php

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

320 lines 10.3 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 return new \WP_Error('api_error', 'Github API error with status code: ' . $code);
234 }
235
236 $body = wp_remote_retrieve_body($response);
237 $data = json_decode($body, true);
238
239 if (empty($data['tag_name']) || empty($data['zipball_url'])) {
240 return new \WP_Error('no_release', 'No release found. Please ensure the repository has published releases.');
241 }
242
243 // Extract version number from tag (remove 'v' prefix if present)
244 $version = ltrim($data['tag_name'], 'vV');
245
246 return [
247 'version' => $version,
248 'download_url' => $data['zipball_url'],
249 'release_notes' => $data['body'] ?? ''
250 ];
251 }
252
253
254 /**
255 * Update addon from WordPress.org
256 *
257 * @param string $pluginFile Plugin file path
258 * @return bool|\WP_Error
259 */
260 private function updateFromWordPress($pluginFile)
261 {
262 require_once ABSPATH . 'wp-admin/includes/file.php';
263 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
264 require_once ABSPATH . 'wp-admin/includes/plugin.php';
265
266 $was_active = is_plugin_active($pluginFile);
267
268 if ($was_active) {
269 deactivate_plugins($pluginFile, true); // true = silent
270 }
271
272 // Use WordPress native Plugin_Upgrader
273 $skin = new \WP_Ajax_Upgrader_Skin();
274 $upgrader = new \Plugin_Upgrader($skin);
275
276 // Perform the upgrade
277 $result = $upgrader->upgrade($pluginFile);
278
279 if (is_wp_error($result)) {
280 if ($was_active) {
281 activate_plugin($pluginFile, '', false, true); // true = silent
282 }
283 return $result;
284 }
285
286 if ($result === false) {
287 if ($was_active) {
288 activate_plugin($pluginFile, '', false, true);
289 }
290 return new \WP_Error('update_failed', __('Plugin update failed.', 'fluent-cart'));
291 }
292
293 if ($was_active) {
294 $activate_result = activate_plugin($pluginFile, '', false, true);
295
296 if (is_wp_error($activate_result)) {
297 return new \WP_Error('activation_failed', $activate_result->get_error_message());
298 }
299 }
300
301 return true;
302 }
303
304 /**
305 * Update addon from other sources (placeholder)
306 *
307 * @param string $sourceType Source type
308 * @return \WP_Error
309 */
310 private function updateFromOther($sourceType)
311 {
312 return new \WP_Error(
313 'not_supported',
314 sprintf(
315 __('Update for source type "%s" is not currently available.', 'fluent-cart'),
316 $sourceType
317 )
318 );
319 }
320 }