PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / 4.2.2
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets v4.2.2
4.5.6 4.5.5 4.5.4 4.2.1 4.2.2 4.2.3 4.5.0 4.5.2 4.5.3 4.2.0 4.1.18 4.1.17 4.1.16 4.1.15 4.1.14 4.1.13 4.1.12 4.1.11 4.1.10 4.1.9 4.1.8 4.0.9 4.1.0 4.1.1 4.1.2 All 148 releases
ultimate-post-kit / includes / setup-wizard / ultimate-post-kit-others-plugin.php

ultimate-post-kit-others-plugin.php in Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets 4.2.2, at includes/setup-wizard/ultimate-post-kit-others-plugin.php

591 lines 27.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Ultimate Post Kit Others Plugin - Standalone Plugin Manager
4 *
5 * This file provides the enhanced plugin installation and management system
6 * for Ultimate Post Kit, separated from the main admin settings for better maintainability.
7 *
8 * @version 1.0.0
9 * @author BDThemes
10 */
11
12 if (!defined('ABSPATH')) {
13 exit;
14 }
15
16 /**
17 * Ultimate Post Kit Others Plugin Manager
18 */
19 class UltimatePostKit_Others_Plugin_Manager {
20
21 /**
22 * Constructor
23 */
24 public function __construct() {
25 // Add AJAX handlers
26 add_action('wp_ajax_upk_get_plugins', [$this, 'ajax_get_plugins']);
27 add_action('wp_ajax_nopriv_upk_get_plugins', [$this, 'ajax_get_plugins']);
28 add_action('wp_ajax_upk_install_plugin', [$this, 'install_plugin_ajax']);
29 }
30
31 /**
32 * Render the others plugin interface
33 */
34 public function render_others_plugin() {
35 // Include the required classes
36 require_once BDTUPK_INC_PATH . 'setup-wizard/class-plugin-integration-helper.php';
37 require_once BDTUPK_INC_PATH . 'setup-wizard/class-remote-data-handler.php';
38
39 // Define plugin slugs for reference
40 $plugin_slugs = array(
41 'bdthemes-element-pack-lite',
42 'bdthemes-prime-slider-lite/bdthemes-prime-slider.php',
43 'ultimate-post-kit',
44 'ultimate-store-kit',
45 'zoloblocks',
46 'pixel-gallery',
47 'live-copy-paste',
48 'spin-wheel',
49 'ai-image',
50 'dark-reader',
51 'ar-viewer',
52 'smart-admin-assistant',
53 'website-accessibility',
54 );
55
56 // Helper function for time formatting
57 if (!function_exists('format_last_updated_usk')) {
58 function format_last_updated_usk($date_string) {
59 if (empty($date_string)) {
60 return __('Unknown', 'ultimate-post-kit');
61 }
62
63 $date = strtotime($date_string);
64 if (!$date) {
65 return __('Unknown', 'ultimate-post-kit');
66 }
67
68 $diff = current_time('timestamp') - $date;
69
70 if ($diff < 60) {
71 return __('Just now', 'ultimate-post-kit');
72 } elseif ($diff < 3600) {
73 $minutes = floor($diff / 60);
74 /* translators: %d: number of minutes */
75 return sprintf(_n('%d minute ago', '%d minutes ago', $minutes, 'ultimate-post-kit'), $minutes);
76 } elseif ($diff < 86400) {
77 $hours = floor($diff / 3600);
78 /* translators: %d: number of hours */
79 return sprintf(_n('%d hour ago', '%d hours ago', $hours, 'ultimate-post-kit'), $hours);
80 } elseif ($diff < 2592000) { // 30 days
81 $days = floor($diff / 86400);
82 /* translators: %d: number of days */
83 return sprintf(_n('%d day ago', '%d days ago', $days, 'ultimate-post-kit'), $days);
84 } elseif ($diff < 31536000) { // 1 year
85 $months = floor($diff / 2592000);
86 /* translators: %d: number of months */
87 return sprintf(_n('%d month ago', '%d months ago', $months, 'ultimate-post-kit'), $months);
88 } else {
89 $years = floor($diff / 31536000);
90 /* translators: %d: number of years */
91 return sprintf(_n('%d year ago', '%d years ago', $years, 'ultimate-post-kit'), $years);
92 }
93 }
94 }
95
96 // Helper function for fallback URLs
97 if (!function_exists('get_plugin_fallback_urls_usk')) {
98 function get_plugin_fallback_urls_usk($plugin_slug) {
99 // Handle different plugin slug formats
100 if (strpos($plugin_slug, '/') !== false) {
101 // If it's a file path like 'plugin-name/plugin-name.php', extract directory
102 $plugin_slug_clean = dirname($plugin_slug);
103 } else {
104 // If it's just the plugin directory name, use it directly
105 $plugin_slug_clean = $plugin_slug;
106 }
107
108 // Custom icon URLs for specific plugins that might not be on WordPress.org
109 $custom_icons = [
110 'ar-viewer' => [
111 'https://ps.w.org/ar-viewer/assets/icon-256x256.gif',
112 'https://ps.w.org/ar-viewer/assets/icon-128x128.gif',
113 ],
114 ];
115
116 // Return custom icons if available, otherwise use default WordPress.org URLs
117 if (isset($custom_icons[$plugin_slug_clean])) {
118 return $custom_icons[$plugin_slug_clean];
119 }
120
121 return [
122 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-256x256.png", // Then PNG
123 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-128x128.png", // Medium PNG
124 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-256x256.gif", // Try GIF first
125 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-128x128.gif", // Medium GIF
126 ];
127 }
128 }
129 ?>
130
131 <div class="upk-dashboard-panel"
132 bdt-scrollspy="target: > div > div > .bdt-card; cls: bdt-animation-slide-bottom-small; delay: 300">
133 <div class="upk-dashboard-others-plugin" id="upk-others-plugin-container">
134
135 <!-- Loading state -->
136 <div class="upk-plugins-loading" id="upk-plugins-loading">
137 <div class="bdt-flex bdt-flex-center bdt-flex-middle bdt-text-center" style="min-height: 200px;">
138 <div>
139 <div class="bdt-spinner bdt-spinner-primary"></div>
140 <p class="bdt-margin-small-top"><?php esc_html_e('Loading plugin data...', 'ultimate-post-kit'); ?></p>
141 </div>
142 </div>
143 </div>
144
145 <!-- Error state (hidden by default) -->
146 <div class="upk-plugins-error" id="upk-plugins-error" style="display: none;">
147 <div class="bdt-alert bdt-alert-warning" bdt-alert>
148 <a class="bdt-alert-close" bdt-close></a>
149 <p><?php esc_html_e('Unable to load plugin data. Please try again later.', 'ultimate-post-kit'); ?></p>
150 <button class="bdt-button bdt-button-small bdt-margin-small-top" id="upk-retry-load-plugins">
151 <?php esc_html_e('Retry', 'ultimate-post-kit'); ?>
152 </button>
153 </div>
154 </div>
155
156 <!-- Plugins container (populated by AJAX) -->
157 <div class="upk-plugins-list" id="upk-plugins-list" style="display: none;">
158 <!-- Plugin cards will be inserted here by JavaScript -->
159 </div>
160 </div>
161 </div>
162
163 <style type="text/css">
164 .upk-loading-spinner {
165 position: absolute;
166 top: 50%;
167 left: 50%;
168 transform: translate(-50%, -50%);
169 text-align: center;
170 }
171
172 .upk-loading-dots {
173 display: flex;
174 justify-content: center;
175 align-items: center;
176 gap: 8px;
177 margin-bottom: 15px;
178 }
179
180 .upk-loading-dot {
181 width: 12px;
182 height: 12px;
183 background-color: #0073aa;
184 border-radius: 50%;
185 animation: upk-wave 1.4s ease-in-out infinite both;
186 }
187
188 .upk-loading-dot:nth-child(1) { animation-delay: -0.32s; }
189 .upk-loading-dot:nth-child(2) { animation-delay: -0.16s; }
190 .upk-loading-dot:nth-child(3) { animation-delay: 0; }
191
192 @keyframes upk-wave {
193 0%, 80%, 100% {
194 transform: scale(0.8);
195 opacity: 0.5;
196 }
197 40% {
198 transform: scale(1.2);
199 opacity: 1;
200 }
201 }
202
203 #upk-plugins-list {
204 position: relative;
205 min-height: 200px;
206 }
207 </style>
208
209 <script type="text/javascript">
210 jQuery(document).ready(function($) {
211 var $container = $('#upk-others-plugin-container');
212 var $loading = $('#upk-plugins-loading');
213 var $error = $('#upk-plugins-error');
214 var $list = $('#upk-plugins-list');
215
216 // Function to load plugins via AJAX
217 function loadPlugins() {
218 $loading.hide();
219 $error.hide();
220 showLoading();
221
222 $.ajax({
223 url: ajaxurl,
224 type: 'POST',
225 data: {
226 action: 'upk_get_plugins',
227 nonce: '<?php echo esc_attr( wp_create_nonce("upk_get_plugins_nonce") ); ?>'
228 },
229 success: function(response) {
230 if (response.success && response.data) {
231 if (response.data.loading) {
232 // Still loading, show message and retry after delay
233 showLoading();
234 setTimeout(loadPlugins, 3000); // Retry after 3 seconds
235 } else {
236 renderPlugins(response.data.plugins);
237 }
238 } else {
239 showError();
240 }
241 },
242 error: function() {
243 showError();
244 }
245 });
246 }
247
248 // Function to render plugins
249 function renderPlugins(plugins) {
250 var html = '';
251
252 if (plugins.length === 0) {
253 html = '<div class="bdt-text-center bdt-padding-large"><p><?php esc_html_e('No plugins available.', 'ultimate-post-kit'); ?></p></div>';
254 } else {
255 plugins.forEach(function(plugin) {
256 // Skip own plugin (Ultimate Post Kit) when printing only; data still includes it for other plugins
257 if (plugin.slug === 'ultimate-post-kit') return;
258 var isActive = false; // We'll determine this via PHP in the actual implementation
259 var logoUrl = plugin.logo || '';
260 var pluginName = plugin.name || '';
261 var pluginSlug = plugin.slug || '';
262
263 // Generate fallback logo URL if needed
264 if (!logoUrl) {
265 var actualSlug = pluginSlug.replace('.php', '').split('/')[0];
266 logoUrl = 'https://ps.w.org/' + actualSlug + '/assets/icon-256x256.png';
267 }
268
269 html += '<div class="bdt-card bdt-card-body bdt-flex bdt-flex-middle bdt-flex-between">' +
270 '<div class="bdt-others-plugin-content">' +
271 '<div class="bdt-plugin-logo-wrap bdt-flex bdt-flex-middle">' +
272 '<div class="bdt-plugin-logo-container">' +
273 '<img src="' + logoUrl + '" alt="' + pluginName + '" class="bdt-plugin-logo" ' +
274 'onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';">' +
275 '<div class="default-plugin-icon" style="display:none;">📦</div>' +
276 '</div>' +
277 '<div class="bdt-others-plugin-user-wrap bdt-flex bdt-flex-middle">' +
278 '<h1 class="upk-feature-title">' + pluginName + '</h1>' +
279 '</div>' +
280 '</div>' +
281 '<div class="bdt-others-plugin-content-text bdt-margin-top">';
282
283 if (plugin.description) {
284 html += '<p>' + plugin.description + '</p>';
285 }
286
287 // Active installs
288 html += '<span class="active-installs bdt-margin-small-top">' +
289 '<?php esc_html_e("Active Installs: ", "ultimate-post-kit"); ?> ';
290 if (plugin.active_installs_count > 0) {
291 html += '<span class="installs-count">' + plugin.active_installs_count.toLocaleString() + '+</span>';
292 } else {
293 html += '<span class="installs-count">Fewer than 10</span>';
294 }
295 html += '</span>';
296
297 // Rating
298 html += '<div class="bdt-others-plugin-rating bdt-margin-small-top bdt-flex bdt-flex-middle">' +
299 '<span class="bdt-others-plugin-rating-stars">';
300
301 var rating = parseFloat(plugin.rating) || 0;
302 var fullStars = Math.floor(rating);
303 var hasHalfStar = (rating - fullStars) >= 0.5;
304 var emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0);
305
306 for (var i = 0; i < fullStars; i++) {
307 html += '<i class="dashicons dashicons-star-filled"></i>';
308 }
309 if (hasHalfStar) {
310 html += '<i class="dashicons dashicons-star-half"></i>';
311 }
312 for (var i = 0; i < emptyStars; i++) {
313 html += '<i class="dashicons dashicons-star-empty"></i>';
314 }
315
316 html += '</span>' +
317 '<span class="bdt-others-plugin-rating-text bdt-margin-small-left">' +
318 rating + ' <?php esc_html_e("out of 5 stars.", "ultimate-post-kit"); ?>';
319
320 if (plugin.num_ratings > 0) {
321 html += '<span class="rating-count">(' + plugin.num_ratings.toLocaleString() + ' <?php esc_html_e("ratings", "ultimate-post-kit"); ?>)</span>';
322 }
323
324 html += '</span></div>';
325
326 // Downloads
327 if (plugin.downloaded_formatted) {
328 html += '<div class="bdt-others-plugin-downloads bdt-margin-small-top">' +
329 '<span><?php esc_html_e("Downloads: ", "ultimate-post-kit"); ?>' + plugin.downloaded_formatted + '</span>' +
330 '</div>';
331 }
332
333 // Last updated
334 if (plugin.last_updated_formatted) {
335 html += '<div class="bdt-others-plugin-updated bdt-margin-small-top">' +
336 '<span><?php esc_html_e("Last Updated: ", "ultimate-post-kit"); ?>' + plugin.last_updated_formatted + '</span>' +
337 '</div>';
338 }
339
340 html += '</div></div>' +
341 '<div class="bdt-others-plugins-link">';
342
343 // Show different buttons based on plugin status
344 if (plugin.status === 'active') {
345 html += '<span class="bdt-button bdt-button-success bdt-disabled">' +
346 '<span class="dashicons dashicons-yes"></span> ' +
347 '<?php esc_html_e("Active", "ultimate-post-kit"); ?>' +
348 '</span>';
349 } else if (plugin.status === 'installed') {
350 var activateUrl = '<?php echo esc_url( admin_url("plugins.php?action=activate&plugin=") ); ?>' + plugin.plugin_file + '&_wpnonce=' + plugin.activate_nonce;
351 html += '<a class="bdt-button bdt-welcome-button" href="' + activateUrl + '">' +
352 '<?php esc_html_e("Activate", "ultimate-post-kit"); ?>' +
353 '</a>';
354 } else {
355 html += '<button class="bdt-button bdt-welcome-button upk-install-plugin" data-plugin-slug="' + pluginSlug + '" data-nonce="<?php echo esc_attr( wp_create_nonce('upk_install_plugin_nonce') ); ?>">' +
356 '<?php esc_html_e("Install", "ultimate-post-kit"); ?>' +
357 '</button>';
358 }
359
360 if (plugin.homepage) {
361 html += '<a class="bdt-button bdt-dashboard-sec-btn" target="_blank" href="' + plugin.homepage + '">' +
362 '<?php esc_html_e("Learn More", "ultimate-post-kit"); ?>' +
363 '</a>';
364 }
365
366 html += '</div></div>';
367 });
368 }
369
370 $list.html(html);
371
372 // Handle plugin action buttons
373 $('.upk-install-plugin').on('click', function(e) {
374 e.preventDefault();
375
376 var $button = $(this);
377 var pluginSlug = $button.data('plugin-slug');
378 var nonce = $button.data('nonce');
379 var originalText = $button.text();
380
381 // Disable button and show loading state
382 $button.prop('disabled', true)
383 .text('<?php echo esc_js(__('Installing...', 'ultimate-post-kit')); ?>')
384 .addClass('bdt-installing');
385
386 // Perform AJAX request
387 $.ajax({
388 url: '<?php echo esc_url( admin_url('admin-ajax.php') ); ?>',
389 type: 'POST',
390 data: {
391 action: 'upk_install_plugin',
392 plugin_slug: pluginSlug,
393 nonce: nonce
394 },
395 success: function(response) {
396 if (response.success) {
397 // Show success message
398 $button.text('<?php echo esc_js(__('Installed!', 'ultimate-post-kit')); ?>')
399 .removeClass('bdt-installing')
400 .addClass('bdt-installed');
401
402 // Show success notification
403 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
404 bdtUIkit.notification({
405 message: '<span class="dashicons dashicons-yes"></span> ' + response.data.message,
406 status: 'success'
407 });
408 }
409
410 // Reload the page after 2 seconds to update button states
411 setTimeout(function() {
412 window.location.reload();
413 }, 2000);
414
415 } else {
416 // Show error message
417 $button.prop('disabled', false)
418 .text(originalText)
419 .removeClass('bdt-installing');
420
421 // Show error notification
422 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
423 bdtUIkit.notification({
424 message: '<span class="dashicons dashicons-warning"></span> ' + response.data.message,
425 status: 'danger'
426 });
427 } else {
428 alert('Error: ' + response.data.message);
429 }
430 }
431 },
432 error: function(xhr, status, error) {
433 // Show error message
434 $button.prop('disabled', false)
435 .text(originalText)
436 .removeClass('bdt-installing');
437
438 // Show error notification
439 if (typeof bdtUIkit !== 'undefined' && bdtUIkit.notification) {
440 bdtUIkit.notification({
441 message: '<span class="dashicons dashicons-warning"></span> <?php echo esc_js(__('Installation failed. Please try again.', 'ultimate-post-kit')); ?>',
442 status: 'danger'
443 });
444 } else {
445 alert('<?php echo esc_js(__('Installation failed. Please try again.', 'ultimate-post-kit')); ?>');
446 }
447 }
448 });
449 });
450 }
451
452 // Function to show loading state
453 function showLoading() {
454 $list.html(
455 '<div class="bdt-text-center bdt-padding-large">' +
456 '<div class="upk-loading-spinner">' +
457 '<div class="upk-loading-dots">' +
458 '<div class="upk-loading-dot"></div>' +
459 '<div class="upk-loading-dot"></div>' +
460 '<div class="upk-loading-dot"></div>' +
461 '</div>' +
462 '</div>' +
463 '<p class="bdt-margin-small-top bdt-text-muted"><?php esc_html_e("Loading plugin data...", "ultimate-post-kit"); ?></p>' +
464 '</div>'
465 );
466 $list.show();
467 }
468
469 // Function to show error
470 function showError() {
471 $error.show();
472 $list.hide();
473 }
474
475 // Retry button handler
476 $('#upk-retry-load-plugins').on('click', function() {
477 loadPlugins();
478 });
479
480 // Initial load
481 loadPlugins();
482 });
483 </script>
484 <?php
485 }
486
487 /**
488 * AJAX handler for getting plugins data
489 */
490 public function ajax_get_plugins() {
491 // Verify nonce
492 if (!check_ajax_referer('upk_get_plugins_nonce', 'nonce', false)) {
493 wp_die(esc_html__('Security check failed.', 'ultimate-post-kit'));
494 }
495
496 // Get cached data
497 $plugins_data = \UltimatePostKit\SetupWizard\Remote_Data_Handler::get_remote_plugins();
498
499 // If cache is empty, try to fetch immediately (but don't block)
500 if (empty($plugins_data)) {
501 // Schedule background fetch if not already done
502 \UltimatePostKit\SetupWizard\Remote_Data_Handler::schedule_remote_fetch();
503
504 // Return empty response with flag indicating data is loading
505 wp_send_json_success([
506 'plugins' => [],
507 'loading' => true,
508 'message' => __('Loading plugin data...', 'ultimate-post-kit')
509 ]);
510 }
511
512 // Send response
513 wp_send_json_success([
514 'plugins' => $plugins_data,
515 'loading' => false,
516 'message' => __('Plugin data loaded successfully.', 'ultimate-post-kit')
517 ]);
518 }
519
520 /**
521 * AJAX handler for plugin installation
522 */
523 public function install_plugin_ajax() {
524 // Check nonce
525 if (!wp_verify_nonce($_POST['nonce'], 'upk_install_plugin_nonce')) {
526 wp_send_json_error(['message' => __('Security check failed', 'ultimate-post-kit')]);
527 }
528
529 // Check user capability
530 if (!current_user_can('install_plugins')) {
531 wp_send_json_error(['message' => __('You do not have permission to install plugins', 'ultimate-post-kit')]);
532 }
533
534 $plugin_slug = sanitize_text_field($_POST['plugin_slug']);
535
536 if (empty($plugin_slug)) {
537 wp_send_json_error(['message' => __('Plugin slug is required', 'ultimate-post-kit')]);
538 }
539
540 // Include necessary WordPress files
541 require_once ABSPATH . 'wp-admin/includes/plugin-install.php';
542 require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
543 require_once ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
544
545 // Get plugin information
546 $api = plugins_api('plugin_information', [
547 'slug' => $plugin_slug,
548 'fields' => [
549 'sections' => false,
550 ],
551 ]);
552
553 if (is_wp_error($api)) {
554 wp_send_json_error(['message' => __('Plugin not found: ', 'ultimate-post-kit') . $api->get_error_message()]);
555 }
556
557 // Install the plugin
558 $skin = new \WP_Ajax_Upgrader_Skin();
559 $upgrader = new \Plugin_Upgrader($skin);
560 $result = $upgrader->install($api->download_link);
561
562 if (is_wp_error($result)) {
563 wp_send_json_error(['message' => __('Installation failed: ', 'ultimate-post-kit') . $result->get_error_message()]);
564 } elseif ($skin->get_errors()->has_errors()) {
565 wp_send_json_error(['message' => __('Installation failed: ', 'ultimate-post-kit') . $skin->get_error_messages()]);
566 } elseif (is_null($result)) {
567 wp_send_json_error(['message' => __('Installation failed: Unable to connect to filesystem', 'ultimate-post-kit')]);
568 }
569
570 // Get installation status
571 $install_status = install_plugin_install_status($api);
572
573 wp_send_json_success([
574 'message' => __('Plugin installed successfully!', 'ultimate-post-kit'),
575 'plugin_file' => $install_status['file'],
576 'plugin_name' => $api->name
577 ]);
578 }
579 }
580
581 // Initialize the manager
582 new UltimatePostKit_Others_Plugin_Manager();
583
584 /**
585 * Helper function for easy rendering
586 */
587 function ultimate_post_kit_others_plugin() {
588 $manager = new UltimatePostKit_Others_Plugin_Manager();
589 $manager->render_others_plugin();
590 }
591