auto-install-notice.php
2 weeks ago
auto-install-tracker.php
2 weeks ago
plugin-installer.php
2 weeks ago
plugin-skin.php
1 year ago
auto-install-notice.php
284 lines
| 1 | <?php |
| 2 | |
| 3 | namespace ShopEngine\Utils\Onboard; |
| 4 | |
| 5 | defined( 'ABSPATH' ) || exit; |
| 6 | |
| 7 | class Auto_Install_Notice { |
| 8 | |
| 9 | const DISMISSED_KEY = 'shopengine_auto_install_notice_dismissed'; |
| 10 | const EMAIL_COLLECTED_KEY = 'wpmet_onboard_email_collected'; |
| 11 | |
| 12 | public static function init(): void { |
| 13 | add_action( 'admin_footer', [ __CLASS__, 'render' ] ); |
| 14 | add_action( 'wp_ajax_shopengine_dismiss_auto_install_notice', [ __CLASS__, 'handle_dismiss' ] ); |
| 15 | add_action( 'wp_ajax_shopengine_confirm_auto_install_notice', [ __CLASS__, 'handle_confirm' ] ); |
| 16 | } |
| 17 | |
| 18 | public static function render(): void { |
| 19 | if ( ! current_user_can( 'manage_options' ) ) { |
| 20 | return; |
| 21 | } |
| 22 | |
| 23 | if ( get_option( self::DISMISSED_KEY ) ) { |
| 24 | return; |
| 25 | } |
| 26 | |
| 27 | if ( \ShopEngine\Utils\Util::get_settings( 'shopengine_user_consent_for_banner', 'true' ) !== 'true' ) { |
| 28 | return; |
| 29 | } |
| 30 | |
| 31 | // Only show when ShopEngine was auto-installed by another wpmet plugin. |
| 32 | $registry = Auto_Install_Tracker::get_registry(); |
| 33 | $auto_installed = isset( $registry['shopengine/shopengine.php'] ); |
| 34 | |
| 35 | if ( ! $auto_installed ) { |
| 36 | return; |
| 37 | } |
| 38 | |
| 39 | // Only show on ShopEngine's own admin pages. |
| 40 | $screen = get_current_screen(); |
| 41 | if ( ! $screen || strpos( $screen->id, 'shopengine' ) === false ) { |
| 42 | return; |
| 43 | } |
| 44 | |
| 45 | $nonce = wp_create_nonce( 'shopengine_auto_install_notice_nonce' ); |
| 46 | $ajax_url = esc_js( admin_url( 'admin-ajax.php' ) ); |
| 47 | $heading = esc_js( __( 'Get more from your new plugins 🚀', 'shopengine' ) ); |
| 48 | $desc = esc_js( __( 'Allow us to use non-sensitive data from your site to improve our products and get personalized performance tips.', 'shopengine' ) ); |
| 49 | $skip_label = esc_js( __( 'Skip for Now', 'shopengine' ) ); |
| 50 | $confirm_label = esc_js( __( 'Confirm & Apply', 'shopengine' ) ); |
| 51 | $applying = esc_js( __( 'Applying…', 'shopengine' ) ); |
| 52 | ?> |
| 53 | <style> |
| 54 | @property --angle { |
| 55 | syntax: '<angle>'; |
| 56 | initial-value: 162.14deg; |
| 57 | inherits: false; |
| 58 | } |
| 59 | #wpmet-shopengine-notice-skip, |
| 60 | #wpmet-shopengine-notice-confirm { |
| 61 | display: flex; |
| 62 | align-items: center; |
| 63 | justify-content: center; |
| 64 | min-height: unset; |
| 65 | line-height: unset; |
| 66 | box-sizing: border-box; |
| 67 | padding: 9px 20px; |
| 68 | border-radius: 8px; |
| 69 | flex: none; |
| 70 | font-size: 13px; |
| 71 | white-space: nowrap; |
| 72 | cursor: pointer; |
| 73 | } |
| 74 | #wpmet-shopengine-notice-skip { |
| 75 | background: #fff; |
| 76 | border: 1px solid #d7d7db; |
| 77 | color: #000; |
| 78 | transition: background 250ms ease, border-color 250ms ease, color 250ms ease; |
| 79 | } |
| 80 | #wpmet-shopengine-notice-skip:hover { |
| 81 | background: #dbeafe; |
| 82 | border: 1px solid #dbeafe; |
| 83 | color: #000; |
| 84 | } |
| 85 | #wpmet-shopengine-notice-confirm { |
| 86 | position: relative; |
| 87 | overflow: hidden; |
| 88 | isolation: isolate; |
| 89 | --angle: 162.14deg; |
| 90 | background: linear-gradient(var(--angle), #4371F8 7.19%, #2B58DE 44.76%); |
| 91 | border: none; |
| 92 | color: #fff; |
| 93 | } |
| 94 | #wpmet-shopengine-notice-confirm::after { |
| 95 | content: ""; |
| 96 | position: absolute; |
| 97 | top: -60%; |
| 98 | right: -10%; |
| 99 | width: 65%; |
| 100 | height: 200%; |
| 101 | background: rgba(255, 255, 255, 0.10); |
| 102 | border-radius: 60% 0 0 10%; |
| 103 | transform: rotate(20deg); |
| 104 | transform-origin: bottom left; |
| 105 | z-index: -1; |
| 106 | pointer-events: none; |
| 107 | transition: top 300ms ease, right 300ms ease, opacity 300ms ease; |
| 108 | } |
| 109 | #wpmet-shopengine-notice-confirm:hover::after { |
| 110 | top: -70%; |
| 111 | right: 0%; |
| 112 | opacity: 0.7; |
| 113 | } |
| 114 | .ant-notification { |
| 115 | z-index: 9999999 !important; |
| 116 | } |
| 117 | </style> |
| 118 | <script> |
| 119 | (function() { |
| 120 | var NONCE = '<?php echo esc_js( $nonce ); ?>'; |
| 121 | var AJAXURL = '<?php echo $ajax_url; ?>'; |
| 122 | var dismissed = false; |
| 123 | |
| 124 | function setContentPadding( height ) { |
| 125 | var el = document.getElementById( 'wpcontent' ); |
| 126 | if ( el ) { el.style.setProperty( 'padding-top', height + 'px', 'important' ); } |
| 127 | } |
| 128 | |
| 129 | function clearContentPadding() { |
| 130 | var el = document.getElementById( 'wpcontent' ); |
| 131 | if ( el ) { el.style.removeProperty( 'padding-top' ); } |
| 132 | } |
| 133 | |
| 134 | function removeNotice() { |
| 135 | dismissed = true; |
| 136 | clearContentPadding(); |
| 137 | var el = document.querySelector( '.wpmet-shopengine-auto-install-notice' ); |
| 138 | if ( el ) { |
| 139 | el.style.opacity = '0'; |
| 140 | el.style.transition = 'opacity 0.3s'; |
| 141 | setTimeout( function() { if ( el.parentNode ) { el.parentNode.removeChild( el ); } }, 320 ); |
| 142 | } |
| 143 | } |
| 144 | |
| 145 | function doPost( action, cb ) { |
| 146 | var xhr = new XMLHttpRequest(); |
| 147 | xhr.open( 'POST', AJAXURL ); |
| 148 | xhr.setRequestHeader( 'Content-Type', 'application/x-www-form-urlencoded' ); |
| 149 | xhr.onload = function() { if ( cb ) { cb(); } }; |
| 150 | xhr.send( 'action=' + encodeURIComponent( action ) + '&nonce=' + encodeURIComponent( NONCE ) ); |
| 151 | } |
| 152 | |
| 153 | function isBlockedPage() { |
| 154 | var h = window.location.hash; |
| 155 | var s = window.location.search; |
| 156 | return h === '#shopengine-modules' || h === '#shopengine-widgets' || h === '#getting-started' |
| 157 | || s.indexOf( 'page=shopengine_wpmet_plugins' ) !== -1; |
| 158 | } |
| 159 | |
| 160 | function injectNotice() { |
| 161 | if ( dismissed ) { return; } |
| 162 | if ( isBlockedPage() ) { return; } |
| 163 | if ( document.querySelector( '.wpmet-shopengine-auto-install-notice' ) ) { return; } |
| 164 | |
| 165 | var div = document.createElement( 'div' ); |
| 166 | div.className = 'wpmet-shopengine-auto-install-notice'; |
| 167 | div.style.cssText = [ |
| 168 | 'display:flex', 'align-items:center', 'justify-content:space-between', |
| 169 | 'gap:20px', 'min-height:104px', 'box-sizing:border-box', |
| 170 | 'position:fixed', 'top:32px', 'left:160px', 'right:0', |
| 171 | 'z-index:999999', 'padding:16px 20px', |
| 172 | 'background:#fff', 'border-left:4px solid #E91E8C', |
| 173 | 'box-shadow:0 2px 8px rgba(0,0,0,.15)' |
| 174 | ].join( ';' ); |
| 175 | |
| 176 | div.innerHTML = |
| 177 | '<div style="flex:1 1 auto;">' + |
| 178 | '<h3 style="margin:0 0 6px;font-family:Inter,sans-serif;font-size:24px;font-weight:700;line-height:24px;letter-spacing:0;"><?php echo $heading; ?></h3>' + |
| 179 | '<p style="margin:0;color:#50575E;font-family:Inter,sans-serif;font-weight:500;font-size:16px;line-height:24px;letter-spacing:0;"><?php echo $desc; ?></p>' + |
| 180 | '</div>' + |
| 181 | '<div style="flex:0 0 auto;display:flex;gap:10px;">' + |
| 182 | '<button class="button" id="wpmet-shopengine-notice-skip"><?php echo $skip_label; ?></button>' + |
| 183 | '<button class="button button-primary" id="wpmet-shopengine-notice-confirm"><?php echo $confirm_label; ?></button>' + |
| 184 | '</div>'; |
| 185 | |
| 186 | document.body.appendChild( div ); |
| 187 | |
| 188 | var noticeHeight = div.offsetHeight || 104; |
| 189 | setContentPadding( noticeHeight ); |
| 190 | |
| 191 | document.getElementById( 'wpmet-shopengine-notice-skip' ).addEventListener( 'click', function() { |
| 192 | doPost( 'shopengine_dismiss_auto_install_notice' ); |
| 193 | removeNotice(); |
| 194 | } ); |
| 195 | |
| 196 | document.getElementById( 'wpmet-shopengine-notice-confirm' ).addEventListener( 'click', function() { |
| 197 | var btn = this; |
| 198 | btn.disabled = true; |
| 199 | btn.textContent = '<?php echo $applying; ?>'; |
| 200 | doPost( 'shopengine_confirm_auto_install_notice', function() { |
| 201 | removeNotice(); |
| 202 | } ); |
| 203 | } ); |
| 204 | } |
| 205 | |
| 206 | function tryInject() { |
| 207 | setTimeout( injectNotice, 300 ); |
| 208 | } |
| 209 | |
| 210 | if ( document.readyState === 'loading' ) { |
| 211 | document.addEventListener( 'DOMContentLoaded', tryInject ); |
| 212 | } else { |
| 213 | tryInject(); |
| 214 | } |
| 215 | |
| 216 | window.addEventListener( 'hashchange', function() { |
| 217 | if ( dismissed ) { return; } |
| 218 | var existing = document.querySelector( '.wpmet-shopengine-auto-install-notice' ); |
| 219 | if ( existing && existing.parentNode ) { existing.parentNode.removeChild( existing ); } |
| 220 | clearContentPadding(); |
| 221 | setTimeout( injectNotice, 400 ); |
| 222 | } ); |
| 223 | |
| 224 | document.addEventListener( 'visibilitychange', function() { |
| 225 | if ( document.visibilityState === 'visible' ) { tryInject(); } |
| 226 | } ); |
| 227 | |
| 228 | window.addEventListener( 'pageshow', function( e ) { |
| 229 | if ( e.persisted ) { tryInject(); } |
| 230 | } ); |
| 231 | })(); |
| 232 | </script> |
| 233 | <?php |
| 234 | } |
| 235 | |
| 236 | public static function handle_dismiss(): void { |
| 237 | check_ajax_referer( 'shopengine_auto_install_notice_nonce', 'nonce' ); |
| 238 | if ( ! current_user_can( 'manage_options' ) ) { |
| 239 | wp_send_json_error(); |
| 240 | } |
| 241 | update_option( self::DISMISSED_KEY, true, false ); |
| 242 | wp_send_json_success(); |
| 243 | } |
| 244 | |
| 245 | public static function handle_confirm(): void { |
| 246 | check_ajax_referer( 'shopengine_auto_install_notice_nonce', 'nonce' ); |
| 247 | if ( ! current_user_can( 'manage_options' ) ) { |
| 248 | wp_send_json_error(); |
| 249 | } |
| 250 | |
| 251 | $stored_email = get_option( 'wpmet_onboard_collected_email' ); |
| 252 | $email = $stored_email |
| 253 | ? sanitize_email( $stored_email ) |
| 254 | : sanitize_email( get_option( 'admin_email' ) ); |
| 255 | |
| 256 | \ShopEngine\Core\Onboard\Plugin_Data_Sender::instance()->sendEmailSubscribeData( 'plugin-subscribe', [ |
| 257 | 'email' => $email, |
| 258 | 'slug' => 'shopengine', |
| 259 | ] ); |
| 260 | |
| 261 | // Also send for auto-installed plugins that don't have their own notice banner. |
| 262 | $registry = Auto_Install_Tracker::get_registry(); |
| 263 | $slug_map = [ |
| 264 | 'elementskit-lite/elementskit-lite.php' => 'elementskit-lite', |
| 265 | 'emailkit/EmailKit.php' => 'emailkit', |
| 266 | 'gutenkit-blocks-addon/gutenkit-blocks-addon.php' => 'gutenkit-blocks-addon', |
| 267 | 'getgenie/getgenie.php' => 'getgenie', |
| 268 | 'popup-builder-block/popup-builder-block.php' => 'popupkit', |
| 269 | ]; |
| 270 | foreach ( array_keys( $registry ) as $plugin_file ) { |
| 271 | if ( isset( $slug_map[ $plugin_file ] ) ) { |
| 272 | \ShopEngine\Core\Onboard\Plugin_Data_Sender::instance()->sendEmailSubscribeData( 'plugin-subscribe', [ |
| 273 | 'email' => $email, |
| 274 | 'slug' => $slug_map[ $plugin_file ], |
| 275 | ] ); |
| 276 | } |
| 277 | } |
| 278 | |
| 279 | update_option( self::EMAIL_COLLECTED_KEY, true, false ); |
| 280 | update_option( self::DISMISSED_KEY, true, false ); |
| 281 | wp_send_json_success(); |
| 282 | } |
| 283 | } |
| 284 |