PluginProbe
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets / 4.1.3
Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets v4.1.3
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 4.1.3 4.1.4 All 146 releases
ultimate-post-kit / includes / setup-wizard / views / integration.php

integration.php in Ultimate Post Kit – Elementor Post Grid, Post Carousel, Post Slider & Blog Layout Widgets 4.1.3, at includes/setup-wizard/views/integration.php

519 lines 23.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Integration Step
4 */
5
6 namespace UltimatePostKit\SetupWizard;
7
8 if (!defined('ABSPATH')) {
9 exit;
10 }
11
12 // Include the required classes
13 require_once __DIR__ . '/../class-plugin-integration-helper.php';
14 require_once __DIR__ . '/../class-remote-data-handler.php';
15
16 // Helper function for time formatting
17 if (!function_exists('format_last_updated_usk')) {
18 function format_last_updated_usk($date_string) {
19 if (empty($date_string)) {
20 return __('Unknown', 'ultimate-post-kit');
21 }
22
23 $date = strtotime($date_string);
24 if (!$date) {
25 return __('Unknown', 'ultimate-post-kit');
26 }
27
28 $diff = current_time('timestamp') - $date;
29
30 if ($diff < 60) {
31 return __('Just now', 'ultimate-post-kit');
32 } elseif ($diff < 3600) {
33 $minutes = floor($diff / 60);
34 return sprintf(_n('%d minute ago', '%d minutes ago', $minutes, 'ultimate-post-kit'), $minutes);
35 } elseif ($diff < 86400) {
36 $hours = floor($diff / 3600);
37 return sprintf(_n('%d hour ago', '%d hours ago', $hours, 'ultimate-post-kit'), $hours);
38 } elseif ($diff < 2592000) { // 30 days
39 $days = floor($diff / 86400);
40 return sprintf(_n('%d day ago', '%d days ago', $days, 'ultimate-post-kit'), $days);
41 } elseif ($diff < 31536000) { // 1 year
42 $months = floor($diff / 2592000);
43 return sprintf(_n('%d month ago', '%d months ago', $months, 'ultimate-post-kit'), $months);
44 } else {
45 $years = floor($diff / 31536000);
46 return sprintf(_n('%d year ago', '%d years ago', $years, 'ultimate-post-kit'), $years);
47 }
48 }
49 }
50
51 // Helper function for fallback URLs
52 if (!function_exists('get_plugin_fallback_urls_usk')) {
53 function get_plugin_fallback_urls_usk($plugin_slug) {
54 // Handle different plugin slug formats
55 if (strpos($plugin_slug, '/') !== false) {
56 // If it's a file path like 'plugin-name/plugin-name.php', extract directory
57 $plugin_slug_clean = dirname($plugin_slug);
58 } else {
59 // If it's just the plugin directory name, use it directly
60 $plugin_slug_clean = $plugin_slug;
61 }
62
63 // Custom icon URLs for specific plugins that might not be on WordPress.org
64 $custom_icons = [
65 'ar-viewer' => [
66 'https://ps.w.org/ar-viewer/assets/icon-256x256.gif',
67 'https://ps.w.org/ar-viewer/assets/icon-128x128.gif',
68 ],
69 ];
70
71 // Return custom icons if available, otherwise use default WordPress.org URLs
72 if (isset($custom_icons[$plugin_slug_clean])) {
73 return $custom_icons[$plugin_slug_clean];
74 }
75
76 return [
77 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-256x256.png", // Large PNG
78 "https://ps.w.org/{$plugin_slug_clean}/assets/icon-128x128.png", // Medium PNG
79 ];
80 }
81 }
82
83 // Define plugin slugs
84 $plugin_slugs = array(
85 'bdthemes-element-pack-lite',
86 'bdthemes-prime-slider-lite/bdthemes-prime-slider.php',
87 'ultimate-post-kit',
88 'ultimate-store-kit',
89 'zoloblocks',
90 'pixel-gallery',
91 'live-copy-paste',
92 'spin-wheel',
93 'ai-image',
94 'dark-reader',
95 'ar-viewer',
96 'smart-admin-assistant',
97 'website-accessibility',
98 );
99
100 // Get enhanced plugin data using the remote data handler
101 $upk_plugins = Remote_Data_Handler::get_remote_plugins();
102
103 // Check if we have cached data
104 $has_cached_data = !empty($upk_plugins);
105
106 // If no cached data, don't fetch immediately - let JavaScript handle it
107 if (!$has_cached_data) {
108 $upk_plugins = []; // Empty array for initial load
109 }
110 ?>
111
112 <div class="bdt-wizard-step bdt-setup-wizard-integration" data-step="integration">
113 <h2><?php esc_html_e('Add More Firepower', 'ultimate-post-kit'); ?></h2>
114 <p><?php esc_html_e('You can onboard additional powerful plugins to extend your web design capabilities.', 'ultimate-post-kit'); ?></p>
115
116 <div class="progress-bar-container">
117 <div id="plugin-install-progress" class="progress-bar"></div>
118 </div>
119
120 <form method="POST" id="upk-install-plugins">
121 <!-- Loading state - shown during plugin installation -->
122 <div class="upk-loading-state" id="upk-install-loading" style="display: none; text-align: center; padding: 40px;">
123 <div class="upk-loading-dots">
124 <div class="upk-loading-dot"></div>
125 <div class="upk-loading-dot"></div>
126 <div class="upk-loading-dot"></div>
127 </div>
128 <p style="margin-top: 20px;" id="upk-loading-message"><?php esc_html_e('Installing plugins...', 'ultimate-post-kit'); ?></p>
129 </div>
130
131 <!-- Initial loading state - shown while fetching plugin data -->
132 <?php if (!$has_cached_data): ?>
133 <div class="upk-loading-state" id="upk-initial-loading" style="text-align: center; padding: 40px;">
134 <div class="upk-loading-dots">
135 <div class="upk-loading-dot"></div>
136 <div class="upk-loading-dot"></div>
137 <div class="upk-loading-dot"></div>
138 </div>
139 <p style="margin-top: 20px;"><?php esc_html_e('Loading plugin data...', 'ultimate-post-kit'); ?></p>
140 </div>
141 <?php endif; ?>
142
143 <div class="bdt-plugin-list" id="upk-integration-plugin-list">
144 <?php if ($has_cached_data): ?>
145 <?php
146 $predefined = \UltimatePostKit\SetupWizard\Plugin_Integration_Helper::get_predefined_plugins();
147 $recommended_by_slug = [];
148 foreach ($predefined as $key => $config) {
149 $dir = (strpos($key, '/') !== false) ? dirname($key) : $key;
150 $recommended_by_slug[ $dir ] = !empty($config['recommended']);
151 }
152 foreach ($upk_plugins as $slug_key => $plugin) :
153 // Skip own plugin (Ultimate Post Kit) when printing only; data still includes it for other plugins
154 if ($slug_key === 'ultimate-post-kit' ) continue;
155 // Use enhanced status if available, otherwise fall back to old method
156 $plugin_status = $plugin['status'] ?? 'unknown';
157 if ($plugin_status === 'unknown') {
158 // Fallback to old method for compatibility
159 $is_active = is_plugin_active($plugin['slug']);
160 } else {
161 // Use enhanced status
162 $is_active = ($plugin_status === 'active');
163 }
164 $plugin_recommended = !empty($recommended_by_slug[ $slug_key ]);
165 $is_recommended = $plugin_recommended && !$is_active;
166 ?>
167 <label class="plugin-item" data-slug="<?php echo esc_attr($plugin['slug']); ?>">
168 <span class="bdt-flex bdt-flex-middle bdt-flex-between bdt-margin-small-bottom">
169 <span class="bdt-plugin-logo">
170 <?php
171 $logo_url = $plugin['logo'] ?? '';
172 $plugin_name = $plugin['name'] ?? '';
173 $plugin_slug = $plugin['slug'] ?? '';
174
175 if (!empty($logo_url) && filter_var($logo_url, FILTER_VALIDATE_URL)) {
176 // Show the original logo from API
177 echo '<img src="' . esc_url($logo_url) . '" alt="' . esc_attr($plugin_name) . '" onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';">';
178 echo '<div class="default-plugin-icon" style="display:none;">📦</div>';
179 } else {
180 // Generate fallback URLs for WordPress.org
181 $actual_slug = (strpos($plugin_slug, '/') !== false) ? dirname($plugin_slug) : $plugin_slug;
182 $fallback_urls = get_plugin_fallback_urls_usk($actual_slug);
183
184 echo '<img src="' . esc_url($fallback_urls[0]) . '" alt="' . esc_attr($plugin_name) . '" onerror="this.style.display=\'none\'; this.nextElementSibling.style.display=\'flex\';">';
185 echo '<div class="default-plugin-icon" style="display:none;">📦</div>';
186 }
187 ?>
188 </span>
189
190 <div class="bdt-plugin-badge-switch-wrap">
191
192 <?php if ($is_recommended) : ?>
193 <span class="recommended-badge"><?php esc_html_e('Recommended', 'ultimate-post-kit'); ?></span>
194 <?php endif; ?>
195
196 <?php if ($is_active) : ?>
197 <span class="active-badge"><?php esc_html_e('ACTIVE', 'ultimate-post-kit'); ?></span>
198 <?php endif; ?>
199 <?php
200 if (!$is_active) : ?>
201 <label class="switch">
202 <input type="checkbox" class="plugin-slider-checkbox" <?php echo $plugin_recommended ? 'checked' : ''; ?>
203 name="plugins[]<?php echo isset($plugin['slug']) ? wp_kses_post($plugin['slug']) : ''; ?>">
204 <span class="slider round"></span>
205 </label>
206 <?php
207 endif;
208 ?>
209 </div>
210 </span>
211 <div class="bdt-flex bdt-flex-middle">
212 <span class="bdt-plugin-name">
213 <?php echo wp_kses_post($plugin['name']); ?>
214 </span>
215 </div>
216
217 <span class="active-installs">
218 <?php esc_html_e('Active Installs: ', 'ultimate-post-kit');
219 if (isset($plugin['active_installs_count']) && $plugin['active_installs_count'] > 0) {
220 echo ' <span class="installs-count">' . number_format($plugin['active_installs_count']) . '+' . '</span>';
221 } else {
222 echo '<span class="installs-count">Fewer than 10</span>';
223 }
224 ?>
225 </span>
226
227 <?php if (isset($plugin['downloaded_formatted']) && !empty($plugin['downloaded_formatted'])): ?>
228 <span class="downloads"><?php esc_html_e('Downloads: ', 'ultimate-post-kit'); echo wp_kses_post($plugin['downloaded_formatted']); ?></span>
229 <?php endif; ?>
230
231 <div class="rating-section">
232 <div class="wporg-ratings" title="<?php echo esc_attr($plugin['rating'] ?? '0'); ?> out of 5 stars" style="color:var(--wp--preset--color--pomegrade-1, #e26f56);">
233 <?php
234 $rating = floatval($plugin['rating'] ?? 0);
235 $full_stars = floor($rating);
236 $has_half_star = ($rating - $full_stars) >= 0.5;
237 $empty_stars = 5 - $full_stars - ($has_half_star ? 1 : 0);
238
239 // Full stars
240 for ($i = 0; $i < $full_stars; $i++) {
241 echo '<span class="dashicons dashicons-star-filled"></span>';
242 }
243
244 // Half star
245 if ($has_half_star) {
246 echo '<span class="dashicons dashicons-star-half"></span>';
247 }
248
249 // Empty stars
250 for ($i = 0; $i < $empty_stars; $i++) {
251 echo '<span class="dashicons dashicons-star-empty"></span>';
252 }
253 ?>
254 </div>
255 <span class="rating-text">
256 <?php echo esc_html($plugin['rating'] ?? '0'); ?> out of 5 stars.
257 <?php if (isset($plugin['num_ratings']) && $plugin['num_ratings'] > 0): ?>
258 <span class="rating-count">(<?php echo number_format($plugin['num_ratings']); ?> ratings)</span>
259 <?php endif; ?>
260 </span>
261 </div>
262
263 <?php
264 // Use the enhanced last_updated_formatted if available, otherwise fall back to formatting
265 if (isset($plugin['last_updated_formatted']) && !empty($plugin['last_updated_formatted'])): ?>
266 <span class="last-updated"><?php esc_html_e('Last Updated: ', 'ultimate-post-kit'); echo esc_html($plugin['last_updated_formatted']); ?></span>
267 <?php elseif (isset($plugin['last_updated']) && !empty($plugin['last_updated'])): ?>
268 <span class="last-updated"><?php esc_html_e('Last Updated: ', 'ultimate-post-kit'); echo esc_html(format_last_updated_usk($plugin['last_updated'])); ?></span>
269 <?php endif; ?>
270
271 </label>
272 <?php
273 endforeach; ?>
274 <?php endif; ?>
275 </div>
276
277 <div class="wizard-navigation bdt-margin-top">
278 <button class="bdt-button bdt-button-primary d-none" type="submit" id="upk-install-plugins-btn">
279 <?php esc_html_e('Install and Continue', 'ultimate-post-kit'); ?>
280 </button>
281 <div class="bdt-close-button bdt-margin-left bdt-wizard-next" data-step="finish"><?php esc_html_e('Skip', 'ultimate-post-kit'); ?></div>
282 </div>
283 </form>
284
285 <div class="bdt-wizard-navigation">
286 <button class="bdt-button bdt-button-secondary bdt-wizard-prev" data-step="features">
287 <span><i class="dashicons dashicons-arrow-left-alt"></i></span>
288 <?php esc_html_e('Previous Step', 'ultimate-post-kit'); ?>
289 </button>
290 </div>
291 </div>
292
293 <style>
294 .upk-loading-dots {
295 display: flex;
296 justify-content: center;
297 gap: 8px;
298 margin: 20px 0;
299 }
300
301 .upk-loading-dot {
302 width: 12px;
303 height: 12px;
304 background-color: #0073aa;
305 border-radius: 50%;
306 animation: upk-wave 1.4s ease-in-out infinite both;
307 }
308
309 .upk-loading-dot:nth-child(1) {
310 animation-delay: -0.32s;
311 }
312
313 .upk-loading-dot:nth-child(2) {
314 animation-delay: -0.16s;
315 }
316
317 .upk-loading-dot:nth-child(3) {
318 animation-delay: 0s;
319 }
320
321 @keyframes upk-wave {
322 0%, 80%, 100% {
323 transform: scale(0.8);
324 opacity: 0.5;
325 }
326 40% {
327 transform: scale(1.2);
328 opacity: 1;
329 }
330 }
331 </style>
332
333 <script>
334 jQuery(document).ready(function($) {
335 let integrationDataLoaded = false;
336
337 // Function to load integration data
338 function loadIntegrationData() {
339 if (integrationDataLoaded) return;
340
341 const $pluginList = $('#upk-integration-plugin-list');
342 const $initialLoading = $('#upk-initial-loading');
343
344 // Don't add another loading state if initial loading is visible
345 // Just keep the existing one
346
347 // Make AJAX request to get plugin data
348 $.ajax({
349 url: ajaxurl,
350 type: 'POST',
351 data: {
352 action: 'upk_get_plugins',
353 nonce: '<?php echo wp_create_nonce('upk_get_plugins_nonce'); ?>'
354 },
355 success: function(response) {
356 if (response.success && response.data.plugins) {
357 // Hide the initial loading div
358 $initialLoading.hide();
359 renderPluginList(response.data.plugins);
360 integrationDataLoaded = true;
361 } else {
362 showError('Unable to load plugin data.');
363 }
364 },
365 error: function() {
366 showError('Network error occurred while loading plugin data.');
367 }
368 });
369 }
370
371 // Function to render plugin list
372 function renderPluginList(plugins) {
373 const $pluginList = $('#upk-integration-plugin-list');
374 let html = '';
375
376 if (plugins.length === 0) {
377 html = '<div class="upk-no-plugins" style="text-align: center; padding: 40px;"><p>No plugins found.</p></div>';
378 } else {
379 plugins.forEach(function(plugin) {
380 // Skip own plugin (Ultimate Post Kit) when printing only; data still includes it for other plugins
381 if (plugin.slug === 'ultimate-post-kit') return;
382 const isActive = plugin.status === 'active';
383 const isRecommended = plugin.recommended && !isActive;
384
385 html += `
386 <label class="plugin-item" data-slug="${plugin.slug}">
387 <span class="bdt-flex bdt-flex-middle bdt-flex-between bdt-margin-small-bottom">
388 <span class="bdt-plugin-logo">
389 ${generatePluginLogo(plugin)}
390 </span>
391 <div class="bdt-plugin-badge-switch-wrap">
392 ${isRecommended ? '<span class="recommended-badge">Recommended</span>' : ''}
393 ${isActive ? '<span class="active-badge">ACTIVE</span>' : ''}
394 ${!isActive ? `
395 <label class="switch">
396 <input type="checkbox" class="plugin-slider-checkbox" ${plugin.recommended ? 'checked' : ''} name="plugins[]${plugin.slug}">
397 <span class="slider round"></span>
398 </label>
399 ` : ''}
400 </div>
401 </span>
402 <div class="bdt-flex bdt-flex-middle">
403 <span class="bdt-plugin-name">${plugin.name}</span>
404 </div>
405 <span class="active-installs">
406 Active Installs:
407 <span class="installs-count">${plugin.active_installs_count > 0 ? plugin.active_installs_count.toLocaleString() + '+' : 'Fewer than 10'}</span>
408 </span>
409 ${plugin.downloaded_formatted ? `<span class="downloads">Downloads: ${plugin.downloaded_formatted}</span>` : ''}
410 <div class="rating-section">
411 <div class="wporg-ratings" title="${plugin.rating} out of 5 stars" style="color:var(--wp--preset--color--pomegrade-1, #e26f56);">
412 ${generateStarRating(plugin.rating)}
413 </div>
414 <span class="rating-text">
415 ${plugin.rating} out of 5 stars.
416 ${plugin.num_ratings > 0 ? `<span class="rating-count">(${plugin.num_ratings.toLocaleString()} ratings)</span>` : ''}
417 </span>
418 </div>
419 ${plugin.last_updated_formatted ? `<span class="last-updated">Last Updated: ${plugin.last_updated_formatted}</span>` : ''}
420 </label>
421 `;
422 });
423 }
424
425 $pluginList.html(html);
426 }
427
428 // Helper function to generate plugin logo
429 function generatePluginLogo(plugin) {
430 if (plugin.logo && plugin.logo.match(/^https?:\/\//)) {
431 return `<img src="${plugin.logo}" alt="${plugin.name}" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
432 <div class="default-plugin-icon" style="display:none;">📦</div>`;
433 } else {
434 const slug = plugin.slug.includes('/') ? plugin.slug.split('/')[0] : plugin.slug;
435 return `<img src="https://ps.w.org/${slug}/assets/icon-256x256.png" alt="${plugin.name}" onerror="this.style.display='none'; this.nextElementSibling.style.display='flex';">
436 <div class="default-plugin-icon" style="display:none;">📦</div>`;
437 }
438 }
439
440 // Helper function to generate star rating
441 function generateStarRating(rating) {
442 const fullStars = Math.floor(rating);
443 const hasHalfStar = (rating - fullStars) >= 0.5;
444 const emptyStars = 5 - fullStars - (hasHalfStar ? 1 : 0);
445
446 let html = '';
447 for (let i = 0; i < fullStars; i++) {
448 html += '<span class="dashicons dashicons-star-filled"></span>';
449 }
450 if (hasHalfStar) {
451 html += '<span class="dashicons dashicons-star-half"></span>';
452 }
453 for (let i = 0; i < emptyStars; i++) {
454 html += '<span class="dashicons dashicons-star-empty"></span>';
455 }
456 return html;
457 }
458
459 // Function to show error
460 function showError(message) {
461 const $pluginList = $('#upk-integration-plugin-list');
462 const $initialLoading = $('#upk-initial-loading');
463
464 // Hide initial loading
465 $initialLoading.hide();
466
467 // Show error in plugin list
468 $pluginList.html(`
469 <div class="upk-error-state" style="text-align: center; padding: 40px;">
470 <p style="color: #d63638;">${message}</p>
471 <button type="button" class="bdt-button bdt-button-secondary" onclick="location.reload()">Retry</button>
472 </div>
473 `);
474 }
475
476 // Detect when integration tab becomes active
477 function observeIntegrationTab() {
478 // Check if integration step is currently visible
479 const $integrationStep = $('.bdt-setup-wizard-integration');
480
481 if ($integrationStep.length) {
482 // Create a MutationObserver to detect when the integration step becomes visible
483 const observer = new MutationObserver(function(mutations) {
484 mutations.forEach(function(mutation) {
485 if (mutation.type === 'attributes' && mutation.attributeName === 'class') {
486 const $target = $(mutation.target);
487 if ($target.hasClass('bdt-setup-wizard-integration') && $target.is(':visible')) {
488 loadIntegrationData();
489 observer.disconnect(); // Stop observing after first load
490 }
491 }
492 });
493 });
494
495 // Start observing
496 observer.observe($integrationStep[0], {
497 attributes: true,
498 attributeFilter: ['class']
499 });
500
501 // Also check immediately if it's already visible
502 if ($integrationStep.is(':visible') && !integrationDataLoaded) {
503 loadIntegrationData();
504 }
505 }
506 }
507
508 // Initialize tab observation
509 observeIntegrationTab();
510
511 // Fallback: Also try to detect tab clicks (for different wizard implementations)
512 $(document).on('click', '[data-step="integration"], .bdt-wizard-step[data-step="integration"]', function() {
513 if (!integrationDataLoaded) {
514 setTimeout(loadIntegrationData, 100);
515 }
516 });
517 });
518 </script>
519