PluginProbe
Post Grid Gutenberg Blocks – PostX / 5.0.24
Post Grid Gutenberg Blocks – PostX v5.0.24
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.24, at includes/notice/class-wow-addons-promotion.php

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