Changeset 357072
- Timestamp:
- 11/04/2026 05:35:33 AM (8 hours ago)
- Location:
- portfoliox-dark/1.0.14
- Files:
-
- 10 edited
- 1 copied
-
. (copied) (copied from portfoliox-dark/1.0.13 )
-
actions/header-actions.php (modified) (2 diffs)
-
assets/css/main.css (modified) (1 diff)
-
functions.php (modified) (1 diff)
-
inc/about/about.php (modified) (4 diffs)
-
inc/recommended-plugins.php (modified) (5 diffs)
-
libs/magical-plugin-activation/assets/css/admin-plugins.css (modified) (34 diffs)
-
libs/magical-plugin-activation/assets/js/admin-plugins.js (modified) (21 diffs)
-
libs/magical-plugin-activation/class-magical-plugin-activation.php (modified) (29 diffs)
-
readme.txt (modified) (2 diffs)
-
style.css (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
portfoliox-dark/1.0.14/actions/header-actions.php
r166704 r357072 17 17 'menu_id' => 'portfoliox-menu', 18 18 'menu_class' => 'portfoliox-menu', 19 'fallback_cb' => 'portfoliox_dark_menu_fallback', 19 20 )); 20 21 ?> … … 125 126 'menu_id' => 'wsm-menu', 126 127 'menu_class' => 'wsm-menu', 127 )); 128 'fallback_cb' => 'portfoliox_dark_menu_fallback', 129 )); 128 130 ?> 129 131 </nav><!-- #site-navigation --> -
portfoliox-dark/1.0.14/assets/css/main.css
r254744 r357072 969 969 } 970 970 } 971 972 /* ========================================================================== 973 Header Logo & Navigation Spacing Rule (Collision Prevention) 974 Ensures at least 30-40px gap between logo and menu so they never touch. 975 ========================================================================== */ 976 @media (min-width: 992px) { 977 .menubar-content, 978 .pxm-style1 .navigation .d-flex, 979 .navigation .d-flex, 980 .site-header .d-flex, 981 .header-main-wrapper .d-flex { 982 gap: 35px; 983 } 984 985 .head-logo-sec, 986 .pxms1-logo, 987 .site-branding.brand-logo, 988 .site-branding.brand-text, 989 .menubar-content .head-logo-sec, 990 .header-logo-wrap { 991 flex-shrink: 0; 992 margin-right: 30px; 993 } 994 995 .main-navigation, 996 .pxms1-menu, 997 .real-estate-pack-container.menu-inner { 998 min-width: 0; 999 } 1000 } -
portfoliox-dark/1.0.14/functions.php
r341891 r357072 340 340 341 341 // Recommended plugins 342 require get_template_directory() . '/inc/recommended-plugins.php'; 342 require_once get_template_directory() . '/inc/recommended-plugins.php'; 343 344 345 /** 346 * Fallback menu for PortfolioX Dark 347 * Limits fallback menu display to a maximum of 7 items (Home + up to 6 published pages) 348 * to prevent header layout break when no custom menu is assigned. 349 * 350 * @param array|object $args Arguments passed from wp_nav_menu. 351 */ 352 function portfoliox_dark_menu_fallback($args = array()) 353 { 354 $menu_id = is_array($args) && isset($args['menu_id']) ? $args['menu_id'] : (is_object($args) && isset($args->menu_id) ? $args->menu_id : 'portfoliox-dark-menu'); 355 $menu_class = is_array($args) && isset($args['menu_class']) ? $args['menu_class'] : (is_object($args) && isset($args->menu_class) ? $args->menu_class : 'portfoliox-dark-menu'); 356 357 $menu = '<ul id="' . esc_attr($menu_id) . '" class="' . esc_attr($menu_class) . '">'; 358 359 // 1. Add Home link as first item 360 $home_current = (is_front_page() || is_home()) ? ' current-menu-item' : ''; 361 $menu .= '<li class="menu-item menu-item-home' . $home_current . '"><a href="' . esc_url(home_url('/')) . '">' . esc_html__('Home', 'portfoliox-dark') . '</a></li>'; 362 363 // 2. Query up to 6 published pages, excluding static front page if configured 364 $exclude_ids = array(); 365 $front_page_id = (int) get_option('page_on_front'); 366 if ($front_page_id > 0) { 367 $exclude_ids[] = $front_page_id; 368 } 369 370 $pages = get_pages(array( 371 'number' => 6, 372 'sort_column' => 'menu_order, post_title', 373 'sort_order' => 'ASC', 374 'post_status' => 'publish', 375 'exclude' => $exclude_ids, 376 )); 377 378 if (!empty($pages)) { 379 foreach ($pages as $page) { 380 $page_current = (is_page($page->ID)) ? ' current-menu-item' : ''; 381 $menu .= '<li class="menu-item menu-item-type-post_type menu-item-object-page' . $page_current . '"><a href="' . esc_url(get_permalink($page->ID)) . '">' . esc_html($page->post_title) . '</a></li>'; 382 } 383 } 384 385 $menu .= '</ul>'; 386 387 echo $menu; 388 } -
portfoliox-dark/1.0.14/inc/about/about.php
r341891 r357072 302 302 add_action('after_setup_theme', 'portfoliox_dark_about_setup'); 303 303 304 /** 305 * Pro notice text (Modern SaaS Card Design) 306 */ 304 307 function portfoliox_dark_pnotice_output() 305 308 { 306 309 $current_theme = wp_get_theme(); 307 310 $current_theme_name = $current_theme->get('Name'); 311 $pro_link = esc_url('https://wpthemespace.com/product/portfoliox-pro/?add-to-cart=5925'); 308 312 $demo_link = esc_url('https://wpthemespace.com/product/portfoliox-pro/'); 309 $pro_link = esc_url('https://wpthemespace.com/product/portfoliox-pro/?add-to-cart=5925');310 313 ?> 311 314 <style> 312 .pxd-notice-wrap{background:#fff;border:1px solid #c3e1f7;border-radius:6px;padding:16px 20px;box-shadow:0 1px 3px rgba(0,0,0,.08),0 1px 2px rgba(0,0,0,.06);display:flex;flex-direction:column;gap:10px;width:100%;box-sizing:border-box} 313 .mgadin-notice .pxd-notice-wrap{margin:0 -26px;width:calc(100% + 52px);border-radius:0;border-left:none;border-right:none;padding:16px 26px} 314 .pxd-notice-title{font-size:17px;font-weight:700;color:#1d2327;line-height:1.3;margin:0;display:flex;align-items:center;gap:6px} 315 .pxd-notice-title span.pxd-star{font-size:18px} 316 .pxd-notice-desc{font-size:13px;line-height:1.55;color:#50575e;margin:0} 317 .pxd-notice-desc strong{color:#2271b1} 318 .pxd-notice-badges{display:flex;flex-wrap:wrap;gap:6px;margin-top:2px} 319 .pxd-badge{display:inline-flex;align-items:center;gap:4px;background:#f0f6fc;color:#2271b1;border:1px solid #c3e1f7;border-radius:3px;padding:3px 8px;font-size:12px;font-weight:500;line-height:1.4;white-space:nowrap} 320 .pxd-badge--highlight{background:#dff0d8;border-color:#b4d8a0;color:#1e7a1e} 321 .pxd-notice-cta{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-top:2px} 322 .pxd-btn{display:inline-flex;align-items:center;gap:5px;border-radius:4px;font-size:13px;font-weight:600;text-decoration:none;cursor:pointer;border:none;line-height:1.4;transition:background .15s,border-color .15s,box-shadow .15s} 323 .pxd-btn--primary{background:#2271b1!important;border:1px solid #135e96;color:#fff!important;padding:5px 14px} 324 .pxd-btn--primary:hover{background:#135e96!important;border-color:#0e4a7a;color:#fff!important} 325 .pxd-btn--primary:focus{box-shadow:0 0 0 1px #fff,0 0 0 3px #2271b1;outline:none} 326 .pxd-btn--primary:visited{color:#fff!important} 327 .pxd-btn--secondary{background:#fff;border:1px solid #8c8f94;color:#2271b1;padding:5px 14px} 328 .pxd-btn--secondary:hover{background:#f6f7f7;border-color:#8c8f94;color:#135e96} 329 .pxd-btn--link{background:none;border:none;color:#8c8f94;padding:5px 8px;text-decoration:underline} 330 .pxd-btn--link:hover{color:#d63638} 331 .pxd-lifetime{background:linear-gradient(135deg,#dff0d8 0%,#f0f6fc 100%);border:1px solid #b4d8a0;border-radius:4px;padding:6px 12px;display:flex;align-items:center;gap:6px;margin-top:2px} 332 .pxd-lifetime-text{font-size:13px;font-weight:700;color:#1e7a1e;line-height:1.3} 333 .pxd-lifetime-sub{font-size:12px;color:#50575e;font-weight:400} 315 @keyframes RedGlow { 316 0% { box-shadow: 0 4px 20px rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.3); } 317 50% { box-shadow: 0 6px 28px rgba(239, 68, 68, 0.35); border-color: rgba(239, 68, 68, 0.65); } 318 100% { box-shadow: 0 4px 20px rgba(239, 68, 68, 0.15); border-color: rgba(239, 68, 68, 0.3); } 319 } 320 @keyframes BtnPulse { 321 0% { transform: scale(1); box-shadow: 0 4px 12px rgba(220, 38, 38, 0.35); } 322 50% { transform: scale(1.02); box-shadow: 0 6px 18px rgba(220, 38, 38, 0.55); } 323 100% { transform: scale(1); box-shadow: 0 4px 12px rgba(220, 38, 38, 0.35); } 324 } 325 @keyframes TagPulse { 326 0% { transform: scale(1); } 327 50% { transform: scale(1.04); } 328 100% { transform: scale(1); } 329 } 330 .portfoliox-dark-pro-notice-card { 331 background: #ffffff !important; 332 border: 1px solid rgba(239, 68, 68, 0.35) !important; 333 border-left: 5px solid #ef4444 !important; 334 border-radius: 12px !important; 335 padding: 24px 28px !important; 336 margin: 20px 0 !important; 337 box-shadow: 0 4px 20px rgba(239, 68, 68, 0.12) !important; 338 animation: RedGlow 3.5s ease-in-out infinite !important; 339 font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif !important; 340 box-sizing: border-box !important; 341 position: relative !important; 342 } 343 .portfoliox-dark-pro-wrapper { 344 display: flex !important; 345 align-items: center !important; 346 justify-content: space-between !important; 347 gap: 32px !important; 348 flex-wrap: wrap !important; 349 } 350 .portfoliox-dark-pro-left { 351 flex: 1 1 560px !important; 352 } 353 .portfoliox-dark-pro-header { 354 display: flex !important; 355 align-items: center !important; 356 gap: 10px !important; 357 margin-bottom: 10px !important; 358 flex-wrap: wrap !important; 359 } 360 .portfoliox-dark-tag-pro { 361 background: linear-gradient(135deg, #ef4444 0%, #b91c1c 100%) !important; 362 color: #ffffff !important; 363 font-size: 11px !important; 364 font-weight: 800 !important; 365 letter-spacing: 1px !important; 366 padding: 3px 10px !important; 367 border-radius: 6px !important; 368 text-transform: uppercase !important; 369 } 370 .portfoliox-dark-tag-deal { 371 background: #fef2f2 !important; 372 color: #b91c1c !important; 373 border: 1px solid #fecaca !important; 374 font-size: 12px !important; 375 font-weight: 700 !important; 376 padding: 3px 10px !important; 377 border-radius: 6px !important; 378 animation: TagPulse 2.5s ease-in-out infinite !important; 379 display: inline-flex !important; 380 align-items: center !important; 381 gap: 5px !important; 382 } 383 .portfoliox-dark-pro-headline { 384 font-size: 20px !important; 385 font-weight: 800 !important; 386 color: #111827 !important; 387 margin: 0 0 10px 0 !important; 388 line-height: 1.35 !important; 389 } 390 .portfoliox-dark-pro-desc { 391 font-size: 13.5px !important; 392 line-height: 1.6 !important; 393 color: #4b5563 !important; 394 margin: 0 0 16px 0 !important; 395 } 396 .portfoliox-dark-pro-badges { 397 display: flex !important; 398 flex-wrap: wrap !important; 399 gap: 8px !important; 400 } 401 .portfoliox-dark-badge-item { 402 background: #f3f4f6 !important; 403 color: #374151 !important; 404 border: 1px solid #e5e7eb !important; 405 font-size: 11.5px !important; 406 font-weight: 600 !important; 407 padding: 4px 10px !important; 408 border-radius: 6px !important; 409 display: inline-flex !important; 410 align-items: center !important; 411 gap: 5px !important; 412 } 413 .portfoliox-dark-badge-item span { 414 color: #10b981 !important; 415 font-weight: bold !important; 416 } 417 .portfoliox-dark-pro-right { 418 display: flex !important; 419 flex-direction: column !important; 420 align-items: flex-end !important; 421 gap: 10px !important; 422 } 423 .portfoliox-dark-btn-cta { 424 background: linear-gradient(135deg, #ef4444 0%, #dc2626 100%) !important; 425 color: #ffffff !important; 426 font-size: 14px !important; 427 font-weight: 700 !important; 428 padding: 12px 24px !important; 429 border-radius: 8px !important; 430 text-decoration: none !important; 431 display: inline-flex !important; 432 align-items: center !important; 433 gap: 8px !important; 434 box-shadow: 0 4px 12px rgba(220, 38, 38, 0.35) !important; 435 animation: BtnPulse 2.8s ease-in-out infinite !important; 436 transition: all 0.2s ease !important; 437 border: none !important; 438 } 439 .portfoliox-dark-btn-cta:hover { 440 background: linear-gradient(135deg, #dc2626 0%, #b91c1c 100%) !important; 441 color: #ffffff !important; 442 transform: translateY(-2px) !important; 443 box-shadow: 0 6px 18px rgba(220, 38, 38, 0.45) !important; 444 } 445 .portfoliox-dark-btn-demo { 446 background: #ffffff !important; 447 color: #4b5563 !important; 448 font-size: 13px !important; 449 font-weight: 600 !important; 450 padding: 8px 18px !important; 451 border-radius: 8px !important; 452 text-decoration: none !important; 453 border: 1px solid #d1d5db !important; 454 display: inline-flex !important; 455 align-items: center !important; 456 gap: 6px !important; 457 transition: all 0.2s ease !important; 458 } 459 .portfoliox-dark-btn-demo:hover { 460 background: #f9fafb !important; 461 color: #111827 !important; 462 border-color: #9ca3af !important; 463 } 464 .portfoliox-dark-btn-dismiss { 465 background: transparent !important; 466 border: none !important; 467 color: #9ca3af !important; 468 font-size: 12px !important; 469 cursor: pointer !important; 470 padding: 4px 6px !important; 471 text-decoration: underline !important; 472 transition: color 0.2s ease !important; 473 } 474 .portfoliox-dark-btn-dismiss:hover { 475 color: #4b5563 !important; 476 } 477 @media (max-width: 782px) { 478 .portfoliox-dark-pro-wrapper { 479 flex-direction: column !important; 480 align-items: flex-start !important; 481 } 482 .portfoliox-dark-pro-right { 483 align-items: flex-start !important; 484 width: 100% !important; 485 } 486 .portfoliox-dark-btn-cta { 487 width: 100% !important; 488 justify-content: center !important; 489 } 490 } 334 491 </style> 335 492 336 <div class="pxd-notice-wrap"> 337 <div class="pxd-notice-title"> 338 <span class="pxd-star">🌟</span> 339 <?php printf(esc_html__('Welcome to %s Experience!', 'portfoliox-dark'), esc_html($current_theme_name)); ?> 340 </div> 341 342 <div class="pxd-notice-desc"> 343 <?php esc_html_e('Stop blending in — start landing clients.', 'portfoliox-dark'); ?> 344 <?php esc_html_e('Here is what PRO delivers to your portfolio:', 'portfoliox-dark'); ?> 345 </div> 346 347 <div class="pxd-notice-badges"> 348 <span class="pxd-badge">✨ One-Click Demo Import</span> 349 <span class="pxd-badge">📈 Conversion-focused layouts</span> 350 <span class="pxd-badge">🧩 Advanced Portfolio Filters</span> 351 <span class="pxd-badge">🔥 Animated Home Text</span> 352 <span class="pxd-badge">💬 Dedicated Premium Support</span> 353 </div> 354 355 <div class="pxd-lifetime"> 356 <span style="font-size:16px">🎯</span> 357 <div> 358 <div class="pxd-lifetime-text">Buy Once, Get Lifetime Access</div> 359 <div class="pxd-lifetime-sub">No recurring fees — one payment, yours forever.</div> 493 <div class="portfoliox-dark-pro-notice-card"> 494 <div class="portfoliox-dark-pro-wrapper"> 495 <div class="portfoliox-dark-pro-left"> 496 <div class="portfoliox-dark-pro-header"> 497 <span class="portfoliox-dark-tag-pro"><?php esc_html_e('PRO UPGRADE', 'portfoliox-dark'); ?></span> 498 <span class="portfoliox-dark-tag-deal">⚡ <?php esc_html_e('Special Offer: Now Only $21 - Price Dropped!', 'portfoliox-dark'); ?></span> 499 </div> 500 <h2 class="portfoliox-dark-pro-headline"> 501 <?php printf(esc_html__('Supercharge Your Dark Mode Portfolio & Agency Website with %s Pro!', 'portfoliox-dark'), esc_html($current_theme_name)); ?> 502 </h2> 503 <p class="portfoliox-dark-pro-desc"> 504 <?php esc_html_e('Unlock stunning dark mode portfolio showcases, sleek project sliders, video & audio portfolio items, lightning-fast Core Web Vitals speed, and 24/7 VIP priority support.', 'portfoliox-dark'); ?> 505 </p> 506 <div class="portfoliox-dark-pro-badges"> 507 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('1-Click Demo Import', 'portfoliox-dark'); ?></div> 508 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('Sleek Dark Portfolio Grid', 'portfoliox-dark'); ?></div> 509 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('Filterable Project Layouts', 'portfoliox-dark'); ?></div> 510 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('Unlimited Colors & Layouts', 'portfoliox-dark'); ?></div> 511 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('Remove Footer Credit', 'portfoliox-dark'); ?></div> 512 <div class="portfoliox-dark-badge-item"><span>✓</span> <?php esc_html_e('24/7 VIP Priority Support', 'portfoliox-dark'); ?></div> 513 </div> 360 514 </div> 361 </div> 362 363 <div class="pxd-notice-cta"> 364 <a href="<?php echo $pro_link; ?>" target="_blank" class="pxd-btn pxd-btn--primary"> 365 🚀 <?php esc_html_e('Upgrade to PRO', 'portfoliox-dark'); ?> 366 </a> 367 <a href="<?php echo $demo_link; ?>" target="_blank" class="pxd-btn pxd-btn--secondary"> 368 <?php esc_html_e('👀 View Demo', 'portfoliox-dark'); ?> 369 </a> 370 <button class="pxd-btn pxd-btn--link btnend"> 371 <?php esc_html_e('Dismiss', 'portfoliox-dark'); ?> 372 </button> 515 <div class="portfoliox-dark-pro-right"> 516 <a href="<?php echo esc_url($pro_link); ?>" target="_blank" class="portfoliox-dark-btn-cta"> 517 🚀 <?php esc_html_e('Upgrade to Pro for Only $21', 'portfoliox-dark'); ?> 518 </a> 519 <a href="<?php echo esc_url($demo_link); ?>" target="_blank" class="portfoliox-dark-btn-demo"> 520 👀 <?php esc_html_e('Live Demo & Features', 'portfoliox-dark'); ?> 521 </a> 522 <button class="portfoliox-dark-btn-dismiss btnend"><?php esc_html_e('Maybe Later', 'portfoliox-dark'); ?></button> 523 </div> 373 524 </div> 374 525 </div> … … 376 527 } 377 528 378 379 380 //Admin notice 529 // Admin notice display 381 530 function portfoliox_dark_new_optins_texts() 382 531 { 383 global $pagenow; 384 $pxdinfo_date = get_option('portfoliox_dark_info_text1'); 385 if (!empty($pxdinfo_date) || $pagenow == 'themes.php') { 386 $clickhide = round((time() - strtotime($pxdinfo_date)) / 24 / 60 / 60); 387 if ($clickhide < 27) { 532 $hide_date = get_option('portfoliox_dark_pro_textinfo_v114'); 533 if (!empty($hide_date)) { 534 $clickhide = round((time() - strtotime($hide_date)) / 24 / 60 / 60); 535 if ($clickhide < 25) { 388 536 return; 389 537 } … … 391 539 392 540 ?> 393 <div class="mgadin-notice notice notice-success mgadin-theme-dashboard mgadin-theme-dashboard-notice mge is-dismissible meis-dismissible" >541 <div class="mgadin-notice notice notice-success mgadin-theme-dashboard mgadin-theme-dashboard-notice mge is-dismissible meis-dismissible" style="padding:0; border:none; background:transparent;"> 394 542 <?php portfoliox_dark_pnotice_output(); ?> 395 543 </div> 396 544 <?php 397 398 545 } 399 546 add_action('admin_notices', 'portfoliox_dark_new_optins_texts'); … … 401 548 function portfoliox_dark_new_optins_texts_init() 402 549 { 403 $install_date = get_option('portfoliox_dark_install_date'); 550 if (isset($_GET['xbnotice']) && $_GET['xbnotice'] == 1) { 551 update_option('portfoliox_dark_pro_textinfo_v114', current_time('mysql')); 552 } 553 $install_date = get_option('portfoliox_dark_theme_install_date'); 404 554 if (empty($install_date)) { 405 update_option('portfoliox_dark_install_date', current_time('mysql')); 406 } 407 408 if (isset($_GET['xbnotice']) && $_GET['xbnotice'] == 1) { 409 update_option('portfoliox_dark_info_text1', current_time('mysql')); 555 update_option('portfoliox_dark_theme_install_date', current_time('mysql')); 410 556 } 411 557 } -
portfoliox-dark/1.0.14/inc/recommended-plugins.php
r341891 r357072 2 2 /** 3 3 * Recommended plugins for PortfolioX Dark 4 *5 * Core plugins (Posts Display, Magical Addons, Easy Share, Click To Top,6 * Password Protected, Elementor, Magical Blocks) come from the Magical Plugin7 * Activation library defaults. This file adds theme-specific extras.8 4 */ 9 5 10 6 function portfoliox_dark_magical_plugins($plugins) { 11 7 $theme_plugins = array( 8 'magical-posts-display' => array( 9 'name' => __('Posts Display', 'portfoliox-dark'), 10 'slug' => 'magical-posts-display', 11 'file' => 'magical-posts-display/magical-posts-display.php', 12 'description' => __('Display posts in beautiful layouts.', 'portfoliox-dark'), 13 'category' => 'Content Display', 14 'essential' => false, 15 'featured' => true, 16 'is_local' => false, 17 ), 18 'magical-addons-for-elementor' => array( 19 'name' => __('Magical Addons', 'portfoliox-dark'), 20 'slug' => 'magical-addons-for-elementor', 21 'file' => 'magical-addons-for-elementor/magical-addons-for-elementor.php', 22 'description' => __('Premium quality addons for Elementor page builder.', 'portfoliox-dark'), 23 'category' => 'Page Builder', 24 'essential' => false, 25 'featured' => true, 26 'is_local' => false, 27 ), 28 'magical-blocks' => array( 29 'name' => __('Magical Blocks', 'portfoliox-dark'), 30 'slug' => 'magical-blocks', 31 'file' => 'magical-blocks/magical-blocks.php', 32 'description' => __('Premium quality blocks for WordPress gutenberg builder.', 'portfoliox-dark'), 33 'category' => 'Page Builder', 34 'essential' => false, 35 'featured' => true, 36 'is_local' => false, 37 ), 12 38 'gallery-box' => array( 13 39 'name' => __('Gallery Box', 'portfoliox-dark'), … … 16 42 'description' => __('Beautiful gallery and lightbox plugin.', 'portfoliox-dark'), 17 43 'category' => 'Media', 18 ' required'=> false,44 'essential' => false, 19 45 'featured' => true, 20 46 'is_local' => false, 21 47 ), 22 'ai-marketing-expert' => array( 23 'name' => __('AI Marketing Expert', 'portfoliox-dark'), 24 'slug' => 'ai-marketing-expert', 25 'file' => 'ai-marketing-expert/ai-marketing-expert.php', 26 'description' => __('AI-powered marketing suite with email marketing, content generator, SEO analyzer, social media, and chatbot.', 'portfoliox-dark'), 27 'category' => 'Marketing', 28 'required' => false, 29 'timed_auto' => true, 48 'click-to-top' => array( 49 'name' => __('Click To Top', 'portfoliox-dark'), 50 'slug' => 'click-to-top', 51 'file' => 'click-to-top/click-to-top.php', 52 'description' => __('One-click scroll to top button.', 'portfoliox-dark'), 53 'category' => 'Utility', 54 'essential' => false, 30 55 'featured' => true, 31 56 'is_local' => false, … … 40 65 'description' => __('Display WooCommerce products in beautiful layouts.', 'portfoliox-dark'), 41 66 'category' => 'eCommerce', 42 ' required'=> false,67 'essential' => false, 43 68 'featured' => true, 44 69 'is_local' => false, … … 53 78 * AI Marketing Expert success notice 54 79 */ 80 if (!function_exists('portfoliox_dark_ai_marketing_notice')) : 55 81 function portfoliox_dark_ai_marketing_notice() { 56 82 if (!is_plugin_active('ai-marketing-expert/ai-marketing-expert.php')) { … … 91 117 } 92 118 add_action('admin_notices', 'portfoliox_dark_ai_marketing_notice'); 119 endif; -
portfoliox-dark/1.0.14/libs/magical-plugin-activation/assets/css/admin-plugins.css
r306496 r357072 1 /* Shop Toolkit Pro Plugin Recommendations Admin Styles */ 2 1 /* Magical Plugin Activation Admin Styles */ 3 2 .magical-plugin-activation-plugins { 4 3 padding: 20px 0; 5 4 max-width: 1400px; 6 5 } 7 8 6 .magical-plugin-activation-plugins .description { 9 7 font-size: 14px; … … 16 14 border-radius: 4px; 17 15 } 18 19 /* Filter Tabs */20 16 .plugin-filter-tabs { 21 17 margin-bottom: 30px; … … 29 25 box-shadow: 0 1px 3px rgba(0,0,0,0.1); 30 26 } 31 32 27 .filter-tab { 33 28 background: none; … … 43 38 position: relative; 44 39 } 45 46 40 .filter-tab:hover { 47 41 color: #0073aa; … … 49 43 border-bottom-color: #0073aa; 50 44 } 51 52 45 .filter-tab.active { 53 46 color: #0073aa; … … 57 50 box-shadow: 0 -2px 5px rgba(0,0,0,0.1); 58 51 } 59 60 /* Plugins Grid */61 52 .plugins-grid { 62 53 display: grid; … … 69 60 box-shadow: 0 2px 8px rgba(0,0,0,0.1); 70 61 } 71 72 62 .plugin-card { 73 63 background: #fff; … … 81 71 width: 100%; 82 72 } 83 84 73 .plugin-card:hover { 85 74 border-color: #0073aa; … … 87 76 transform: translateY(-4px); 88 77 } 89 90 78 .plugin-card.featured { 91 79 border-color: #00a32a; … … 93 81 background: linear-gradient(135deg, #fff 0%, #f8fff9 100%); 94 82 } 95 96 83 .plugin-card.featured::before { 97 84 content: ''; … … 105 92 animation: featured-shimmer 3s ease-in-out infinite; 106 93 } 107 108 94 @keyframes featured-shimmer { 109 95 0%, 100% { background-position: 200% 0; } 110 96 50% { background-position: -200% 0; } 111 97 } 112 113 /* Featured Badge */114 98 .featured-badge { 115 99 position: absolute; … … 126 110 letter-spacing: 0.5px; 127 111 } 128 129 /* Required Plugin Badge */ 130 .plugin-card .required-badge { 112 .essential-badge { 131 113 position: absolute; 132 114 top: 10px; … … 144 126 } 145 127 146 /* Plugin Card Required Styling */ 147 .plugin-card[data-required="1"] { 128 .plugin-card[data-essential="1"] { 148 129 border: 2px solid #d63638; 149 130 box-shadow: 0 4px 12px rgba(214, 54, 56, 0.15); 150 131 } 151 152 .plugin-card[data-required="1"] .plugin-header h3 { 132 .plugin-card[data-essential="1"] .plugin-header h3 { 153 133 color: #d63638; 154 134 font-weight: 600; 155 135 } 156 157 /* Filter Tab for Required */ 158 .filter-tab[data-filter="required"] { 136 .filter-tab[data-filter="essential"] { 159 137 background: #fff2f2; 160 138 border-color: #d63638; 161 139 color: #d63638; 162 140 } 163 164 .filter-tab[data-filter="required"].active { 141 .filter-tab[data-filter="essential"].active { 165 142 background: #d63638; 166 143 color: white; 167 144 } 168 169 /* Plugin Header */170 145 .plugin-header { 171 146 margin-bottom: 18px; … … 173 148 padding-bottom: 15px; 174 149 } 175 176 150 .plugin-header h3 { 177 151 margin: 0 0 8px 0; … … 182 156 letter-spacing: -0.01em; 183 157 } 184 185 158 .plugin-category { 186 159 display: inline-block; … … 195 168 box-shadow: 0 1px 3px rgba(0,0,0,0.1); 196 169 } 197 198 /* Category-specific colors */199 .plugin-category {200 background: #f0f0f1;201 color: #50575e;202 }203 204 /* Plugin Description */205 170 .plugin-description { 206 171 margin-bottom: 25px; 207 172 min-height: 60px; 208 173 } 209 210 174 .plugin-description p { 211 175 margin: 0; … … 214 178 font-size: 14px; 215 179 } 216 217 /* Plugin Actions */218 180 .plugin-actions { 219 181 display: flex; … … 224 186 border-top: 1px solid #f0f0f1; 225 187 } 226 227 188 .plugin-actions .button { 228 189 min-width: 100px; … … 234 195 text-transform: none; 235 196 } 236 237 197 .plugin-actions .button-primary { 238 198 background: linear-gradient(135deg, #0073aa 0%, #005a87 100%); … … 240 200 box-shadow: 0 2px 4px rgba(0,115,170,0.3); 241 201 } 242 243 202 .plugin-actions .button-primary:hover { 244 203 background: linear-gradient(135deg, #005a87 0%, #004866 100%); … … 246 205 box-shadow: 0 4px 8px rgba(0,115,170,0.4); 247 206 } 248 249 207 .plugin-actions .button.disabled { 250 208 background: linear-gradient(135deg, #f0f0f1 0%, #e8e8e9 100%); … … 253 211 border-color: #ddd; 254 212 } 255 256 /* Plugin Status */257 213 .plugin-status { 258 214 font-size: 12px; … … 264 220 box-shadow: 0 1px 3px rgba(0,0,0,0.1); 265 221 } 266 267 222 .plugin-status.status-active { 268 223 background: linear-gradient(135deg, #d1e7dd 0%, #c3e6cb 100%); … … 270 225 border: 1px solid #badbcc; 271 226 } 272 273 227 .plugin-status.status-inactive { 274 228 background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%); … … 276 230 border: 1px solid #f1c40f; 277 231 } 278 279 232 .plugin-status.status-not-installed { 280 233 background: linear-gradient(135deg, #f8d7da 0%, #f5c6cb 100%); … … 282 235 border: 1px solid #f1556c; 283 236 } 284 285 /* Update status styles */286 237 .plugin-status.status-needs-update { 287 238 background: linear-gradient(135deg, #ffeaa7 0%, #fdcb6e 100%); … … 290 241 animation: updatePulse 2s ease-in-out infinite; 291 242 } 292 293 243 .plugin-status.status-inactive-needs-update { 294 244 background: linear-gradient(135deg, #fab1a0 0%, #e17055 100%); … … 297 247 animation: updatePulse 2s ease-in-out infinite; 298 248 } 299 300 249 @keyframes updatePulse { 301 0%, 100% { 302 transform: scale(1); 303 opacity: 1; 304 } 305 50% { 306 transform: scale(1.05); 307 opacity: 0.8; 308 } 309 } 310 311 /* Update button styles */ 250 0%, 100% { transform: scale(1); opacity: 1; } 251 50% { transform: scale(1.05); opacity: 0.8; } 252 } 312 253 .button.update-plugin { 313 254 background: linear-gradient(135deg, #fdcb6e 0%, #e17055 100%) !important; … … 317 258 border-radius: 6px !important; 318 259 box-shadow: 0 2px 4px rgba(253, 203, 110, 0.3) !important; 319 position: relative !important;320 260 overflow: hidden !important; 321 261 } 322 323 262 .button.update-plugin:hover { 324 263 background: linear-gradient(135deg, #e17055 0%, #d63031 100%) !important; … … 326 265 box-shadow: 0 4px 8px rgba(253, 203, 110, 0.4) !important; 327 266 } 328 329 .button.update-plugin::before {330 content: '⚡';331 margin-right: 5px;332 }333 334 /* Version info styles */335 .version-info {336 display: block;337 margin-top: 5px;338 color: #666;339 font-size: 11px;340 line-height: 1.3;341 opacity: 0.8;342 }343 344 .plugin-card[data-status="needs-update"] .version-info,345 .plugin-card[data-status="inactive-needs-update"] .version-info {346 color: #d63031;347 font-weight: 600;348 }349 350 /* Local plugin badge */351 267 .local-plugin-badge { 352 268 position: absolute; … … 364 280 box-shadow: 0 2px 4px rgba(108, 92, 231, 0.3); 365 281 } 366 367 /* Plugin card with local plugin styling */368 282 .plugin-card[data-local="1"] { 369 283 border: 2px solid #6c5ce7; … … 371 285 box-shadow: 0 4px 12px rgba(108, 92, 231, 0.15); 372 286 } 373 374 287 .plugin-card[data-local="1"] .plugin-header h3 { 375 288 color: #6c5ce7; 376 289 font-weight: 600; 377 290 } 378 379 /* Update available notice */ 380 .update-notice { 381 background: linear-gradient(135deg, #fff3cd 0%, #ffeaa7 100%); 382 border: 1px solid #ffeaa7; 383 border-radius: 8px; 384 padding: 15px; 385 margin: 20px 0; 386 box-shadow: 0 2px 8px rgba(253, 203, 110, 0.2); 387 } 388 389 .update-notice h3 { 390 margin: 0 0 10px 0; 391 color: #d63031; 392 font-size: 16px; 393 display: flex; 394 align-items: center; 395 gap: 8px; 396 } 397 398 .update-notice h3::before { 399 content: '⚠️'; 400 font-size: 18px; 401 } 402 403 .update-notice p { 404 margin: 0; 405 color: #856404; 406 line-height: 1.5; 407 } 408 409 /* Loading States */ 291 .version-info { 292 display: block; 293 margin-top: 5px; 294 color: #666; 295 font-size: 11px; 296 line-height: 1.3; 297 opacity: 0.8; 298 } 410 299 .button.loading { 411 300 position: relative; … … 414 303 overflow: hidden; 415 304 } 416 417 305 .button.loading::after { 418 306 content: ''; … … 428 316 animation: button-loading 1s linear infinite; 429 317 } 430 431 318 @keyframes button-loading { 432 to { 433 transform: rotate(360deg); 434 } 435 } 436 437 /* Filter States */ 438 .plugin-card.hidden { 439 display: none; 440 } 441 442 /* Admin Notice */ 443 .magical-plugin-activation-pro-plugin-notice { 444 position: relative; 445 border: none !important; 446 background: linear-gradient(135deg, #fff 0%, #f8f9ff 100%) !important; 447 border-radius: 12px !important; 448 box-shadow: 0 4px 20px rgba(34, 113, 177, 0.12) !important; 449 padding: 0 !important; 450 margin: 20px 0 !important; 451 overflow: hidden; 452 } 453 454 .magical-plugin-activation-pro-plugin-notice::before { 455 content: ''; 456 position: absolute; 457 top: 0; 458 left: 0; 459 right: 0; 460 height: 4px; 461 background: linear-gradient(90deg, #2271b1 0%, #135e96 50%, #2271b1 100%); 462 background-size: 200% 100%; 463 animation: recommendedShimmer 3s ease-in-out infinite; 464 } 465 466 @keyframes recommendedShimmer { 467 0%, 100% { background-position: 200% 0; } 468 50% { background-position: -200% 0; } 469 } 470 471 .magical-plugin-activation-pro-plugin-notice > div { 472 padding: 20px 25px !important; 473 display: flex !important; 474 align-items: center !important; 475 gap: 20px !important; 476 margin: 0 !important; 477 } 478 479 .magical-plugin-activation-pro-plugin-notice h3 { 480 color: #2271b1 !important; 481 font-size: 18px !important; 482 font-weight: 600 !important; 483 margin: 0 0 8px 0 !important; 484 display: flex !important; 485 align-items: center !important; 486 gap: 8px !important; 487 } 488 489 .magical-plugin-activation-pro-plugin-notice h3::before { 490 content: '⚡'; 491 font-size: 20px; 492 filter: hue-rotate(200deg); 493 } 494 495 .magical-plugin-activation-pro-plugin-notice p { 496 color: #3c434a !important; 497 font-size: 14px !important; 498 line-height: 1.5 !important; 499 margin: 0 0 15px 0 !important; 500 } 501 502 .magical-plugin-activation-pro-plugin-notice .button { 503 background: linear-gradient(135deg, #2271b1 0%, #135e96 100%) !important; 504 border: none !important; 505 color: #fff !important; 506 font-weight: 600 !important; 507 border-radius: 8px !important; 508 padding: 10px 20px !important; 509 font-size: 14px !important; 510 text-decoration: none !important; 511 transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1) !important; 512 box-shadow: 0 2px 8px rgba(34, 113, 177, 0.3) !important; 513 position: relative !important; 514 overflow: hidden !important; 515 } 516 517 .magical-plugin-activation-pro-plugin-notice .button::before { 518 content: ''; 519 position: absolute; 520 top: 0; 521 left: -100%; 522 width: 100%; 523 height: 100%; 524 background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent); 525 transition: left 0.5s; 526 } 527 528 .magical-plugin-activation-pro-plugin-notice .button:hover::before { 529 left: 100%; 530 } 531 532 .magical-plugin-activation-pro-plugin-notice .button:hover { 533 background: linear-gradient(135deg, #135e96 0%, #0f4a75 100%) !important; 534 transform: translateY(-2px) !important; 535 box-shadow: 0 4px 12px rgba(34, 113, 177, 0.4) !important; 536 } 537 538 .magical-plugin-activation-pro-plugin-notice .button:active { 539 transform: translateY(0) !important; 540 } 541 542 .magical-plugin-activation-pro-plugin-notice .button-secondary { 543 background: rgba(34, 113, 177, 0.1) !important; 544 color: #2271b1 !important; 545 border: 2px solid rgba(34, 113, 177, 0.2) !important; 546 box-shadow: none !important; 547 } 548 549 .magical-plugin-activation-pro-plugin-notice .button-secondary:hover { 550 background: rgba(34, 113, 177, 0.15) !important; 551 border-color: rgba(34, 113, 177, 0.3) !important; 552 transform: translateY(-1px) !important; 553 } 554 555 .magical-plugin-activation-pro-plugin-notice .notice-dismiss { 556 top: 15px !important; 557 right: 15px !important; 558 color: #2271b1 !important; 559 opacity: 0.6 !important; 560 font-size: 18px !important; 561 } 562 563 .magical-plugin-activation-pro-plugin-notice .notice-dismiss:hover { 564 opacity: 1 !important; 565 color: #135e96 !important; 566 } 567 568 /* Plugin icon in notice */ 569 .magical-plugin-activation-pro-plugin-notice .plugin-icon-recomend { 570 font-size: 48px; 571 color: #2271b1; 572 opacity: 0.15; 573 min-width: 60px; 574 text-align: center; 575 } 576 577 /* Success/Error Messages */ 578 .plugin-message { 579 position: absolute; 580 top: 15px; 581 right: 15px; 582 background: #00a32a; 583 color: white; 584 padding: 8px 12px; 585 border-radius: 6px; 586 font-size: 12px; 587 font-weight: 600; 588 opacity: 0; 589 transform: translateY(-10px) scale(0.9); 590 transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); 591 box-shadow: 0 4px 12px rgba(0,163,42,0.3); 592 z-index: 10; 593 } 594 595 .plugin-message.show { 596 opacity: 1; 597 transform: translateY(0) scale(1); 598 } 599 600 .plugin-message.error { 601 background: #d63638; 602 box-shadow: 0 4px 12px rgba(214,54,56,0.3); 603 } 604 605 /* Install Required Plugins Button */ 606 #install-required-plugins { 607 animation: pulse 2s infinite; 608 } 609 610 @keyframes pulse { 611 0% { transform: scale(1); } 612 50% { transform: scale(1.05); } 613 100% { transform: scale(1); } 614 } 615 616 #install-required-plugins:hover { 617 animation: none; 618 transform: scale(1.05); 619 } 620 621 /* Progress indicator for bulk install */ 622 .bulk-install-progress { 623 margin: 15px 0; 624 padding: 15px; 625 background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); 626 border-radius: 8px; 627 border: 1px solid #dee2e6; 628 box-shadow: 0 2px 4px rgba(0,0,0,0.1); 629 display: none; 630 } 631 632 .bulk-install-progress.active { 633 display: block; 634 animation: slideIn 0.3s ease-out; 635 } 636 637 @keyframes slideIn { 638 from { 639 opacity: 0; 640 transform: translateY(-10px); 641 } 642 to { 643 opacity: 1; 644 transform: translateY(0); 645 } 646 } 647 648 .progress-bar { 649 height: 12px; 650 background: #e9ecef; 651 border-radius: 6px; 652 overflow: hidden; 653 margin-bottom: 10px; 654 position: relative; 655 box-shadow: inset 0 1px 2px rgba(0,0,0,0.1); 656 } 657 658 .progress-bar::before { 659 content: ''; 660 position: absolute; 661 top: 0; 662 left: 0; 663 right: 0; 664 height: 50%; 665 background: linear-gradient(to bottom, rgba(255,255,255,0.3), transparent); 666 border-radius: 6px 6px 0 0; 667 } 668 669 .progress-fill { 670 height: 100%; 671 background: linear-gradient(45deg, #0073aa 25%, #005a87 25%, #005a87 50%, #0073aa 50%, #0073aa 75%, #005a87 75%, #005a87); 672 background-size: 20px 20px; 673 transition: width 0.8s cubic-bezier(0.25, 0.46, 0.45, 0.94); 674 width: 0%; 675 position: relative; 676 border-radius: 6px; 677 animation: progressStripes 1s linear infinite; 678 } 679 680 @keyframes progressStripes { 681 0% { 682 background-position: 0 0; 683 } 684 100% { 685 background-position: 20px 0; 686 } 687 } 688 689 .progress-fill::after { 690 content: ''; 691 position: absolute; 692 top: 0; 693 left: 0; 694 right: 0; 695 height: 100%; 696 background: linear-gradient(to right, rgba(255,255,255,0.2), transparent, rgba(255,255,255,0.2)); 697 border-radius: 6px; 698 animation: progressGlow 2s ease-in-out infinite; 699 } 700 701 @keyframes progressGlow { 702 0%, 100% { 703 opacity: 0; 704 } 705 50% { 706 opacity: 1; 707 } 708 } 709 710 .progress-text { 711 font-size: 13px; 712 color: #495057; 713 text-align: center; 714 font-weight: 500; 715 margin: 0; 716 } 717 718 /* Plugin Update Notice */ 719 .magical-plugin-activation-pro-update-notice { 720 position: relative; 721 border: 1px solid #d39e00; 722 border-left: 4px solid #d39e00; 723 padding: 12px; 724 margin: 5px 15px 20px 0; 725 background: #fff8e1; 726 border-radius: 4px; 727 box-shadow: 0 2px 4px rgba(0,0,0,0.1); 728 } 729 730 .magical-plugin-activation-pro-update-notice .plugin-update-content { 731 display: flex; 732 align-items: flex-start; 733 gap: 20px; 734 } 735 736 .magical-plugin-activation-pro-update-notice .plugin-update-content h3 { 737 margin: 0 0 10px 0; 738 font-size: 18px; 739 font-weight: 600; 740 color: #d39e00; 741 } 742 743 .magical-plugin-activation-pro-update-notice .plugin-update-content p { 744 margin: 0 0 15px 0; 745 font-size: 14px; 746 line-height: 1.5; 747 color: #5c5c5c; 748 } 749 750 .magical-plugin-activation-pro-update-notice .plugin-icon-recomend { 751 font-size: 32px; 752 opacity: 0.8; 753 min-width: 40px; 754 text-align: center; 755 } 756 757 .plugin-update-list { 758 margin: 15px 0; 759 padding: 0; 760 list-style: none; 761 } 762 763 .plugin-update-item { 764 display: flex; 765 align-items: center; 766 gap: 10px; 767 margin-bottom: 10px; 768 padding: 10px; 769 background: #fff; 770 border: 1px solid #e0e0e0; 771 border-radius: 4px; 772 font-size: 13px; 773 flex-wrap: wrap; 774 } 775 776 .plugin-update-item strong { 777 color: #333; 778 font-weight: 600; 779 flex-shrink: 0; 780 } 781 782 .plugin-update-item .local-plugin-badge { 783 background: #2271b1; 784 color: white; 785 padding: 2px 6px; 786 border-radius: 3px; 787 font-size: 11px; 788 font-weight: 500; 789 text-transform: uppercase; 790 letter-spacing: 0.5px; 791 } 792 793 .plugin-update-item .version-info { 794 color: #666; 795 font-size: 12px; 796 margin-left: auto; 797 } 798 799 .plugin-update-item .button { 800 margin-left: 10px; 801 padding: 4px 8px; 802 font-size: 12px; 803 height: auto; 804 line-height: 1.2; 805 } 806 807 /* Update button styles */ 808 .update-plugin { 809 background: #d39e00; 810 color: white; 811 border: none; 812 padding: 8px 16px; 813 border-radius: 4px; 814 cursor: pointer; 815 font-weight: 500; 816 text-decoration: none; 817 transition: all 0.3s ease; 818 position: relative; 819 overflow: hidden; 820 } 821 822 .update-plugin:hover { 823 background: #b8860b; 824 transform: translateY(-2px); 825 box-shadow: 0 4px 8px rgba(211, 158, 0, 0.3); 826 } 827 828 .update-plugin:active { 829 transform: translateY(0); 830 } 831 832 .update-plugin:disabled, 833 .update-plugin.loading { 834 opacity: 0.6; 835 cursor: not-allowed; 836 pointer-events: none; 837 } 838 839 .update-plugin.loading::after { 840 content: ''; 841 position: absolute; 842 top: 0; 843 left: -100%; 844 width: 100%; 845 height: 100%; 846 background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); 847 animation: button-loading 1.5s ease-in-out infinite; 848 } 849 850 @keyframes button-loading { 851 0% { left: -100%; } 852 100% { left: 100%; } 853 } 854 855 /* Update All Plugins Button */ 856 #update-all-plugins { 857 background: #d39e00; 858 color: white; 859 border: none; 860 padding: 10px 20px; 861 border-radius: 4px; 862 cursor: pointer; 863 font-weight: 600; 864 text-decoration: none; 865 transition: all 0.3s ease; 866 display: inline-flex; 867 align-items: center; 868 gap: 8px; 869 } 870 871 #update-all-plugins:hover { 872 background: #b8860b; 873 transform: translateY(-2px); 874 box-shadow: 0 4px 12px rgba(211, 158, 0, 0.3); 875 } 876 877 #update-all-plugins:active { 878 transform: translateY(0); 879 } 880 881 #update-all-plugins:before { 882 content: "🔄"; 883 font-size: 14px; 884 } 885 886 /* Plugin status indicators for updates */ 887 .plugin-status.status-needs-update, 888 .plugin-status.status-inactive-needs-update { 889 color: #d39e00; 890 font-weight: 600; 891 background: #fff8e1; 892 padding: 4px 8px; 893 border-radius: 3px; 894 border: 1px solid #d39e00; 895 } 896 897 .plugin-status.status-needs-update::before, 898 .plugin-status.status-inactive-needs-update::before { 899 content: "🔄"; 900 margin-right: 4px; 901 } 902 903 /* Version info styling */ 904 .plugin-card .version-info { 905 display: block; 906 margin-top: 8px; 907 color: #666; 908 font-size: 12px; 909 line-height: 1.3; 910 } 911 912 .plugin-card .version-info strong { 913 color: #333; 914 } 915 916 /* Update available badge */ 917 .plugin-card .update-available { 918 position: absolute; 919 top: -5px; 920 right: -5px; 921 background: #d39e00; 922 color: white; 923 padding: 4px 8px; 924 border-radius: 12px; 925 font-size: 11px; 926 font-weight: 600; 927 text-transform: uppercase; 928 letter-spacing: 0.5px; 929 box-shadow: 0 2px 4px rgba(0,0,0,0.2); 930 z-index: 10; 931 } 932 933 /* Responsive design for update notice */ 319 to { transform: rotate(360deg); } 320 } 321 .plugin-card.hidden { display: none; } 934 322 @media (max-width: 782px) { 935 .magical-plugin-activation-pro-update-notice .plugin-update-content { 936 flex-direction: column; 937 gap: 15px; 938 } 939 940 .plugin-update-item { 941 flex-direction: column; 942 align-items: flex-start; 943 gap: 8px; 944 } 945 946 .plugin-update-item .version-info { 947 margin-left: 0; 948 } 949 950 .plugin-update-item .button { 951 margin-left: 0; 952 margin-top: 8px; 953 align-self: flex-start; 954 } 955 } 956 957 /* Responsive Design */ 958 @media (max-width: 1200px) { 959 .plugins-grid { 960 grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); 961 gap: 20px; 962 } 963 } 964 965 @media (max-width: 782px) { 966 .magical-plugin-activation-plugins { 967 padding: 10px 0; 968 } 969 970 .plugins-grid { 971 grid-template-columns: 1fr; 972 gap: 15px; 973 padding: 15px; 974 } 975 976 .plugin-filter-tabs { 977 padding: 8px; 978 gap: 3px; 979 } 980 981 .filter-tab { 982 flex: 1; 983 min-width: auto; 984 text-align: center; 985 padding: 10px 8px; 986 font-size: 11px; 987 margin-right: 0; 988 } 989 990 .plugin-card { 991 padding: 20px; 992 } 993 994 .plugin-actions { 995 flex-direction: column; 996 align-items: stretch; 997 gap: 10px; 998 } 999 1000 .plugin-actions .button { 1001 width: 100%; 1002 } 1003 1004 .magical-plugin-activation-pro-plugin-notice p { 1005 flex-direction: column; 1006 align-items: flex-start; 1007 gap: 10px; 1008 } 1009 1010 .magical-plugin-activation-pro-plugin-notice .button { 1011 margin-left: 0; 1012 align-self: stretch; 1013 } 1014 } 1015 1016 /* Responsive improvements for recommended notice */ 1017 @media (max-width: 768px) { 1018 .magical-plugin-activation-pro-plugin-notice > div { 1019 flex-direction: column !important; 1020 text-align: center !important; 1021 gap: 15px !important; 1022 } 1023 1024 .magical-plugin-activation-pro-plugin-notice > div > div:first-child { 1025 order: 2; 1026 } 1027 1028 .magical-plugin-activation-pro-plugin-notice .plugin-icon-recomend { 1029 order: 1; 1030 font-size: 36px !important; 1031 } 1032 1033 .magical-plugin-activation-pro-plugin-notice > div > div:first-child > div { 1034 justify-content: center !important; 1035 } 1036 1037 .bulk-install-progress { 1038 padding: 12px !important; 1039 margin: 10px 0 !important; 1040 } 1041 1042 .progress-text { 1043 font-size: 12px !important; 1044 } 1045 } 1046 1047 /* Animation for when plugins are successfully installed */ 1048 @keyframes success-pulse { 1049 0%, 100% { 1050 transform: scale(1); 1051 opacity: 1; 1052 } 1053 50% { 1054 transform: scale(1.05); 1055 opacity: 0.8; 1056 } 1057 } 1058 1059 .magical-plugin-activation-pro-plugin-notice.success { 1060 animation: success-pulse 0.6s ease-in-out; 1061 } 1062 1063 /* Loading state for buttons */ 1064 .magical-plugin-activation-pro-plugin-notice .button.loading { 1065 position: relative; 1066 color: transparent !important; 1067 pointer-events: none; 1068 overflow: hidden; 1069 } 1070 1071 .magical-plugin-activation-pro-plugin-notice .button.loading::after { 1072 content: ''; 1073 position: absolute; 1074 top: 50%; 1075 left: 50%; 1076 width: 16px; 1077 height: 16px; 1078 margin: -8px 0 0 -8px; 1079 border: 2px solid rgba(255,255,255,0.3); 1080 border-radius: 50%; 1081 border-top-color: #fff; 1082 animation: button-loading 1s linear infinite; 1083 } 1084 1085 /* Bulk Update Progress */ 1086 .bulk-update-progress { 1087 margin-top: 15px; 1088 padding: 15px; 1089 background: #fff; 1090 border: 1px solid #ddd; 1091 border-radius: 6px; 1092 box-shadow: 0 2px 4px rgba(0,0,0,0.1); 1093 opacity: 0; 1094 transform: translateY(-10px); 1095 transition: all 0.3s ease; 1096 } 1097 1098 .bulk-update-progress.active { 1099 opacity: 1; 1100 transform: translateY(0); 1101 } 1102 1103 .bulk-update-progress .progress-bar { 1104 height: 8px; 1105 background: #e0e0e0; 1106 border-radius: 4px; 1107 overflow: hidden; 1108 margin-bottom: 10px; 1109 } 1110 1111 .bulk-update-progress .progress-fill { 1112 height: 100%; 1113 background: linear-gradient(90deg, #d39e00, #f1c40f); 1114 border-radius: 4px; 1115 transition: width 0.3s ease; 1116 position: relative; 1117 } 1118 1119 .bulk-update-progress .progress-fill::after { 1120 content: ''; 1121 position: absolute; 1122 top: 0; 1123 left: 0; 1124 width: 100%; 1125 height: 100%; 1126 background: linear-gradient(90deg, transparent, rgba(255,255,255,0.3), transparent); 1127 animation: progress-shimmer 1.5s ease-in-out infinite; 1128 } 1129 1130 @keyframes progress-shimmer { 1131 0% { transform: translateX(-100%); } 1132 100% { transform: translateX(100%); } 1133 } 1134 1135 .bulk-update-progress .progress-text { 1136 font-size: 13px; 1137 color: #666; 1138 text-align: center; 1139 font-weight: 500; 1140 } 1141 1142 /* Improved focus states for accessibility */ 1143 .filter-tab:focus, 1144 .plugin-actions .button:focus { 1145 outline: 2px solid #0073aa; 1146 outline-offset: 2px; 1147 } 1148 1149 /* Loading skeleton effect */ 1150 .plugin-card.loading { 1151 position: relative; 1152 overflow: hidden; 1153 } 1154 1155 .plugin-card.loading::before { 1156 content: ''; 1157 position: absolute; 1158 top: 0; 1159 left: -100%; 1160 width: 100%; 1161 height: 100%; 1162 background: linear-gradient(90deg, transparent, rgba(255,255,255,0.4), transparent); 1163 animation: loading-shimmer 1.5s ease-in-out infinite; 1164 } 1165 1166 @keyframes loading-shimmer { 1167 0% { left: -100%; } 1168 100% { left: 100%; } 1169 } 1170 1171 /* Plugin Notices */ 1172 .magical-plugin-activation-pro-required-notice, 1173 .magical-plugin-activation-pro-recommended-notice, 1174 .magical-plugin-activation-pro-update-notice { 1175 border-radius: 8px; 1176 box-shadow: 0 2px 4px rgba(0,0,0,0.1); 1177 margin: 20px 0; 1178 animation: slideInFromTop 0.3s ease-out; 1179 } 1180 1181 .magical-plugin-activation-pro-required-notice { 1182 border-left: 4px solid #dc3232; 1183 } 1184 1185 .magical-plugin-activation-pro-recommended-notice { 1186 border-left: 4px solid #0073aa; 1187 } 1188 1189 .magical-plugin-activation-pro-update-notice { 1190 border-left: 4px solid #ffb900; 1191 } 1192 1193 .plugin-recommended-content, 1194 .plugin-update-content { 1195 display: flex; 1196 align-items: center; 1197 gap: 20px; 1198 padding: 10px 0; 1199 } 1200 1201 .plugin-recommended-content .plugin-icon-recomend, 1202 .plugin-update-content .plugin-icon-recomend { 1203 font-size: 24px; 1204 opacity: 0.8; 1205 } 1206 1207 .plugin-recommended-content h3, 1208 .plugin-update-content h3 { 1209 margin: 0 0 10px 0; 1210 color: #23282d; 1211 font-size: 16px; 1212 } 1213 1214 .plugin-recommended-content p, 1215 .plugin-update-content p { 1216 margin: 0 0 15px 0; 1217 color: #646970; 1218 line-height: 1.5; 1219 } 1220 1221 @keyframes slideInFromTop { 1222 from { 1223 transform: translateY(-20px); 1224 opacity: 0; 1225 } 1226 to { 1227 transform: translateY(0); 1228 opacity: 1; 1229 } 1230 } 323 .plugins-grid { grid-template-columns: 1fr; gap: 15px; padding: 15px; } 324 .filter-tab { flex: 1; text-align: center; padding: 10px 8px; font-size: 11px; } 325 .plugin-card { padding: 20px; } 326 .plugin-actions { flex-direction: column; align-items: stretch; gap: 10px; } 327 .plugin-actions .button { width: 100%; } 328 } -
portfoliox-dark/1.0.14/libs/magical-plugin-activation/assets/js/admin-plugins.js
r306496 r357072 1 /**2 * Shop Toolkit Pro Plugin Recommendations Admin JavaScript3 */4 5 1 (function($) { 6 2 'use strict'; 7 8 3 $(document).ready(function() { 9 // Initialize plugin recommendations10 4 PluginRecommendations.init(); 11 5 }); 12 13 6 var PluginRecommendations = { 14 15 7 init: function() { 16 8 this.bindEvents(); 17 9 this.initFilters(); 18 19 // Check if recommended plugins notice should be hidden20 10 if (window.location.href.indexOf('wp-admin') !== -1) { 21 11 this.checkRecommendedPluginsStatus(); 22 12 } 23 13 }, 24 25 14 bindEvents: function() { 26 // Install plugin27 15 $(document).on('click', '.install-plugin', this.installPlugin); 28 29 // Activate plugin30 16 $(document).on('click', '.activate-plugin', this.activatePlugin); 31 32 // Update plugin33 17 $(document).on('click', '.update-plugin', this.updatePlugin); 34 35 // Filter tabs36 18 $(document).on('click', '.filter-tab', this.filterPlugins); 37 38 // Dismiss install notice - Handle .install-dismiss buttons and #install-dismiss ID39 19 $(document).on('click', '.install-dismiss, #install-dismiss', this.dismissInstallNotice); 40 41 // Bulk install required plugins 42 $(document).on('click', '#install-required-plugins', this.bulkInstallRequired); 43 44 // Bulk install recommended plugins 20 $(document).on('click', '#install-essential-plugins', this.bulkInstallEssential); 45 21 $(document).on('click', '#install-recommended-plugins', this.bulkInstallRecommended); 46 47 // Update all plugins 22 $(document).on('click', '#install-all-plugins', this.bulkInstallAll); 48 23 $(document).on('click', '#update-all-plugins', this.updateAllPlugins); 49 24 }, 50 51 25 initFilters: function() { 52 // Set initial counts53 26 this.updateFilterCounts(); 54 27 }, 55 56 28 installPlugin: function(e) { 57 29 e.preventDefault(); 58 59 30 var $button = $(this); 60 31 var slug = $button.data('slug'); 61 32 var isLocal = $button.data('is-local') === 1; 62 var originalText = $button.text(); 63 64 // Disable button and show loading 65 $button.addClass('loading').prop('disabled', true); 66 33 $button.addClass('loading').prop('disabled', true); 67 34 $.ajax({ 68 35 url: MagicalPluginActivation.ajaxurl, … … 76 43 success: function(response) { 77 44 if (response.success) { 78 PluginRecommendations.showMessage($button, response.data.message || MagicalPluginActivation.strings.installed, 'success'); 79 80 // Update plugin status 45 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.installed, 'success'); 81 46 setTimeout(function() { 82 47 PluginRecommendations.updatePluginStatus(slug, 'inactive'); 83 84 // Auto-activate the plugin85 48 $button.removeClass('loading').trigger('click'); 86 49 }, 1000); 87 50 } else { 88 PluginRecommendations.showMessage($button, response.data.message ||MagicalPluginActivation.strings.error, 'error');51 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.error, 'error'); 89 52 $button.removeClass('loading').prop('disabled', false); 90 53 } … … 96 59 }); 97 60 }, 98 99 61 activatePlugin: function(e) { 100 62 e.preventDefault(); 101 102 63 var $button = $(this); 103 64 var file = $button.data('file'); 104 65 var slug = $button.data('slug'); 105 var originalText = $button.text(); 106 107 // Disable button and show loading 108 $button.addClass('loading').prop('disabled', true); 109 66 $button.addClass('loading').prop('disabled', true); 110 67 $.ajax({ 111 68 url: MagicalPluginActivation.ajaxurl, … … 119 76 if (response.success) { 120 77 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.activated, 'success'); 121 122 // Update plugin status123 78 setTimeout(function() { 124 79 PluginRecommendations.updatePluginStatus(slug, 'active'); 125 126 // Check if all recommended plugins are now active127 80 PluginRecommendations.checkRecommendedPluginsStatus(); 128 129 // Reload page after activation to refresh plugin status 130 setTimeout(function() { 131 location.reload(); 132 }, 2000); 81 setTimeout(function() { location.reload(); }, 2000); 133 82 }, 1000); 134 83 } else { 135 PluginRecommendations.showMessage($button, response.data ||MagicalPluginActivation.strings.error, 'error');84 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.error, 'error'); 136 85 $button.removeClass('loading').prop('disabled', false); 137 86 } … … 143 92 }); 144 93 }, 145 146 94 updatePlugin: function(e) { 147 95 e.preventDefault(); 148 149 96 var $button = $(this); 150 97 var slug = $button.data('slug'); 151 98 var file = $button.data('file'); 152 99 var isLocal = $button.data('is-local') === 1; 153 var originalText = $button.text(); 154 155 // Disable button and show loading 156 $button.addClass('loading').prop('disabled', true); 157 100 $button.addClass('loading').prop('disabled', true); 158 101 $.ajax({ 159 102 url: MagicalPluginActivation.ajaxurl, … … 168 111 success: function(response) { 169 112 if (response.success) { 170 PluginRecommendations.showMessage($button, response.data.message || MagicalPluginActivation.strings.updated, 'success'); 171 172 // Update plugin status to active (since it was reactivated) 113 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.updated, 'success'); 173 114 setTimeout(function() { 174 115 PluginRecommendations.updatePluginStatus(slug, 'active'); 175 176 // Check if all recommended plugins are now active177 116 PluginRecommendations.checkRecommendedPluginsStatus(); 178 117 }, 1000); 179 118 } else { 180 PluginRecommendations.showMessage($button, response.data.message ||MagicalPluginActivation.strings.error, 'error');119 PluginRecommendations.showMessage($button, MagicalPluginActivation.strings.error, 'error'); 181 120 $button.removeClass('loading').prop('disabled', false); 182 121 } … … 188 127 }); 189 128 }, 190 191 129 filterPlugins: function(e) { 192 130 e.preventDefault(); 193 194 131 var $tab = $(this); 195 132 var filter = $tab.data('filter'); 196 197 // Update active tab198 133 $('.filter-tab').removeClass('active'); 199 134 $tab.addClass('active'); 200 201 // Filter plugin cards202 135 $('.plugin-card').each(function() { 203 136 var $card = $(this); 204 137 var status = $card.data('status'); 205 138 var featured = $card.data('featured'); 206 var required = $card.data('required');139 var essential = $card.data('essential'); 207 140 var show = false; 208 209 141 switch (filter) { 210 case 'all': 211 show = true; 212 break; 213 case 'featured': 214 show = featured == 1; 215 break; 216 case 'required': 217 show = required == 1; 218 break; 219 case 'active': 220 show = status === 'active'; 221 break; 222 case 'inactive': 223 show = status === 'inactive'; 224 break; 225 case 'not-installed': 226 show = status === 'not-installed'; 227 break; 228 } 229 230 if (show) { 231 $card.removeClass('hidden').fadeIn(300); 232 } else { 233 $card.addClass('hidden').fadeOut(300); 234 } 235 }); 236 237 // Update URL without reloading 142 case 'all': show = true; break; 143 case 'featured': show = featured == 1; break; 144 case 'essential': show = essential == 1; break; 145 case 'active': show = status === 'active'; break; 146 case 'inactive': show = status === 'inactive'; break; 147 case 'not-installed': show = status === 'not-installed'; break; 148 } 149 if (show) { $card.removeClass('hidden').fadeIn(300); } 150 else { $card.addClass('hidden').fadeOut(300); } 151 }); 238 152 if (history.pushState) { 239 153 var newUrl = window.location.href.split('?')[0] + '?page=magical-plugin-activation-plugins'; 240 if (filter !== 'all') { 241 newUrl += '&filter=' + filter; 242 } 154 if (filter !== 'all') { newUrl += '&filter=' + filter; } 243 155 history.pushState(null, null, newUrl); 244 156 } 245 157 }, 246 247 158 updateFilterCounts: function() { 248 var counts = { 249 all: 0, 250 featured: 0, 251 required: 0, 252 active: 0, 253 inactive: 0, 254 'not-installed': 0 255 }; 256 159 var counts = { all: 0, featured: 0, essential: 0, active: 0, inactive: 0, 'not-installed': 0 }; 257 160 $('.plugin-card').each(function() { 258 161 var $card = $(this); 259 162 var status = $card.data('status'); 260 163 var featured = $card.data('featured'); 261 var required = $card.data('required'); 262 164 var essential = $card.data('essential'); 263 165 counts.all++; 264 166 counts[status]++; 265 266 if (featured == 1) { 267 counts.featured++; 268 } 269 270 if (required == 1) { 271 counts.required++; 272 } 273 }); 274 275 // Update tab text with counts 167 if (featured == 1) counts.featured++; 168 if (essential == 1) counts.essential++; 169 }); 276 170 $('.filter-tab').each(function() { 277 171 var $tab = $(this); … … 279 173 var count = counts[filter]; 280 174 var baseText = $tab.text().split(' (')[0]; 281 282 if (count > 0) { 283 $tab.text(baseText + ' (' + count + ')'); 284 } else { 285 $tab.text(baseText); 286 } 287 }); 288 }, 289 175 if (count > 0) { $tab.text(baseText + ' (' + count + ')'); } 176 else { $tab.text(baseText); } 177 }); 178 }, 290 179 showMessage: function($button, message, type) { 291 180 var $card = $button.closest('.plugin-card'); … … 294 183 .addClass(type === 'error' ? 'error' : '') 295 184 .appendTo($card); 296 297 // Show message 298 setTimeout(function() { 299 $message.addClass('show'); 300 }, 100); 301 302 // Hide message after 3 seconds 185 setTimeout(function() { $message.addClass('show'); }, 100); 303 186 setTimeout(function() { 304 187 $message.removeClass('show'); 305 setTimeout(function() { 306 $message.remove(); 307 }, 300); 188 setTimeout(function() { $message.remove(); }, 300); 308 189 }, 3000); 309 190 }, 310 311 // NEW: dismissInstallNotice function to handle .install-dismiss button clicks 191 updatePluginStatus: function(slug, status) { 192 var $card = $('.plugin-card[data-slug="' + slug + '"]'); 193 if (!$card.length) return; 194 $card.attr('data-status', status) 195 .removeClass('status-active status-inactive status-not-installed') 196 .addClass('status-' + status); 197 $card.find('.plugin-status').text(status.charAt(0).toUpperCase() + status.slice(1).replace('-', ' ')); 198 this.updateFilterCounts(); 199 }, 312 200 dismissInstallNotice: function(e) { 313 201 e.preventDefault(); 314 202 var $button = $(this); 315 203 var $notice = $button.closest('.notice'); 316 // Determine notice type based on CSS class 317 var noticeType = 'recommended'; // default 318 if ($notice.hasClass('magical-plugin-activation-pro-recommended-notice')) { 319 noticeType = 'recommended'; 320 } else if ($notice.hasClass('magical-plugin-activation-pro-update-notice')) { 321 noticeType = 'update'; 322 } else if ($notice.hasClass('magical-plugin-activation-pro-required-notice')) { 323 noticeType = 'install'; // Use 'install' for required plugins notice 324 } 325 326 // Two-step dismiss for required plugins 204 var noticeType = 'recommended'; 205 if ($notice.hasClass('magical-plugin-activation-pro-recommended-notice')) { noticeType = 'recommended'; } 206 else if ($notice.hasClass('magical-plugin-activation-pro-update-notice')) { noticeType = 'update'; } 207 else if ($notice.hasClass('magical-plugin-activation-pro-essential-notice')) { noticeType = 'install'; } 327 208 if (noticeType === 'install') { 328 209 if (!$button.data('confirm-dismiss')) { 329 // First click: show warning, do not dismiss 330 // Remove any previous warning 331 $notice.find('.magical-plugin-activation-required-warning').remove(); 332 // Add warning message 333 var warning = $('<div class="magical-plugin-activation-required-warning" style="color:#b71c1c; margin-top:8px; font-weight:bold;">'+ 334 (MagicalPluginActivation && MagicalPluginActivation.strings && MagicalPluginActivation.strings.requiredWarning ? MagicalPluginActivation.strings.requiredWarning : 335 'You must install and activate all required plugins before dismissing this notice. Click Dismiss again to hide this warning.')+ 336 '</div>'); 210 $notice.find('.magical-plugin-activation-essential-warning').remove(); 211 var warning = $('<div class="magical-plugin-activation-essential-warning" style="color:#b71c1c; margin-top:8px; font-weight:bold;">'+MagicalPluginActivation.strings.essentialWarning+'</div>'); 337 212 $notice.find('p').append(warning); 338 213 $button.data('confirm-dismiss', true); 339 214 return; 340 215 } 341 // Second click: proceed with AJAX and dismiss342 216 } 343 344 // Send AJAX request to hide notice permanently345 217 var requestData = { 346 218 action: 'magical_plugin_activation_dismiss_plugin_notice', 347 219 nonce: MagicalPluginActivation.nonce 348 220 }; 349 // Add notice_type or use specific action for different notices 350 if (noticeType === 'update') { 351 requestData.action = 'magical_plugin_activation_dismiss_update_notice'; 352 } else if (noticeType === 'install') { 353 requestData.action = 'magical_plugin_activation_dismiss_install_notice'; 354 } else { 355 requestData.notice_type = noticeType; 356 } 221 if (noticeType === 'update') { requestData.action = 'magical_plugin_activation_dismiss_update_notice'; } 222 else if (noticeType === 'install') { requestData.action = 'magical_plugin_activation_dismiss_install_notice'; } 223 else { requestData.notice_type = noticeType; } 357 224 $.post(MagicalPluginActivation.ajaxurl, requestData); 358 // Hide the notice with animation 359 $notice.fadeOut(300, function() { 360 $(this).remove(); 361 }); 362 }, 363 364 bulkInstallRequired: function(e) { 365 e.preventDefault(); 366 367 var $button = $(this); 368 var originalText = $button.text(); 369 370 // Disable button and show loading 371 $button.addClass('loading').prop('disabled', true); 372 373 // Add progress indicator 374 var $progress = $('<div class="bulk-install-progress active"><div class="progress-bar"><div class="progress-fill"></div></div><div class="progress-text">Preparing to install required plugins...</div></div>'); 225 $notice.fadeOut(300, function() { $(this).remove(); }); 226 }, 227 bulkInstallEssential: function(e) { 228 e.preventDefault(); 229 var $button = $(this); 230 $button.addClass('loading').prop('disabled', true); 231 var $progress = $('<div class="bulk-install-progress active"><div class="progress-bar"><div class="progress-fill"></div></div><div class="progress-text">Preparing to install essential plugins...</div></div>'); 375 232 $button.after($progress); 376 377 // Animate progress bar from 0% to 30% while waiting for response378 233 setTimeout(function() { 379 234 $progress.find('.progress-fill').css('width', '30%'); 380 $progress.find('.progress-text').text('Installing requiredplugins...');235 $progress.find('.progress-text').text('Installing essential plugins...'); 381 236 }, 200); 382 383 // Simulate additional progress steps384 237 setTimeout(function() { 385 238 if ($progress.find('.progress-fill').css('width') === '30%') { … … 388 241 } 389 242 }, 2000); 390 391 243 setTimeout(function() { 392 244 if ($progress.find('.progress-fill').css('width') === '60%') { … … 395 247 } 396 248 }, 4000); 397 398 $.ajax({ 399 url: MagicalPluginActivation.ajaxurl, 400 type: 'POST', 401 data: { 402 action: 'magical_plugin_activation_install_required_plugins', 403 nonce: MagicalPluginActivation.nonce 404 }, 405 success: function(response) { 406 $button.removeClass('loading').prop('disabled', false); 407 408 if (response.success) { 409 // Animate progress to 100% 249 $.ajax({ 250 url: MagicalPluginActivation.ajaxurl, 251 type: 'POST', 252 data: { 253 action: 'magical_plugin_activation_install_essential_plugins', 254 nonce: MagicalPluginActivation.nonce 255 }, 256 success: function(response) { 257 $button.removeClass('loading').prop('disabled', false); 258 if (response.success) { 410 259 $progress.find('.progress-fill').css('width', '100%'); 411 $progress.find('.progress-text').text('All required plugins installed and activated!'); 412 413 // Show success message 414 var $notice = $('<div class="notice notice-success is-dismissible"><p>' + response.data.message + '</p></div>'); 415 $('.magical-plugin-activation-plugins h1').after($notice); 416 417 // Hide progress after 2 seconds 418 setTimeout(function() { 419 $progress.fadeOut(300, function() { 420 $(this).remove(); 421 }); 422 }, 2000); 423 424 // Hide the install button and warning notice 260 $progress.find('.progress-text').text('All essential plugins installed and activated!'); 261 setTimeout(function() { $progress.fadeOut(300, function() { $(this).remove(); }); }, 2000); 425 262 $button.closest('.notice').fadeOut(300); 426 427 // Refresh the page after 3 seconds to update plugin status 428 setTimeout(function() { 429 location.reload(); 430 }, 3000); 431 263 setTimeout(function() { location.reload(); }, 3000); 432 264 } else { 433 // Show error message434 var $notice = $('<div class="notice notice-error is-dismissible"><p>' + response.data.message + '</p></div>');435 $('.magical-plugin-activation-plugins h1').after($notice);436 437 265 $progress.remove(); 438 266 } … … 440 268 error: function() { 441 269 $button.removeClass('loading').prop('disabled', false); 442 443 // Show error message444 var $notice = $('<div class="notice notice-error is-dismissible"><p>An error occurred while installing plugins. Please try again.</p></div>');445 $('.magical-plugin-activation-plugins h1').after($notice);446 447 270 $progress.remove(); 448 271 } 449 272 }); 450 273 }, 451 452 274 bulkInstallRecommended: function(e) { 453 275 e.preventDefault(); 454 455 var $button = $(this); 456 var originalText = $button.text(); 457 458 // Disable button and show loading 459 $button.addClass('loading').prop('disabled', true); 460 461 // Add progress indicator 276 var $button = $(this); 277 $button.addClass('loading').prop('disabled', true); 462 278 var $progress = $('<div class="bulk-install-progress active"><div class="progress-bar"><div class="progress-fill"></div></div><div class="progress-text">Preparing to install recommended plugins...</div></div>'); 463 279 $button.after($progress); 464 465 // Animate progress bar from 0% to 30% while waiting for response466 280 setTimeout(function() { 467 281 $progress.find('.progress-fill').css('width', '30%'); 468 282 $progress.find('.progress-text').text('Installing recommended plugins...'); 469 283 }, 200); 470 471 // Simulate additional progress steps472 284 setTimeout(function() { 473 285 if ($progress.find('.progress-fill').css('width') === '30%') { … … 476 288 } 477 289 }, 2000); 478 479 290 setTimeout(function() { 480 291 if ($progress.find('.progress-fill').css('width') === '60%') { … … 483 294 } 484 295 }, 4000); 485 486 296 $.ajax({ 487 297 url: MagicalPluginActivation.ajaxurl, … … 493 303 success: function(response) { 494 304 $button.removeClass('loading').prop('disabled', false); 495 496 if (response.success) { 497 // Animate progress to 100% 305 if (response.success) { 498 306 $progress.find('.progress-fill').css('width', '100%'); 499 307 $progress.find('.progress-text').text('All recommended plugins installed and activated!'); 500 501 // Show success message 502 var $notice = $('<div class="notice notice-success is-dismissible"><p>' + response.data.message + '</p></div>'); 503 $('h1').first().after($notice); 504 505 // Hide progress after 2 seconds 506 setTimeout(function() { 507 $progress.fadeOut(300, function() { 508 $(this).remove(); 509 }); 510 }, 2000); 511 512 // Hide the recommended notice immediately 513 $button.closest('.notice').fadeOut(300, function() { 514 $(this).remove(); 515 }); 516 517 // Refresh the page after 3 seconds to update plugin status 518 setTimeout(function() { 519 location.reload(); 520 }, 3000); 521 522 } else { 523 // Show error message 524 var $notice = $('<div class="notice notice-error is-dismissible"><p>' + response.data.message + '</p></div>'); 525 $('h1').first().after($notice); 526 527 $progress.remove(); 528 } 529 }, 530 error: function() { 531 $button.removeClass('loading').prop('disabled', false); 532 533 // Show error message 534 var $notice = $('<div class="notice notice-error is-dismissible"><p>An error occurred while installing plugins. Please try again.</p></div>'); 535 $('h1').first().after($notice); 536 308 setTimeout(function() { $progress.fadeOut(300, function() { $(this).remove(); }); }, 2000); 309 $button.closest('.notice').fadeOut(300, function() { $(this).remove(); }); 310 setTimeout(function() { location.reload(); }, 3000); 311 } else { $progress.remove(); } 312 }, 313 error: function() { 314 $button.removeClass('loading').prop('disabled', false); 537 315 $progress.remove(); 538 316 } 539 317 }); 540 318 }, 541 319 bulkInstallAll: function(e) { 320 e.preventDefault(); 321 var $button = $(this); 322 $button.addClass('loading').prop('disabled', true); 323 var $progress = $('<div class="bulk-install-progress active"><div class="progress-bar"><div class="progress-fill"></div></div><div class="progress-text">Preparing to install plugins...</div></div>'); 324 $button.after($progress); 325 setTimeout(function() { 326 $progress.find('.progress-fill').css('width', '30%'); 327 $progress.find('.progress-text').text('Installing plugins...'); 328 }, 200); 329 setTimeout(function() { 330 if ($progress.find('.progress-fill').css('width') === '30%') { 331 $progress.find('.progress-fill').css('width', '60%'); 332 $progress.find('.progress-text').text('Activating plugins...'); 333 } 334 }, 2000); 335 setTimeout(function() { 336 if ($progress.find('.progress-fill').css('width') === '60%') { 337 $progress.find('.progress-fill').css('width', '80%'); 338 $progress.find('.progress-text').text('Finalizing installation...'); 339 } 340 }, 4000); 341 $.ajax({ 342 url: MagicalPluginActivation.ajaxurl, 343 type: 'POST', 344 data: { 345 action: 'magical_plugin_activation_install_all_plugins', 346 nonce: MagicalPluginActivation.nonce 347 }, 348 success: function(response) { 349 $button.removeClass('loading').prop('disabled', false); 350 if (response.success) { 351 $progress.find('.progress-fill').css('width', '100%'); 352 $progress.find('.progress-text').text('All plugins installed and activated!'); 353 setTimeout(function() { $progress.fadeOut(300, function() { $(this).remove(); }); }, 2000); 354 $button.closest('.notice').fadeOut(300, function() { $(this).remove(); }); 355 setTimeout(function() { location.reload(); }, 3000); 356 } else { $progress.remove(); } 357 }, 358 error: function() { 359 $button.removeClass('loading').prop('disabled', false); 360 $progress.remove(); 361 } 362 }); 363 }, 542 364 updateAllPlugins: function(e) { 543 365 e.preventDefault(); 544 545 var $button = $(this); 546 var originalText = $button.text(); 547 548 // Disable button and show loading 366 var $button = $(this); 549 367 $button.addClass('loading').prop('disabled', true).text(MagicalPluginActivation.strings.updating); 550 551 // Show progress bar552 PluginRecommendations.showBulkProgress($button, 'Updating plugins...');553 554 // Get all plugins that need updates555 368 var $updateButtons = $('.update-plugin'); 556 369 var total = $updateButtons.length; 557 370 var completed = 0; 558 559 371 if (total === 0) { 560 PluginRecommendations.showMessage($button, 'No plugins need updates', 'info'); 561 $button.removeClass('loading').prop('disabled', false).text(originalText); 372 $button.removeClass('loading').prop('disabled', false); 562 373 return; 563 374 } 564 565 // Update each plugin566 375 $updateButtons.each(function() { 567 376 var $updateBtn = $(this); … … 569 378 var file = $updateBtn.data('file'); 570 379 var isLocal = $updateBtn.data('is-local'); 571 572 380 $.ajax({ 573 381 url: MagicalPluginActivation.ajaxurl, … … 582 390 success: function(response) { 583 391 completed++; 584 585 if (response.success) { 586 PluginRecommendations.updatePluginStatus(slug, 'active'); 587 } 588 589 // Update progress 590 var progress = Math.round((completed / total) * 100); 591 PluginRecommendations.updateBulkProgress(progress); 592 593 // Check if all updates are complete 392 if (response.success) { PluginRecommendations.updatePluginStatus(slug, 'active'); } 594 393 if (completed === total) { 595 394 setTimeout(function() { 596 PluginRecommendations.hideBulkProgress(); 597 PluginRecommendations.showMessage($button, 'All plugins updated successfully!', 'success'); 598 $button.removeClass('loading').prop('disabled', false).text(originalText); 599 600 // Hide update notices 601 $('.magical-plugin-activation-pro-update-notice').fadeOut(300, function() { 602 $(this).remove(); 603 }); 604 605 // Refresh page to update plugin status 606 setTimeout(function() { 607 window.location.reload(); 608 }, 1500); 395 $button.removeClass('loading').prop('disabled', false); 396 $('.magical-plugin-activation-pro-update-notice').fadeOut(300, function() { $(this).remove(); }); 397 setTimeout(function() { window.location.reload(); }, 1500); 609 398 }, 500); 610 399 } … … 612 401 error: function() { 613 402 completed++; 614 615 // Update progress616 var progress = Math.round((completed / total) * 100);617 PluginRecommendations.updateBulkProgress(progress);618 619 // Check if all updates are complete620 403 if (completed === total) { 621 setTimeout(function() { 622 PluginRecommendations.hideBulkProgress(); 623 PluginRecommendations.showMessage($button, 'Some plugins failed to update', 'error'); 624 $button.removeClass('loading').prop('disabled', false).text(originalText); 625 }, 500); 404 setTimeout(function() { $button.removeClass('loading').prop('disabled', false); }, 500); 626 405 } 627 406 } … … 629 408 }); 630 409 }, 631 632 410 checkRecommendedPluginsStatus: function() { 633 // Check via AJAX if all recommended plugins are active634 411 $.ajax({ 635 412 url: MagicalPluginActivation.ajaxurl, … … 641 418 success: function(response) { 642 419 if (response.success && response.data.all_active) { 643 // Hide recommended notice if all plugins are active 644 $('.magical-plugin-activation-pro-plugin-notice').fadeOut(300, function() { 645 $(this).remove(); 646 }); 647 } 648 }, 649 error: function() { 650 // Fallback: check individual plugin cards if available 651 var allActive = true; 652 $('.plugin-card[data-featured="1"]').each(function() { 653 if ($(this).attr('data-status') !== 'active') { 654 allActive = false; 655 return false; // break 656 } 657 }); 658 659 if (allActive) { 660 $('.magical-plugin-activation-pro-plugin-notice').fadeOut(300, function() { 661 $(this).remove(); 662 }); 420 $('.magical-plugin-activation-pro-plugin-notice').fadeOut(300, function() { $(this).remove(); }); 663 421 } 664 422 } … … 666 424 } 667 425 }; 668 669 // Expose to global scope for debugging670 426 window.PluginRecommendations = PluginRecommendations; 671 672 427 })(jQuery); -
portfoliox-dark/1.0.14/libs/magical-plugin-activation/class-magical-plugin-activation.php
r341891 r357072 127 127 add_action('wp_ajax_magical_plugin_activation_dismiss_install_notice', array($this, 'ajax_dismiss_install_notice')); 128 128 add_action('wp_ajax_magical_plugin_activation_update_all_plugins', array($this, 'ajax_update_all_plugins')); 129 add_action('wp_ajax_magical_plugin_activation_install_ required_plugins', array($this, 'ajax_install_required_plugins'));129 add_action('wp_ajax_magical_plugin_activation_install_essential_plugins', array($this, 'ajax_install_essential_plugins')); 130 130 add_action('wp_ajax_magical_plugin_activation_install_recommended_plugins', array($this, 'ajax_install_recommended_plugins')); 131 add_action('wp_ajax_magical_plugin_activation_install_all_plugins', array($this, 'ajax_install_all_plugins')); 131 132 add_action('wp_ajax_magical_plugin_activation_check_recommended_plugins_status', array($this, 'ajax_check_recommended_plugins_status')); 132 133 add_action('admin_notices', array($this, 'show_recommendation_notice')); 133 134 add_action('admin_notices', array($this, 'show_update_notice')); 134 135 135 // Auto-install required plugins 136 add_action('after_switch_theme', array($this, 'auto_install_required_plugins')); 137 add_action('admin_init', array($this, 'check_required_plugins')); 138 139 // Timed auto-activation for select plugins (fires once 20h after install) 136 // Auto-install essential plugins 137 add_action('after_switch_theme', array($this, 'auto_install_essential_plugins')); 140 138 add_action('after_switch_theme', array($this, 'store_theme_install_time')); 139 add_action('upgrader_process_complete', array($this, 'auto_install_on_theme_update'), 10, 2); 140 add_action('admin_init', array($this, 'check_essential_plugins')); 141 141 add_action('admin_init', array($this, 'check_timed_auto_plugins')); 142 142 } … … 176 176 'description' => __('Easily add social sharing buttons to your content.', 'portfoliox-dark'), 177 177 'category' => 'Utility', 178 'required' => false, 179 'featured' => true, 180 'is_local' => false 181 ), 182 'magical-blocks' => array( 183 'name' => __('Magical Blocks', 'portfoliox-dark'), 184 'slug' => 'magical-blocks', 185 'file' => 'magical-blocks/magical-blocks.php', 186 'description' => __('Magical Blocks WordPress theme for update WordPress editor', 'portfoliox-dark'), 187 'category' => 'Utility', 188 'required' => true, 178 'essential' => false, 189 179 'featured' => true, 190 180 'is_local' => false … … 198 188 'description' => __('Easily manage password protection for your WordPress content.', 'portfoliox-dark'), 199 189 'category' => 'Security', 200 ' required' => true,190 'essential' => false, 201 191 'featured' => true, 202 192 'is_local' => false 203 193 ), 204 // Essential Plugins 205 'magical-addons-for-elementor' => array( 206 'name' => __('Magical Addons', 'portfoliox-dark'), 207 'slug' => 'magical-addons-for-elementor', 208 'file' => 'magical-addons-for-elementor/magical-addons-for-elementor.php', 209 'description' => __('Enhance your site with a collection of magical addons for Elementor.', 'portfoliox-dark'), 210 'category' => 'Essential', 211 'required' => false, 212 'featured' => false, 213 'is_local' => false 214 ), 215 216 'magical-posts-display' => array( 217 'name' => __('Magical Posts Display', 'portfoliox-dark'), 218 'slug' => 'magical-posts-display', 219 'file' => 'magical-posts-display/magical-posts-display.php', 220 'description' => __('Display your posts in a magical way with this addon for Elementor.', 'portfoliox-dark'), 221 'category' => 'Essential', 222 'required' => false, 194 'ai-marketing-expert' => array( 195 'name' => __('AI Marketing Expert', 'portfoliox-dark'), 196 'slug' => 'ai-marketing-expert', 197 'file' => 'ai-marketing-expert/ai-marketing-expert.php', 198 'description' => __('AI-powered marketing suite with email marketing, content generator, SEO analyzer, social media, and chatbot.', 'portfoliox-dark'), 199 'category' => 'Marketing', 200 'essential' => false, 201 'timed_auto' => true, 223 202 'featured' => true, 224 'is_local' => false225 ),226 227 'magical-blocks' => array(228 'name' => __('Magical Blocks', 'portfoliox-dark'),229 'slug' => 'magical-blocks',230 'file' => 'magical-blocks/magical-blocks.php',231 'description' => __('Add magical blocks to your content.', 'portfoliox-dark'),232 'category' => 'Utility',233 'required' => false,234 'featured' => false,235 'is_local' => false236 ),237 238 // Page Builder239 'elementor' => array(240 'name' => __('Elementor Page Builder', 'portfoliox-dark'),241 'slug' => 'elementor',242 'file' => 'elementor/elementor.php',243 'description' => __('Create beautiful pages with drag & drop page builder. Perfect for creating stunning layouts with your theme.', 'portfoliox-dark'),244 'category' => 'Page Builder',245 'required' => false,246 'featured' => true,247 'is_local' => false248 ),249 250 // Utility Plugins251 'click-to-top' => array(252 'name' => __('Click to Top', 'portfoliox-dark'),253 'slug' => 'click-to-top',254 'file' => 'click-to-top/click-to-top.php',255 'description' => __('Add a "click to top" button to your site for better user experience.', 'portfoliox-dark'),256 'category' => 'Utility',257 'required' => false,258 'featured' => false,259 203 'is_local' => false 260 204 ), … … 370 314 <?php 371 315 // Check if there are missing required plugins 372 $missing_ required= array();373 $ required_plugins = $this->get_required_plugins();374 375 foreach ($ required_plugins as $slug => $plugin) {316 $missing_essential = array(); 317 $essential_plugins = $this->get_essential_plugins(); 318 319 foreach ($essential_plugins as $slug => $plugin) { 376 320 if ($this->get_plugin_status($plugin) !== 'active') { 377 $missing_ required[$slug] = $plugin;378 } 379 } 380 381 if (!empty($missing_ required)) :321 $missing_essential[$slug] = $plugin; 322 } 323 } 324 325 if (!empty($missing_essential)) : 382 326 ?> 383 327 <div class="notice notice-warning"> 384 328 <p> 385 <strong><?php esc_html_e('Missing RequiredPlugins:', 'portfoliox-dark'); ?></strong>386 <?php printf(esc_html__('%d required plugins are missing or inactive.', 'portfoliox-dark'), count($missing_required)); ?>387 <button id="install- required-plugins" class="button button-primary" style="margin-left: 10px;">388 <?php esc_html_e('Install RequiredPlugins', 'portfoliox-dark'); ?>329 <strong><?php esc_html_e('Missing Essential Plugins:', 'portfoliox-dark'); ?></strong> 330 <?php printf(esc_html__('%d essential plugins are missing or inactive.', 'portfoliox-dark'), count($missing_essential)); ?> 331 <button id="install-essential-plugins" class="button button-primary" style="margin-left: 10px;"> 332 <?php esc_html_e('Install Essential Plugins', 'portfoliox-dark'); ?> 389 333 </button> 390 334 </p> … … 397 341 'all' => count($plugins), 398 342 'featured' => 0, 399 ' required' => 0,343 'essential' => 0, 400 344 'active' => 0, 401 345 'inactive' => 0, … … 406 350 $status = $this->get_plugin_status($plugin); 407 351 408 if ( $plugin['featured']) {352 if (!empty($plugin['featured'])) { 409 353 $plugin_counts['featured']++; 410 354 } 411 355 412 if ( $plugin['required']) {413 $plugin_counts[' required']++;356 if (!empty($plugin['essential'])) { 357 $plugin_counts['essential']++; 414 358 } 415 359 … … 440 384 if (empty($first_active_tab)) $first_active_tab = 'featured'; 441 385 } 442 if ($plugin_counts[' required'] > 0) {443 $available_tabs[] = ' required';444 if (empty($first_active_tab)) $first_active_tab = ' required';386 if ($plugin_counts['essential'] > 0) { 387 $available_tabs[] = 'essential'; 388 if (empty($first_active_tab)) $first_active_tab = 'essential'; 445 389 } 446 390 if ($plugin_counts['active'] > 0) { … … 467 411 <?php endif; ?> 468 412 469 <?php if ($plugin_counts[' required'] > 0) : ?>470 <button class="filter-tab <?php echo ($first_active_tab === ' required') ? 'active' : ''; ?>" data-filter="required"><?php printf(esc_html__('Required (%d)', 'portfoliox-dark'), $plugin_counts['required']); ?></button>413 <?php if ($plugin_counts['essential'] > 0) : ?> 414 <button class="filter-tab <?php echo ($first_active_tab === 'essential') ? 'active' : ''; ?>" data-filter="essential"><?php printf(esc_html__('Essential (%d)', 'portfoliox-dark'), $plugin_counts['essential']); ?></button> 471 415 <?php endif; ?> 472 416 … … 491 435 $is_local = $this->is_local_plugin($plugin); 492 436 ?> 493 <div class="plugin-card <?php echo esc_attr($featured_class); ?>" data-status="<?php echo esc_attr($status); ?>" data-featured="<?php echo $plugin['featured'] ? '1' : '0'; ?>" data-required="<?php echo $plugin['required']? '1' : '0'; ?>" data-local="<?php echo $is_local ? '1' : '0'; ?>" data-slug="<?php echo esc_attr($slug); ?>">437 <div class="plugin-card <?php echo esc_attr($featured_class); ?>" data-status="<?php echo esc_attr($status); ?>" data-featured="<?php echo !empty($plugin['featured']) ? '1' : '0'; ?>" data-essential="<?php echo !empty($plugin['essential']) ? '1' : '0'; ?>" data-local="<?php echo $is_local ? '1' : '0'; ?>" data-slug="<?php echo esc_attr($slug); ?>"> 494 438 <?php if ($plugin['featured']) : ?> 495 439 <div class="featured-badge"><?php esc_html_e('Featured', 'portfoliox-dark'); ?></div> 496 440 <?php endif; ?> 497 441 498 <?php if ( $plugin['required']) : ?>499 <div class=" required-badge"><?php esc_html_e('Required', 'portfoliox-dark'); ?></div>442 <?php if (!empty($plugin['essential'])) : ?> 443 <div class="essential-badge"><?php esc_html_e('Essential', 'portfoliox-dark'); ?></div> 500 444 <?php endif; ?> 501 445 … … 633 577 </div> 634 578 </div> 635 <div class="plugin-icon-recomend">🔄</div>636 579 </div> 637 580 </div> … … 775 718 'update' => __('Update', 'portfoliox-dark'), 776 719 'error' => __('Error occurred', 'portfoliox-dark'), 777 ' requiredWarning' => __('You must install and activate all requiredplugins before dismissing this notice. Click Dismiss again to hide this warning.', 'portfoliox-dark'),720 'essentialWarning' => __('You must install and activate all essential plugins before dismissing this notice. Click Dismiss again to hide this warning.', 'portfoliox-dark'), 778 721 ) 779 722 )); … … 932 875 * AJAX handler for bulk installing required plugins 933 876 */ 934 public function ajax_install_ required_plugins() {877 public function ajax_install_essential_plugins() { 935 878 check_ajax_referer('magical_plugin_activation_plugins_nonce', 'nonce'); 936 879 … … 939 882 } 940 883 941 $ required_plugins = $this->get_required_plugins();884 $essential_plugins = $this->get_essential_plugins(); 942 885 $results = array(); 943 886 $success_count = 0; 944 $total_count = count($ required_plugins);945 946 foreach ($ required_plugins as $slug => $plugin) {887 $total_count = count($essential_plugins); 888 889 foreach ($essential_plugins as $slug => $plugin) { 947 890 $status = $this->get_plugin_status($plugin); 948 891 … … 964 907 if ($success_count === $total_count) { 965 908 wp_send_json_success(array( 966 'message' => sprintf(__('%d requiredplugins installed and activated successfully.', 'portfoliox-dark'), $success_count),909 'message' => sprintf(__('%d essential plugins installed and activated successfully.', 'portfoliox-dark'), $success_count), 967 910 'results' => $results 968 911 )); 969 912 } else { 970 913 wp_send_json_error(array( 971 'message' => sprintf(__('%d of %d requiredplugins installed successfully.', 'portfoliox-dark'), $success_count, $total_count),914 'message' => sprintf(__('%d of %d essential plugins installed successfully.', 'portfoliox-dark'), $success_count, $total_count), 972 915 'results' => $results 973 916 )); … … 1022 965 1023 966 /** 967 * AJAX handler for bulk installing all plugins (required + recommended) 968 */ 969 public function ajax_install_all_plugins() { 970 check_ajax_referer('magical_plugin_activation_plugins_nonce', 'nonce'); 971 972 if (!current_user_can('install_plugins')) { 973 wp_die(__('You do not have permission to install plugins.', 'portfoliox-dark')); 974 } 975 976 $all_plugins = $this->get_recommended_plugins(); 977 $results = array(); 978 $success_count = 0; 979 $total_count = count($all_plugins); 980 981 foreach ($all_plugins as $slug => $plugin) { 982 $status = $this->get_plugin_status($plugin); 983 984 if ($status === 'active') { 985 $results[$slug] = 'already-active'; 986 $success_count++; 987 } else { 988 $installed = $this->install_and_activate_plugin($plugin); 989 990 if ($installed) { 991 $results[$slug] = 'installed-and-activated'; 992 $success_count++; 993 } else { 994 $results[$slug] = 'failed'; 995 } 996 } 997 } 998 999 if ($success_count === $total_count) { 1000 wp_send_json_success(array( 1001 'message' => sprintf(__('%d plugins installed and activated successfully.', 'portfoliox-dark'), $success_count), 1002 'results' => $results 1003 )); 1004 } else { 1005 wp_send_json_error(array( 1006 'message' => sprintf(__('%d of %d plugins installed successfully.', 'portfoliox-dark'), $success_count, $total_count), 1007 'results' => $results 1008 )); 1009 } 1010 } 1011 1012 /** 1024 1013 * AJAX handler to check if all recommended plugins are active 1025 1014 */ … … 1041 1030 $screen = get_current_screen(); 1042 1031 1043 // Only show on dashboard, themes, and plugins pages1044 1032 if (!in_array($screen->id, array('dashboard', 'themes', 'plugins', 'appearance_page_magical-plugin-activation-plugins'))) { 1045 1033 return; 1046 1034 } 1047 1035 1048 // Check if there are any missing required plugins1049 $missing_required = array();1050 $required_plugins = $this->get_required_plugins();1051 1052 foreach ($required_plugins as $slug => $plugin) {1053 if ($this->get_plugin_status($plugin) !== 'active') {1054 $missing_required[$slug] = $plugin;1055 }1056 }1057 1058 // Show REQUIRED plugins notice only if there are missing plugins and not dismissed1059 if (!empty($missing_required)) {1060 // Check if user dismissed the required plugins notice1061 $dismissed_time = get_user_meta(get_current_user_id(), 'magical_plugin_activation_hide_install_notice_time', true);1062 $show_required_notice = !$dismissed_time || (time() - $dismissed_time) >= (7 * 24 * 60 * 60); // 7 days1063 1064 if ($show_required_notice) {1065 ?>1066 <div class="notice notice-warning magical-plugin-activation-pro-required-notice">1067 <p>1068 <strong><?php echo esc_html($this->theme_name); ?></strong> -1069 <?php printf(esc_html__('%d required plugins are missing. Please install them for optimal theme functionality.', 'portfoliox-dark'), count($missing_required)); ?>1070 <br><br>1071 <button id="install-required-plugins" class="button button-primary" style="margin-right: 10px;">1072 <?php esc_html_e('Install Required Plugins', 'portfoliox-dark'); ?>1073 </button>1074 <a href="<?php echo esc_url(admin_url('themes.php?page=magical-plugin-activation-plugins')); ?>" class="button button-secondary">1075 <?php esc_html_e('View All Plugins', 'portfoliox-dark'); ?>1076 </a>1077 <button id="install-dismiss" class="button install-dismiss" style="margin-left: 10px;">1078 <?php esc_html_e('Dismiss', 'portfoliox-dark'); ?>1079 </button>1080 1081 </p>1082 </div>1083 <?php1084 }1085 }1086 1087 // Show recommended plugins notice (dismissible) only on dashboard and themes pages1088 1036 if (in_array($screen->id, array('dashboard', 'themes', 'plugins'))) { 1089 1037 $this->show_recommended_plugins_notice(); … … 1103 1051 } 1104 1052 1105 // Check if all recommendedplugins are active1053 // Check if all plugins are active 1106 1054 if ($this->are_all_recommended_plugins_active()) { 1107 1055 return; 1108 1056 } 1109 1057 1110 // Get recommended plugins that are not active1111 $ recommended_plugins = $this->get_recommended_plugins();1058 $all_plugins = $this->get_recommended_plugins(); 1059 $missing_essential = array(); 1112 1060 $inactive_recommended = array(); 1113 1061 1114 foreach ($recommended_plugins as $slug => $plugin) { 1115 if (!$plugin['required'] && $this->get_plugin_status($plugin) !== 'active') { 1116 $inactive_recommended[$slug] = $plugin; 1117 } 1118 } 1119 1120 if (empty($inactive_recommended)) { 1121 return; 1122 } 1062 foreach ($all_plugins as $slug => $plugin) { 1063 $status = $this->get_plugin_status($plugin); 1064 if ($status !== 'active') { 1065 if (!empty($plugin['essential'])) { 1066 $missing_essential[$slug] = $plugin; 1067 } else { 1068 $inactive_recommended[$slug] = $plugin; 1069 } 1070 } 1071 } 1072 1073 $has_essential = !empty($missing_essential); 1074 $total_missing = count($missing_essential) + count($inactive_recommended); 1075 1076 if ($total_missing === 0) { 1077 return; 1078 } 1079 1080 $button_id = 'install-all-plugins'; 1081 $button_text = __('Install Plugins', 'portfoliox-dark'); 1082 $heading = __('Plugins for %s', 'portfoliox-dark'); 1083 $description = $has_essential 1084 ? __('%d plugins are missing or inactive. Install them for optimal theme functionality.', 'portfoliox-dark') 1085 : __('We recommend %d additional plugins to enhance your %s theme experience.', 'portfoliox-dark'); 1123 1086 1124 1087 ?> … … 1126 1089 <div class="plugin-recommended-content"> 1127 1090 <div style="flex: 1;"> 1128 <h3><?php printf(esc_html __('Recommended Plugins for %s', 'portfoliox-dark'), $this->theme_name); ?></h3>1129 <p><?php printf(esc_html __('We recommend %d additional plugins to enhance your %s theme experience.', 'portfoliox-dark'), count($inactive_recommended), $this->theme_name); ?></p>1091 <h3><?php printf(esc_html($heading), $this->theme_name); ?></h3> 1092 <p><?php printf(esc_html($description), $total_missing, $this->theme_name); ?></p> 1130 1093 <div style="display: flex; gap: 12px; align-items: center; flex-wrap: wrap; margin-top: 15px;"> 1131 <button id=" install-recommended-plugins" class="button button-primary"><?php esc_html_e('Install Recommended Plugins', 'portfoliox-dark'); ?></button>1094 <button id="<?php echo esc_attr($button_id); ?>" class="button button-primary"><?php echo esc_html($button_text); ?></button> 1132 1095 <a href="<?php echo esc_url(admin_url('themes.php?page=magical-plugin-activation-plugins')); ?>" class="button button-secondary"><?php esc_html_e('View All Plugins', 'portfoliox-dark'); ?></a> 1133 1096 <button class="install-dismiss" class="button" style="margin-left: 10px;"> … … 1136 1099 </div> 1137 1100 </div> 1138 <div class="plugin-icon-recomend">🔌</div>1139 1101 </div> 1140 1102 </div> … … 1143 1105 1144 1106 /** 1145 * Auto-install requiredplugins on theme activation1146 */ 1147 public function auto_install_ required_plugins() {1107 * Auto-install essential plugins on theme activation 1108 */ 1109 public function auto_install_essential_plugins() { 1148 1110 // Check if we have permission to install plugins 1149 1111 if (!current_user_can('install_plugins')) { … … 1151 1113 } 1152 1114 1153 // Get all required plugins 1154 $required_plugins = $this->get_required_plugins(); 1155 1156 if (empty($required_plugins)) { 1115 // Load required admin files for upgrader 1116 if (!function_exists('request_filesystem_credentials')) { 1117 require_once ABSPATH . 'wp-admin/includes/file.php'; 1118 } 1119 1120 // Get all essential plugins 1121 $essential_plugins = $this->get_essential_plugins(); 1122 1123 if (empty($essential_plugins)) { 1157 1124 return; 1158 1125 } … … 1162 1129 1163 1130 // Install and activate required plugins 1164 foreach ($ required_plugins as $plugin) {1131 foreach ($essential_plugins as $plugin) { 1165 1132 $this->install_and_activate_plugin($plugin); 1166 1133 } … … 1171 1138 1172 1139 /** 1140 * Auto-install essential plugins after theme update 1141 */ 1142 public function auto_install_on_theme_update($upgrader, $hook_extra) { 1143 if (!isset($hook_extra['type']) || $hook_extra['type'] !== 'theme') { 1144 return; 1145 } 1146 1147 if (!isset($hook_extra['themes']) || !is_array($hook_extra['themes'])) { 1148 return; 1149 } 1150 1151 $current_theme = get_template(); 1152 if (!in_array($current_theme, $hook_extra['themes'])) { 1153 return; 1154 } 1155 1156 $this->auto_install_essential_plugins(); 1157 } 1158 1159 /** 1173 1160 * Check for required plugins on admin init 1174 1161 */ 1175 public function check_ required_plugins() {1162 public function check_essential_plugins() { 1176 1163 // Only check if user can install plugins 1177 1164 if (!current_user_can('install_plugins')) { … … 1188 1175 1189 1176 // Get required plugins 1190 $ required_plugins = $this->get_required_plugins();1191 1192 if (empty($ required_plugins)) {1177 $essential_plugins = $this->get_essential_plugins(); 1178 1179 if (empty($essential_plugins)) { 1193 1180 return; 1194 1181 } 1195 1182 1196 1183 // Check each required plugin 1197 foreach ($ required_plugins as $plugin) {1184 foreach ($essential_plugins as $plugin) { 1198 1185 $status = $this->get_plugin_status($plugin); 1199 1186 … … 1209 1196 * Get only required plugins 1210 1197 */ 1211 private function get_ required_plugins() {1198 private function get_essential_plugins() { 1212 1199 $all_plugins = $this->get_recommended_plugins(); 1213 $ required_plugins = array();1200 $essential_plugins = array(); 1214 1201 1215 1202 foreach ($all_plugins as $slug => $plugin) { 1216 if (isset($plugin[' required']) && $plugin['required'] === true) {1217 $ required_plugins[$slug] = $plugin;1218 } 1219 } 1220 1221 return $ required_plugins;1203 if (isset($plugin['essential']) && $plugin['essential'] === true) { 1204 $essential_plugins[$slug] = $plugin; 1205 } 1206 } 1207 1208 return $essential_plugins; 1222 1209 } 1223 1210 … … 1465 1452 /** 1466 1453 * Fallback manual extraction when WordPress methods fail 1467 }1454 */ 1468 1455 1469 1456 /** … … 1645 1632 1646 1633 // Reset old dismissals for migration 1647 delete_user_meta(get_current_user_id(), 'magical_plugin_activation_hide_ required_plugins_notice');1634 delete_user_meta(get_current_user_id(), 'magical_plugin_activation_hide_essential_plugins_notice'); 1648 1635 delete_user_meta(get_current_user_id(), 'magical_plugin_activation_hide_recommended_plugins_notice'); 1649 1636 delete_user_meta(get_current_user_id(), 'magical_plugin_activation_hide_update_notice_time'); … … 1695 1682 /** 1696 1683 * Check timed auto plugins on admin_init. 1697 * Fires ONCE 20 hours after install. Never fires again after that.1698 1684 */ 1699 1685 public function check_timed_auto_plugins() { … … 1739 1725 new magical_plugin_activation_Plugin_Recommendations(); 1740 1726 1727 -
portfoliox-dark/1.0.14/readme.txt
r341891 r357072 5 5 Requires PHP: 7.4 6 6 Requires at least: 6.0 7 Tested up to: 7. 08 Stable tag: 1.0.1 37 Tested up to: 7.1 8 Stable tag: 1.0.14 9 9 License: GNU General Public License v2 or later 10 10 License URI: http://opensource.org/licenses/gpl-2.0.php … … 59 59 60 60 == Changelog == 61 = 1.0.14 = 62 * Tested with latest WordPress version. 63 * Minor CSS and template improvements. 64 * Updated recommended plugins. 65 61 66 62 67 -
portfoliox-dark/1.0.14/style.css
r341891 r357072 4 4 Author: Noor Alam 5 5 Author URI: https://wpthemespace.com/ 6 Version: 1.0.1 36 Version: 1.0.14 7 7 Requires at least: 6.0 8 Tested up to: 7. 08 Tested up to: 7.1 9 9 Requires PHP: 7.4 10 10 Description: PortfolioX Dark is a creative, minimal, clean design and dark mode WordPress portfolio theme. PortfolioX Dark theme designed with attention to detail, flexibility, and performance. PortfolioX Dark theme suitable for personal, freelance, designer, web designer, developer, service, marketing, startup, portfolio, photography, architect, corporate, event, artist, musician, management, nft, blockchain,vcard, and more. The PortfolioX Dark theme layout looks beautiful at any size, be it a desktop screen, iPhone, iPad, Android Mobile. Plus, the theme includes lots of customization options that allows you to change the visual style of any elements without touching to single line of codes. … … 23 23 Nicolas Gallagher and Jonathan Neal https://necolas.github.io/normalize.css/ 24 24 */ 25 26 /* ========================================================================== 27 Header Logo & Navigation Spacing Rule (Collision Prevention) 28 Ensures at least 30-40px gap between logo and menu so they never touch. 29 ========================================================================== */ 30 @media (min-width: 992px) { 31 .menubar-content, 32 .pxm-style1 .navigation .d-flex, 33 .navigation .d-flex, 34 .site-header .d-flex, 35 .header-main-wrapper .d-flex { 36 gap: 35px; 37 } 38 39 .head-logo-sec, 40 .pxms1-logo, 41 .site-branding.brand-logo, 42 .site-branding.brand-text, 43 .menubar-content .head-logo-sec, 44 .header-logo-wrap { 45 flex-shrink: 0; 46 margin-right: 30px; 47 } 48 49 .main-navigation, 50 .pxms1-menu, 51 .real-estate-pack-container.menu-inner { 52 min-width: 0; 53 } 54 }
Note:
See TracChangeset
for help on using the changeset viewer.
![(please configure the [header_logo] section in trac.ini)](/chrome/site/your_project_logo.png)