PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.0.29
Post Grid Gutenberg Blocks – PostX v5.0.29
5.0.41 5.0.39 5.0.38 5.0.37 5.0.36 5.0.35 5.0.34 5.0.33 5.0.32 5.0.31 5.0.30 5.0.29 5.0.28 5.0.27 5.0.26 5.0.25 5.0.23 5.0.24 5.0.22 5.0.21 5.0.20 5.0.19 5.0.18 5.0.17 2.1.1 All 238 releases
ultimate-post / includes / notice / class-wow-addons-promotion.php

class-wow-addons-promotion.php in Post Grid Gutenberg Blocks – PostX 5.0.29, at includes/notice/class-wow-addons-promotion.php

988 lines 25.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php // phpcs:ignore
2 /**
3 * Initialization Action.
4 *
5 * @package ULTP // CHANGE THIS.
6 */
7 namespace ULTP\Includes\Notice; // CHANGE THIS.
8
9 defined( 'ABSPATH' ) || exit;
10
11 /**
12 * Initialization class.
13 */
14 class WowAddonsPromotion {
15
16 private const VERSION = '20'; // Cache buster.
17 private const PRODUCTS_MENU_SLUG = 'prad-promo-products-options';
18 private const PROMOTED_PLUGIN_SLUG = 'product-addons';
19 private const PROMOTED_PLUGIN_FILE = 'product-addons/product-addons.php';
20
21 /**
22 * Setup class.
23 */
24 public function __construct() {
25 add_filter( 'prad_promo_promotion_hooks', array( $this, 'load' ) );
26 add_action( 'plugins_loaded', array( $this, 'run_promotions' ) );
27 }
28
29 /**
30 * Run promotions.
31 *
32 * @return void
33 */
34 public function run_promotions() {
35 $is_active = ultimate_post()->is_lc_active();
36 if ( $is_active || ! class_exists( '\WooCommerce' ) ||
37 defined( 'PRAD_VER' )
38 ) {
39 return;
40 }
41
42 if ( $GLOBALS['prad_promo_promotion']['init'] ?? false ) {
43 return;
44 }
45
46 $GLOBALS['prad_promo_promotion'] = array(
47 'init' => true,
48 );
49
50 $hooks = apply_filters( 'prad_promo_promotion_hooks', array() );
51
52 if ( ! is_array( $hooks ) ) {
53 return;
54 }
55
56 uksort( $hooks, 'version_compare' );
57
58 $latest_hook = end( $hooks );
59
60 if ( is_callable( $latest_hook ) ) {
61 $latest_hook();
62 }
63 }
64
65 /**
66 * Load plugin
67 *
68 * @param array $callbacks Callbacks.
69 * @return array
70 */
71 public function load( $callbacks ) {
72
73 if ( isset( $callbacks[ self::VERSION ] ) ) {
74 return $callbacks;
75 }
76
77 $callbacks[ self::VERSION ] = function () {
78 // Dismiss actions.
79 add_action( 'wp_ajax_prad_promo_dismiss_promotion', array( $this, 'ajax_dismiss_promotion' ) );
80 add_action( 'wp_ajax_prad_promo_install_promotion_plugin', array( $this, 'ajax_install_promotion_plugin' ) );
81
82 // Promotions.
83 // ------------------.
84
85 // Add Options Tab.
86 add_filter( 'woocommerce_product_data_tabs', array( $this, 'register_product_options_tab' ), 999 );
87 add_action( 'woocommerce_product_data_panels', array( $this, 'render_product_options_panel' ) );
88
89 // Variation tab notice.
90 add_action( 'woocommerce_product_data_panels', array( $this, 'render_variations_notice' ) );
91
92 // Products submenu modal.
93 add_action( 'admin_menu', array( $this, 'add_products_submenu' ), 9999 );
94 add_action( 'admin_footer', array( $this, 'render_products_submenu_modal' ) );
95 };
96
97 return $callbacks;
98 }
99
100 /**
101 * Add the promotional submenu item under Products.
102 *
103 * @return void
104 */
105 public function add_products_submenu() {
106 add_submenu_page(
107 'woocommerce',
108 'Products Options',
109 'Products Options',
110 'edit_posts',
111 self::PRODUCTS_MENU_SLUG,
112 '__return_null',
113 6
114 );
115
116 add_submenu_page(
117 'edit.php?post_type=product',
118 'Products Options',
119 'Products Options',
120 'edit_posts',
121 self::PRODUCTS_MENU_SLUG,
122 '__return_null',
123 6
124 );
125 }
126
127 /**
128 * Register a promotion tab in the WooCommerce product data metabox.
129 *
130 * @param array $tabs Existing product data tabs.
131 * @return array
132 */
133 public function register_product_options_tab( $tabs ) {
134 if ( ! is_array( $tabs ) || ! $this->should_show_promotion( 'add_product_options' ) ) {
135 return $tabs;
136 }
137
138 $tabs['prad-promo-add-product-options'] = array(
139 'label' => 'Add Product Options',
140 'target' => 'prad-promo-add-product-options',
141 'class' => array( 'hide_if_grouped' ),
142 'priority' => 60,
143 );
144
145 return $tabs;
146 }
147
148 /**
149 * Render the promotion panel for the product options tab.
150 *
151 * @return void
152 */
153 public function render_product_options_panel() {
154 if ( ! $this->should_show_promotion( 'add_product_options' ) ) {
155 return;
156 }
157
158 ?>
159 <div id="prad-promo-add-product-options" class="panel woocommerce_options_panel">
160 <?php
161 $this->render_promotion_notice(
162 'prad-promo-add-product-options',
163 'add_product_options',
164 '
165 <div style="font-weight:bold;margin-bottom:12px;font-size:large;">
166 Create Unlimited Product Options in Minutes
167 </div>
168 <div style=""margin-bottom:12px;">
169 Go beyond default variations, add flexible fields, pricing, and start selling customizable products
170 </div>
171 <ul style="padding-left: 1.5rem;">
172 <li>
173 <span style="font-weight:bold;">
174 &#10003;&nbsp;
175 </span>
176 Add as many product fields and option sets as you need.
177 </li>
178 <li>
179 <span style="font-weight:bold;">
180 &#10003; &nbsp;
181 </span>
182 Show or hide fields and add additional charges.
183 </li>
184 <li>
185 <span style="font-weight:bold;">
186 &#10003; &nbsp;
187 </span>
188 Seamlessly add options to simple, variable, or grouped products.
189 </li>
190 </ul>
191 ',
192 'margin-inline: 20px;background:#f2f2f2;',
193 true,
194 array(
195 'default' => 'Start Now',
196 'loading' => 'Starting...',
197 ),
198 'align-items:start;flex-direction:column;'
199 );
200 ?>
201 </div>
202 <?php
203 }
204
205 /**
206 * Render promotion notice at the top of the variations tab.
207 *
208 * @return void
209 */
210 public function render_variations_notice() {
211 if ( ! $this->should_show_promotion( 'variations_tab' ) ) {
212 return;
213 }
214
215 ?>
216 <div id="prad-promo-variations-tab-container" style="display:none;">
217 <?php
218 ob_start();
219 ?>
220 <script>
221 jQuery( function( $ ) {
222 $(document).ready(function() {
223 const $notice = $( '#prad-promo-variations-tab' );
224 const $panel = $( '#variable_product_options_inner' );
225
226 if ( ! $notice.length || ! $panel.length ) {
227 return;
228 }
229
230 $notice.prependTo( $panel ).show();
231 });
232 } );
233 </script>
234 <?php
235 echo ob_get_clean(); // phpcs:ignore
236
237 $this->render_promotion_notice(
238 'prad-promo-variations-tab',
239 'variations_tab',
240 'Create Unlimited Product Variations in a Few Clicks',
241 'margin:16px 12px 16px 12px;border: 1px solid #c3c4c7;border-left-width: 4px;border-left-color: #72aee6;width:fit-content;padding-right:50px;',
242 true,
243 array(
244 'default' => 'Configure Now',
245 'loading' => 'Configuring...',
246 )
247 );
248 ?>
249 </div>
250 <?php
251 }
252
253 /**
254 * Render the promotional modal for the Products submenu item.
255 *
256 * @return void
257 */
258 public function render_products_submenu_modal() {
259 if ( ! is_admin() || ! current_user_can( 'edit_posts' ) ) {
260 return;
261 }
262
263 $submenu_url = admin_url( 'edit.php?post_type=product&page=' . self::PRODUCTS_MENU_SLUG );
264 $products_url = admin_url( 'edit.php?post_type=product' );
265 $learn_more = 'https://wordpress.org/plugins/product-addons/';
266 $nonce = wp_create_nonce( 'prad_promo_promotion_nonce' );
267 $img_src = ULTP_URL . '/assets/img/dashboard_banner/wooproduct/wowaddons-modal.png'; // CHANGE THIS.
268 ?>
269 <style>
270 .prad-promo-products-modal {
271 position: fixed;
272 inset: 0;
273 z-index: 99999;
274 display: none;
275 align-items: center;
276 justify-content: center;
277 padding: 24px;
278 background: rgba(15, 23, 42, 0.62);
279 }
280
281 .prad-promo-products-modal.is-active {
282 display: flex;
283 }
284
285 body.prad-promo-products-modal-open {
286 overflow: hidden;
287 }
288
289 .prad-promo-products-modal *,
290 .prad-promo-products-modal *::before,
291 .prad-promo-products-modal *::after {
292 box-sizing: border-box;
293 }
294
295 .prad-promo-products-modal__dialog {
296 position: relative;
297 width: min(100%, 470px);
298 padding: 28px 28px 22px;
299 border-radius: 22px;
300 background: linear-gradient(180deg, #ffffff 0%, #f6f9ff 100%);
301 box-shadow: 0 28px 80px rgba(15, 23, 42, 0.28);
302 text-align: center;
303 }
304
305 .prad-promo-products-modal__close {
306 position: absolute;
307 top: 18px;
308 right: 18px;
309 border: 0;
310 background: transparent;
311 color: #64748b;
312 cursor: pointer;
313 font-size: 24px;
314 line-height: 1;
315 }
316
317 .prad-promo-products-modal__close:hover,
318 .prad-promo-products-modal__close:focus {
319 color: #0f172a;
320 outline: none;
321 }
322
323 .prad-promo-products-modal__title {
324 margin: 0 0 10px;
325 color: #16213e;
326 font-size: 34px;
327 line-height: 1.08;
328 font-weight: 800;
329 letter-spacing: -0.03em;
330 }
331
332 .prad-promo-products-modal__text {
333 max-width: 330px;
334 margin: 0 auto 20px;
335 color: #64748b;
336 font-size: 15px;
337 line-height: 1.55;
338 }
339
340 .prad-promo-products-modal__list {
341 margin: 0 auto 24px;
342 padding: 0;
343 /* max-width: 320px; */
344 list-style: none;
345 text-align: left;
346 }
347
348 .prad-promo-products-modal__list li {
349 display: flex;
350 align-items: center;
351 gap: 12px;
352 padding: 11px 0;
353 border-bottom: 1px solid #e2e8f0;
354 color: #1e293b;
355 font-size: 14px;
356 font-weight: 600;
357 }
358
359 .prad-promo-products-modal__list li:last-child {
360 border-bottom: 0;
361 }
362
363 .prad-promo-products-modal__check {
364 display: inline-flex;
365 align-items: center;
366 justify-content: center;
367 width: 20px;
368 height: 20px;
369 border-radius: 50%;
370 background: #dcfce7;
371 color: #16a34a;
372 font-size: 12px;
373 font-weight: 700;
374 flex: 0 0 20px;
375 }
376
377 .prad-promo-products-modal__button {
378 display: flex;
379 align-items: center;
380 justify-content: center;
381 gap: 10px;
382 width: 100%;
383 padding: 15px 18px;
384 border: 0;
385 border-radius: 10px;
386 background: linear-gradient(180deg, #3b82f6 0%, #2563eb 100%);
387 color: #fff;
388 font-size: 15px;
389 font-weight: 700;
390 cursor: pointer;
391 box-shadow: 0 14px 28px rgba(37, 99, 235, 0.24);
392 }
393
394 .prad-promo-products-modal__button:hover,
395 .prad-promo-products-modal__button:focus {
396 background: linear-gradient(180deg, #2563eb 0%, #1d4ed8 100%);
397 color: #fff;
398 outline: none;
399 }
400
401 .prad-promo-products-modal__button[aria-disabled="true"] {
402 opacity: 0.75;
403 cursor: wait;
404 }
405
406 .prad-promo-products-modal__learn {
407 display: inline-block;
408 margin-top: 12px;
409 color: #2563eb;
410 font-size: 13px;
411 font-weight: 600;
412 text-decoration: underline;
413 }
414
415 .prad-promo-products-modal__footer {
416 display: grid;
417 grid-template-columns: repeat(3, minmax(0, 1fr));
418 gap: 10px;
419 margin-top: 18px;
420 padding: 12px;
421 border: 1px solid #e2e8f0;
422 border-radius: 14px;
423 background: rgba(255, 255, 255, 0.85);
424 }
425
426 .prad-promo-products-modal__meta {
427 display: flex;
428 align-items: center;
429 justify-content: center;
430 gap: 6px;
431 color: #64748b;
432 font-size: 12px;
433 font-weight: 600;
434 }
435
436 .prad-promo-products-modal__meta .dashicons {
437 width: 16px;
438 height: 16px;
439 font-size: 16px;
440 }
441
442
443 @media (max-height: 760px) {
444 .prad-promo-products-modal__dialog {
445 padding: 22px 22px 18px;
446 }
447
448 .prad-promo-products-modal__img {
449 max-height: 160px;
450 margin-bottom: 18px;
451 }
452
453 .prad-promo-products-modal__title {
454 font-size: 28px;
455 margin-bottom: 8px;
456 }
457
458 .prad-promo-products-modal__text {
459 margin-bottom: 16px;
460 font-size: 14px;
461 line-height: 1.45;
462 }
463
464 .prad-promo-products-modal__list {
465 margin-bottom: 18px;
466 }
467
468 .prad-promo-products-modal__list li {
469 gap: 10px;
470 padding: 8px 0;
471 font-size: 13px;
472 }
473
474 .prad-promo-products-modal__button {
475 padding: 13px 16px;
476 font-size: 14px;
477 }
478 }
479
480 @media (max-height: 680px) {
481 .prad-promo-products-modal__dialog {
482 padding: 18px 18px 16px;
483 }
484
485 .prad-promo-products-modal__img {
486 max-height: 120px;
487 margin-bottom: 14px;
488 }
489
490 .prad-promo-products-modal__title {
491 font-size: 24px;
492 }
493
494 .prad-promo-products-modal__text {
495 max-width: 100%;
496 margin-bottom: 12px;
497 font-size: 13px;
498 }
499
500 .prad-promo-products-modal__list {
501 margin-bottom: 14px;
502 }
503
504 .prad-promo-products-modal__list li {
505 padding: 6px 0;
506 font-size: 12px;
507 }
508
509 .prad-promo-products-modal__button {
510 padding: 12px 14px;
511 font-size: 13px;
512 }
513 }
514 .prad-promo-products-modal__img {
515 max-width: 100%;
516 height: auto;
517 margin-bottom: 24px;
518 margin-inline: auto;
519 }
520 </style>
521
522 <div id="prad-promo-products-modal" class="prad-promo-products-modal" aria-hidden="true">
523 <div class="prad-promo-products-modal__dialog" role="dialog" aria-modal="true" aria-labelledby="prad-promo-products-modal-title">
524 <button type="button" class="prad-promo-products-modal__close" aria-label="Close">&times;</button>
525 <img class="prad-promo-products-modal__img" src="<?php echo esc_attr( $img_src ); ?>" />
526 <h2 id="prad-promo-products-modal-title" class="prad-promo-products-modal__title">
527 Create Unlimited Product Options in Minutes
528 </h2>
529 <p class="prad-promo-products-modal__text">
530 Go beyond default variations, add flexible fields, pricing, and start selling customizable products
531 </p>
532 <ul class="prad-promo-products-modal__list">
533 <li><span class="prad-promo-products-modal__check">&#10003;</span><span>
534 Add as many product fields and option sets as you need.
535 </span></li>
536 <li><span class="prad-promo-products-modal__check">&#10003;</span><span>
537 Show or hide fields and add additional charges.
538 </span></li>
539 <li><span class="prad-promo-products-modal__check">&#10003;</span><span>
540 Seamlessly add options to simple, variable, or grouped products.
541 </span></li>
542 </ul>
543 <button
544 type="button"
545 class="prad-promo-products-modal__button"
546 data-default-label="Start Creating Custom Options"
547 data-loading-label="Starting..."
548 >
549 <span class="dashicons dashicons-admin-tools"></span>
550 <span>Start Creating Custom Options</span>
551 </button>
552 </div>
553 </div>
554
555 <script>
556 jQuery( function( $ ) {
557 const modal = $( '#prad-promo-products-modal' );
558 const dialog = modal.find( '.prad-promo-products-modal__dialog' );
559 const button = modal.find( '.prad-promo-products-modal__button' );
560 const buttonText = button.find( 'span' ).last();
561 const submenuSlug = <?php echo wp_json_encode( self::PRODUCTS_MENU_SLUG ); ?>;
562 const fallbackUrl = <?php echo wp_json_encode( $products_url ); ?>;
563 const nonce = <?php echo wp_json_encode( $nonce ); ?>;
564 const dashboardUrl = <?php echo wp_json_encode( $this->get_dashboard_url() ); ?>;
565 const defaultErrorMessage = <?php echo wp_json_encode( 'Failed to install WowAddons.' ); ?>;
566 let openedFromModalPage = window.location.search.indexOf( 'page=<?php echo esc_js( self::PRODUCTS_MENU_SLUG ); ?>' ) !== -1;
567
568 function openModal() {
569 modal.addClass( 'is-active' ).attr( 'aria-hidden', 'false' );
570 $( 'body' ).addClass( 'prad-promo-products-modal-open' );
571 }
572
573 function closeModal() {
574 modal.removeClass( 'is-active' ).attr( 'aria-hidden', 'true' );
575 $( 'body' ).removeClass( 'prad-promo-products-modal-open' );
576
577 if ( openedFromModalPage ) {
578 window.location.href = fallbackUrl;
579 }
580 }
581
582 $( document ).on( 'click', '#adminmenu a[href*="page=' + submenuSlug + '"], .wp-submenu a[href*="page=' + submenuSlug + '"]', function( event ) {
583 event.preventDefault();
584 event.stopImmediatePropagation();
585 openedFromModalPage = false;
586 openModal();
587 return false;
588 } );
589
590 modal.on( 'click', function( event ) {
591 if ( ! dialog.is( event.target ) && 0 === dialog.has( event.target ).length ) {
592 closeModal();
593 }
594 } );
595
596 modal.find( '.prad-promo-products-modal__close' ).on( 'click', function() {
597 closeModal();
598 } );
599
600 $( document ).on( 'keydown', function( event ) {
601 if ( 'Escape' === event.key && modal.hasClass( 'is-active' ) ) {
602 closeModal();
603 }
604 } );
605
606 button.on( 'click', function( event ) {
607 event.preventDefault();
608
609 if ( 'true' === button.attr( 'aria-disabled' ) ) {
610 return;
611 }
612
613 button.attr( 'aria-disabled', 'true' );
614 buttonText.text( button.data( 'loading-label' ) );
615
616 $.ajax( {
617 url: <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>,
618 type: 'POST',
619 dataType: 'json',
620 data: {
621 action: 'prad_promo_install_promotion_plugin',
622 nonce: nonce
623 }
624 } ).done( function( response ) {
625 if ( ! response || ! response.success ) {
626 button.attr( 'aria-disabled', 'false' );
627 buttonText.text( button.data( 'default-label' ) );
628 window.alert( defaultErrorMessage );
629 return;
630 }
631
632 window.location.href = dashboardUrl;
633 } ).fail( function( xhr ) {
634 const message = xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message
635 ? xhr.responseJSON.data.message
636 : defaultErrorMessage;
637
638 button.attr( 'aria-disabled', 'false' );
639 buttonText.text( button.data( 'default-label' ) );
640 window.alert( message );
641 } );
642 } );
643
644 if ( openedFromModalPage ) {
645 openModal();
646 }
647 } );
648 </script>
649 <?php
650 }
651
652 /**
653 * Ajax handler for dismissing promotion notice.
654 *
655 * @return void
656 */
657 public function ajax_dismiss_promotion() {
658 check_ajax_referer( 'prad_promo_promotion_nonce', 'nonce' );
659
660 $type = sanitize_text_field( wp_unslash( $_POST['type'] ?? '' ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
661 $this->set_dismissed( $type );
662
663 wp_send_json_success();
664 }
665
666 /**
667 * Ajax handler for installing the promoted plugin.
668 *
669 * @return void
670 */
671 public function ajax_install_promotion_plugin() {
672 check_ajax_referer( 'prad_promo_promotion_nonce', 'nonce' );
673
674 $plugin_exists = file_exists( WP_PLUGIN_DIR . '/' . self::PROMOTED_PLUGIN_FILE );
675
676 if ( ! $plugin_exists && ! current_user_can( 'install_plugins' ) ) {
677 wp_send_json_error(
678 array(
679 'message' => 'You are not allowed to install plugins.',
680 )
681 );
682 }
683
684 if ( $plugin_exists && ! current_user_can( 'activate_plugins' ) ) {
685 wp_send_json_error(
686 array(
687 'message' => 'You are not allowed to activate plugins.',
688 )
689 );
690 }
691
692 $result = $this->install_and_active_plugin();
693
694 if ( false === $result ) {
695 wp_send_json_error(
696 array(
697 'message' => 'Failed to install WowAddons.',
698 )
699 );
700 }
701
702 wp_send_json_success(
703 array(
704 'status' => $result,
705 'dashboard_url' => $this->get_dashboard_url(),
706 'message' => 'WowAddons installed successfully.',
707 )
708 );
709 }
710
711 /**
712 * Get dismiss key
713 *
714 * @param string $type Promotion type.
715 * @return string
716 */
717 private function get_dismiss_key( $type ) {
718 return 'prad_promo_promotion_is_closed_' . self::VERSION . '_' . $type;
719 }
720
721 /**
722 * Should show a promotion
723 *
724 * @param string $type Promotion type.
725 * @return void
726 */
727 private function set_dismissed( $type ) {
728 set_transient( $this->get_dismiss_key( $type ), 'yes', DAY_IN_SECONDS * 30 );
729 }
730
731 /**
732 * Should show a promotion
733 * Dont show promotions if:
734 * - The promotion was dismissed by the user.
735 * - The promotion hook already ran in the current page load by another plugin.
736 *
737 * @param string $type Promotion type.
738 * @return boolean
739 */
740 private function should_show_promotion( $type ) {
741 $ran_once = boolval( $GLOBALS['prad_promo_promotion'][ $type ] ?? false );
742 if ( $ran_once ) {
743 return false;
744 }
745 return get_transient( $this->get_dismiss_key( $type ) ) !== 'yes';
746 }
747
748 /**
749 * Render a reusable promotion notice block.
750 *
751 * @param string $id Notice DOM id.
752 * @param string $type Promotion type.
753 * @param string $message Notice message.
754 * @param string $style Inline wrapper style.
755 * @param boolean $inline Whether the notice should use inline positioning classes.
756 * @param array $button_labels Button text overrides.
757 * @param string $container_cls Additional classes for the message container.
758 * @return void
759 */
760 private function render_promotion_notice( $id, $type, $message, $style = '', $inline = true, $button_labels = array(), $container_cls = '' ) {
761 $GLOBALS['prad_promo_promotion'][ $type ] = true;
762
763 $button_labels = wp_parse_args(
764 is_array( $button_labels ) ? $button_labels : array(),
765 array(
766 'default' => 'Start Now',
767 'loading' => 'Starting...',
768 )
769 );
770
771 $classes = array( 'notice', 'notice-info', 'is-dismissible', 'wtrs-promotion-notice' );
772
773 if ( $inline ) {
774 $classes[] = 'inline';
775 }
776
777 ob_start();
778 ?>
779
780 <div
781 id="<?php echo esc_attr( $id ); ?>"
782 class="<?php echo esc_attr( implode( ' ', $classes ) ); ?>"
783 data-type="<?php echo esc_attr( $type ); ?>"
784 style="<?php echo esc_attr( $style ); ?>"
785 >
786 <div style="padding-block:12px;display:flex;gap:1rem;align-items:center;<?php echo esc_attr( $container_cls ); ?>">
787 <span>
788 <?php echo wp_kses_post( $message ); ?>
789 </span>
790 <a
791 href="#"
792 class="button button-secondary wtrs-promotion-install-link"
793 role="button"
794 data-default-label="<?php echo esc_attr( $button_labels['default'] ); ?>"
795 data-loading-label="<?php echo esc_attr( $button_labels['loading'] ); ?>"
796 >
797 <?php echo esc_html( $button_labels['default'] ); ?>
798 </a>
799 </div>
800 <button type="button" class="notice-dismiss">
801 <span class="screen-reader-text">Dismiss this notice</span>
802 </button>
803 </div>
804 <?php $this->echo_dismiss_notice_js( '#' . $id ); ?>
805 <?php $this->echo_install_notice_js( '#' . $id ); ?>
806 <?php
807 echo ob_get_clean(); // phpcs:ignore
808 }
809
810 /**
811 * Notice dismiss js
812 *
813 * @param string $id Notice ID.
814 * @return void
815 */
816 private function echo_dismiss_notice_js( $id ) {
817 ob_start();
818 ?>
819 <script>
820 jQuery( function( $ ) {
821 $( document ).on( 'click', '<?php echo esc_js( $id ); ?> .notice-dismiss', function() {
822 var $notice = $( this ).closest( '<?php echo esc_js( $id ); ?>' );
823
824 if ( ! $notice.length || 'true' === $notice.attr( 'data-dismissed' ) ) {
825 return;
826 }
827
828 $notice.slideUp( 300, function() {
829 $notice.remove();
830 } ).attr( 'data-dismissed', 'true' );
831
832 $.ajax( {
833 url: <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>,
834 type: 'POST',
835 data: {
836 action: 'prad_promo_dismiss_promotion',
837 nonce: <?php echo wp_json_encode( wp_create_nonce( 'prad_promo_promotion_nonce' ) ); ?>,
838 type: $notice.data( 'type' ) || ''
839 }
840 } )
841 } );
842 } );
843 </script>
844 <?php
845 echo ob_get_clean(); // phpcs:ignore
846 }
847
848 /**
849 * Notice install js.
850 *
851 * @param string $id Notice ID.
852 * @return void
853 */
854 private function echo_install_notice_js( $id ) {
855 ob_start();
856 ?>
857 <script>
858 jQuery( function( $ ) {
859 $( document ).on( 'click', '<?php echo esc_js( $id ); ?> .wtrs-promotion-install-link', function( event ) {
860 var $button = $( this );
861 var $notice = $button.closest( '<?php echo esc_js( $id ); ?>' );
862 var defaultErrorMessage = <?php echo wp_json_encode( 'Failed to install WowAddons.' ); ?>;
863
864 event.preventDefault();
865
866 if ( ! $notice.length || 'true' === $button.attr( 'aria-disabled' ) ) {
867 return;
868 }
869
870 $button.attr( 'aria-disabled', 'true' )
871 .addClass( 'button-disabled' )
872 .text($button.data( 'loading-label' ))
873
874 $.ajax( {
875 url: <?php echo wp_json_encode( admin_url( 'admin-ajax.php' ) ); ?>,
876 type: 'POST',
877 dataType: 'json',
878 data: {
879 action: 'prad_promo_install_promotion_plugin',
880 nonce: <?php echo wp_json_encode( wp_create_nonce( 'prad_promo_promotion_nonce' ) ); ?>
881 }
882 } ).done( function( response ) {
883 if ( ! response || ! response.success || ! response.data ) {
884 $button.attr( 'aria-disabled', 'false' ).removeClass( 'button-disabled' ).text( $button.data( 'default-label' ) );
885 window.alert( defaultErrorMessage );
886 return;
887 }
888 window.location.href = "<?php echo esc_js( $this->get_dashboard_url() ); ?>";
889 } ).fail( function( xhr ) {
890 var message = xhr.responseJSON && xhr.responseJSON.data && xhr.responseJSON.data.message
891 ? xhr.responseJSON.data.message
892 : defaultErrorMessage;
893
894 $button.attr( 'aria-disabled', 'false' ).removeClass( 'button-disabled' ).text( $button.data( 'default-label' ) );
895 window.alert( message );
896 } );
897 } );
898 } );
899 </script>
900 <?php
901 echo ob_get_clean(); // phpcs:ignore
902 }
903
904 /**
905 * Get the dashboard URL for the promoted plugin.
906 *
907 * @return string
908 */
909 private function get_dashboard_url() {
910 return admin_url( 'admin.php?page=prad-dashboard#dashboard' );
911 }
912
913 /**
914 * Installs and activates the promoted plugin.
915 *
916 * @return string|false
917 */
918 public function install_and_active_plugin() {
919 include_once ABSPATH . 'wp-admin/includes/plugin.php';
920
921 if ( is_plugin_active( self::PROMOTED_PLUGIN_FILE ) ) {
922 return 'active';
923 }
924
925 if ( ! file_exists( WP_PLUGIN_DIR . '/' . self::PROMOTED_PLUGIN_FILE ) ) {
926 if ( ! $this->download_plugin( self::PROMOTED_PLUGIN_FILE, self::PROMOTED_PLUGIN_SLUG ) ) {
927 return false;
928 }
929 }
930
931 $res = activate_plugin( self::PROMOTED_PLUGIN_FILE );
932
933 return is_wp_error( $res ) ? false : 'installed';
934 }
935
936 /**
937 * Installs a plugin based on the provided plugin file and slug.
938 *
939 * This function is expected to handle the logic required to install a plugin,
940 * such as downloading, unpacking, and activating the plugin using the provided
941 * plugin file and slug.
942 *
943 * @param string $plugin The plugin file path or identifier (e.g., 'plugin-directory/plugin-file.php').
944 * @param string $slug The plugin slug (typically the directory name of the plugin).
945 */
946 private function download_plugin( $plugin, $slug ) {
947 include ABSPATH . 'wp-admin/includes/plugin-install.php';
948 include ABSPATH . 'wp-admin/includes/class-wp-upgrader.php';
949
950 if ( ! class_exists( 'Plugin_Upgrader' ) ) {
951 include ABSPATH . 'wp-admin/includes/class-plugin-upgrader.php';
952 }
953 if ( ! class_exists( 'WP_Ajax_Upgrader_Skin' ) ) {
954 include ABSPATH . 'wp-admin/includes/class-wp-ajax-upgrader-skin.php';
955 }
956
957 $api = plugins_api(
958 'plugin_information',
959 array(
960 'slug' => $slug,
961 'fields' => array(
962 'short_description' => false,
963 'sections' => false,
964 'requires' => false,
965 'rating' => false,
966 'ratings' => false,
967 'downloaded' => false,
968 'last_updated' => false,
969 'added' => false,
970 'tags' => false,
971 'compatibility' => false,
972 'homepage' => false,
973 'donate_link' => false,
974 ),
975 )
976 );
977
978 if ( is_wp_error( $api ) ) {
979 return false;
980 }
981
982 $upgrader = new \Plugin_Upgrader( new \WP_Ajax_Upgrader_Skin() );
983 $install_result = $upgrader->install( $api->download_link );
984
985 return is_wp_error( $install_result ) || false === $install_result ? false : true;
986 }
987 }
988