PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.2.8
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.2.8
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
merchant / inc / modules / inactive-tab-message / class-inactive-tab-message.php

class-inactive-tab-message.php in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 2.2.8, at inc/modules/inactive-tab-message/class-inactive-tab-message.php

366 lines 11.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Inactive Tab Message.
5 *
6 * @package Merchant
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly
11 }
12
13 require_once __DIR__ . '/class-inactive-tab-message-resolver.php';
14
15 /**
16 * Inactive Tab Message Class.
17 *
18 */
19 class Merchant_Inactive_Tab_Message extends Merchant_Add_Module {
20
21 /**
22 * Module ID.
23 *
24 */
25 const MODULE_ID = 'inactive-tab-message';
26
27 /**
28 * Is module preview.
29 *
30 * @var bool
31 */
32 public static $is_module_preview = false;
33
34 /**
35 * Constructor.
36 *
37 */
38 public function __construct() {
39 $this->setup_module();
40 parent::__construct();
41
42 if ( is_admin() && $this->is_module_settings_page() ) {
43 $this->register_admin_hooks();
44 }
45
46 if ( Merchant_Modules::is_module_active( self::MODULE_ID ) && is_admin() ) {
47 $this->init_translations();
48 }
49
50 if ( ! Merchant_Modules::is_module_active( self::MODULE_ID ) ) {
51 return;
52 }
53
54 // Return early if it's on admin but not in the respective module settings page.
55 if ( is_admin() && ! $this->is_module_settings_page() ) {
56 return;
57 }
58
59 $this->register_frontend_hooks();
60 }
61
62 /**
63 * Set up module identity: ID, flags, section, defaults, data, and options path.
64 *
65 * @return void
66 */
67 protected function setup_module(): void {
68 $this->module_id = self::MODULE_ID;
69 $this->wc_only = true;
70 $this->module_section = 'reduce-abandonment';
71
72 $this->module_default_settings = array(
73 // Existing (backward compatible).
74 'message' => __( '✋ Don\'t forget this', 'merchant' ),
75 'abandoned_message' => __( '✋ You left something in the cart', 'merchant' ),
76
77 // High-value cart.
78 'high_value_message' => '',
79 'high_value_threshold' => 100,
80
81 // Rotating messages.
82 'enable_rotation' => 0,
83 'rotation_messages' => array(),
84 'rotation_interval' => 3,
85
86 // Favicon.
87 'enable_favicon' => 0,
88 'favicon_type' => 'emoji',
89 'favicon_emoji' => 'wave',
90 'favicon_url' => '',
91
92 // Return message.
93 'return_message' => '',
94 'return_duration' => 2,
95
96 // Scrolling text.
97 'enable_scroll' => 0,
98 );
99
100 $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
101 $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
102 }
103
104 /**
105 * Register hooks that are only needed on the module's admin settings page.
106 *
107 * @return void
108 */
109 protected function register_admin_hooks(): void {
110 self::$is_module_preview = true;
111
112 // Enqueue admin styles.
113 add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_css' ) );
114
115 // Admin preview box.
116 add_filter( 'merchant_module_preview', array( $this, 'render_admin_preview' ), 10, 2 );
117 }
118
119 /**
120 * Register hooks that power the frontend functionality.
121 *
122 * @return void
123 */
124 protected function register_frontend_hooks(): void {
125 // Enqueue scripts.
126 add_action( 'merchant_enqueue_after_main_css_js', array( $this, 'enqueue_scripts' ) );
127
128 // Localize script.
129 add_filter( 'merchant_localize_script', array( $this, 'localize_script' ) );
130
131 // Add merchant selector and content to cart fragments.
132 add_filter( 'woocommerce_add_to_cart_fragments', array( $this, 'cart_count_fragment' ) );
133 }
134
135 /**
136 * Init translations.
137 *
138 * @return void
139 */
140 public function init_translations() {
141 $settings = $this->get_module_settings();
142 $resolver = new Merchant_Inactive_Tab_Message_Resolver();
143
144 foreach ( $resolver->get_translatable_strings( $settings ) as $entry ) {
145 Merchant_Translator::register_string( $entry['string'], esc_html( $entry['name'] ) );
146 }
147 }
148
149 /**
150 * Admin enqueue CSS.
151 *
152 * @return void
153 */
154 public function admin_enqueue_css() {
155 $page = ( ! empty( $_GET['page'] ) ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
156 $module = ( ! empty( $_GET['module'] ) ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
157
158 if ( 'merchant' === $page && self::MODULE_ID === $module ) {
159 wp_enqueue_style( 'merchant-admin-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/admin/preview.min.css', array(), MERCHANT_VERSION );
160 wp_enqueue_script( 'merchant-admin-' . self::MODULE_ID . '-preview', MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/admin/preview.min.js', array( 'jquery' ), MERCHANT_VERSION, true );
161 wp_localize_script(
162 'merchant-admin-' . self::MODULE_ID . '-preview',
163 'merchantItmPreview',
164 array(
165 'siteName' => get_bloginfo( 'name' ),
166 )
167 );
168 }
169 }
170
171 /**
172 * Enqueue scripts.
173 *
174 * @return void
175 */
176 public function enqueue_scripts() {
177 // Enqueue vendor favico.js (shared with cart-count-favicon module).
178 wp_enqueue_script( 'favico', MERCHANT_URI . 'assets/js/vendor/favico.js', array(), MERCHANT_VERSION, true );
179
180 // Register and enqueue the main module script.
181 wp_enqueue_script( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/inactive-tab-message.min.js', array( 'favico' ), MERCHANT_VERSION, true );
182 }
183
184 /**
185 * Localize script with module settings.
186 *
187 * @param array<string, mixed> $setting The merchant global object setting parameter.
188 * @return array<string, mixed> The merchant global object setting parameter.
189 */
190 public function localize_script( $setting ) {
191 $module_settings = $this->get_module_settings();
192
193 $cart_count = 0;
194 $cart_total = '';
195 $wc = function_exists( 'WC' ) ? WC() : null;
196
197 if ( $wc && $wc->cart ) { // @phpstan-ignore booleanAnd.rightAlwaysTrue
198 $cart_count = $wc->cart->get_cart_contents_count();
199 $cart_total = html_entity_decode( wp_strip_all_tags( $wc->cart->get_cart_total() ), ENT_QUOTES, 'UTF-8' );
200 }
201
202 $site_name = get_bloginfo( 'name' );
203
204 $resolver = new Merchant_Inactive_Tab_Message_Resolver();
205 $data = $resolver->prepare_localized_data( $module_settings, $cart_count, $cart_total, $site_name );
206
207 // Translate messages.
208 $translate_keys = array(
209 'inactive_tab_message',
210 'inactive_tab_abandoned_message',
211 'inactive_tab_high_value_message',
212 'inactive_tab_return_message',
213 );
214
215 foreach ( $translate_keys as $key ) {
216 if ( ! empty( $data[ $key ] ) ) {
217 $data[ $key ] = Merchant_Translator::translate( $data[ $key ] );
218 }
219 }
220
221 // Translate rotation messages.
222 if ( ! empty( $data['inactive_tab_rotation_messages'] ) ) {
223 $data['inactive_tab_rotation_messages'] = array_map(
224 array( 'Merchant_Translator', 'translate' ),
225 $data['inactive_tab_rotation_messages']
226 );
227 }
228
229 // Also pass raw cart total for threshold comparison in JS.
230 $data['inactive_tab_cart_total_raw'] = 0;
231 if ( $wc && $wc->cart ) { // @phpstan-ignore booleanAnd.rightAlwaysTrue
232 $data['inactive_tab_cart_total_raw'] = (float) $wc->cart->get_cart_contents_total();
233 }
234
235 // Resolve favicon attachment ID to URL.
236 if ( ! empty( $data['inactive_tab_favicon_url'] ) ) {
237 $favicon_attachment_url = wp_get_attachment_url( (int) $data['inactive_tab_favicon_url'] );
238 $data['inactive_tab_favicon_url'] = $favicon_attachment_url ? $favicon_attachment_url : '';
239 }
240
241 return array_merge( $setting, $data );
242 }
243
244 /**
245 * Render admin preview.
246 *
247 * @param Merchant_Admin_Preview $preview
248 * @param string $module
249 *
250 * @return Merchant_Admin_Preview
251 */
252 public function render_admin_preview( $preview, $module ) {
253 if ( self::MODULE_ID === $module ) {
254 ob_start();
255 self::admin_preview_content();
256 $content = (string) ob_get_clean();
257
258 // HTML.
259 $preview->set_html( $content );
260
261 // All live preview updates (text, favicon, rotation) are handled
262 // by the module's own admin/preview.js to avoid conflicts with
263 // the global preview system's catch-all change handler.
264 }
265
266 return $preview;
267 }
268
269 /**
270 * Admin preview content.
271 *
272 * Enhanced preview showing a simulated browser tab with favicon and message.
273 *
274 * @return void
275 */
276 public function admin_preview_content() {
277 $settings = $this->get_module_settings();
278 $favicon_url = get_site_icon_url() ? get_site_icon_url( 512 ) : MERCHANT_URI . 'inc/modules/' . self::MODULE_ID . '/admin/images/wplogo.svg';
279
280 // Map string keys to emoji characters (must match JS emojiMap).
281 $emoji_map = array(
282 'wave' => '👋',
283 'bell' => '🔔',
284 'cart' => '🛒',
285 'clock' => '',
286 'alert' => '',
287 'money' => '💰',
288 'fire' => '🔥',
289 'star' => '',
290 );
291
292 $favicon_key = $settings['favicon_emoji'] ?? 'wave';
293 $favicon_emoji = $emoji_map[ $favicon_key ] ?? $emoji_map['wave'];
294
295 ?>
296
297 <div class="mrc-preview-inactive-tab-message">
298 <div class="mrc-inactive-tab-preview-tabs">
299 <!-- Active tab (original state) -->
300 <div class="mrc-inactive-tab-preview-tab mrc-inactive-tab-preview-tab--active">
301 <div class="mrc-inactive-tab-preview-tab__favicon">
302 <img src="<?php echo esc_url( $favicon_url ); ?>" alt="" />
303 </div>
304 <div class="mrc-inactive-tab-preview-tab__title">
305 <?php echo esc_html__( 'Your Page Title', 'merchant' ); ?>
306 </div>
307 <span class="mrc-inactive-tab-preview-tab__close dashicons dashicons-no-alt"></span>
308 </div>
309
310 <!-- Inactive tab (shows the message) -->
311 <div class="mrc-inactive-tab-preview-tab mrc-inactive-tab-preview-tab--inactive">
312 <div class="mrc-inactive-tab-preview-tab__favicon mrc-inactive-tab-preview-tab__favicon--swap">
313 <?php if ( ! empty( $settings['enable_favicon'] ) && 'image' === ( $settings['favicon_type'] ?? 'emoji' ) && ! empty( $settings['favicon_url'] ) ) : ?>
314 <?php $custom_favicon_url = wp_get_attachment_url( (int) $settings['favicon_url'] ); ?>
315 <?php if ( $custom_favicon_url ) : ?>
316 <img class="mrc-inactive-tab-favicon-custom" src="<?php echo esc_url( $custom_favicon_url ); ?>" alt="" />
317 <?php else : ?>
318 <img src="<?php echo esc_url( $favicon_url ); ?>" alt="" />
319 <?php endif; ?>
320 <?php elseif ( ! empty( $settings['enable_favicon'] ) && 'emoji' === ( $settings['favicon_type'] ?? 'emoji' ) ) : ?>
321 <span class="mrc-inactive-tab-favicon-emoji"><?php echo esc_html( $favicon_emoji ); ?></span>
322 <?php else : ?>
323 <img src="<?php echo esc_url( $favicon_url ); ?>" alt="" />
324 <?php endif; ?>
325 </div>
326 <div class="mrc-inactive-tab-preview-tab__title mrc-inactive-tab-message-text">
327 <?php echo esc_html( Merchant_Translator::translate( $settings['message'] ) ); ?>
328 </div>
329 <span class="mrc-inactive-tab-preview-tab__close dashicons dashicons-no-alt"></span>
330 </div>
331 </div>
332
333 <div class="mrc-inactive-tab-preview-label">
334 <?php echo esc_html__( 'Active tab', 'merchant' ); ?>
335 <span class="mrc-inactive-tab-preview-label--right"><?php echo esc_html__( 'Inactive tab (preview)', 'merchant' ); ?></span>
336 </div>
337 </div>
338
339 <?php
340 }
341
342 /**
343 * Cart count fragments.
344 *
345 * @param array<string, mixed> $fragments The cart fragments.
346 * @return array<string, mixed> The cart fragments.
347 */
348 public function cart_count_fragment( $fragments ) {
349 if ( Merchant_Modules::is_module_active( 'inactive-tab-message' ) ) {
350 $wc = function_exists( 'WC' ) ? WC() : null;
351 if ( $wc && $wc->cart ) { // @phpstan-ignore booleanAnd.rightAlwaysTrue
352 $fragments['.merchant_cart_count'] = $wc->cart->get_cart_contents_count();
353 $fragments['.merchant_cart_total'] = html_entity_decode( wp_strip_all_tags( $wc->cart->get_cart_total() ), ENT_QUOTES, 'UTF-8' );
354 $fragments['.merchant_cart_total_raw'] = (float) $wc->cart->get_cart_contents_total();
355 }
356 }
357
358 return $fragments;
359 }
360 }
361
362 // Initialize the module.
363 add_action( 'init', function() {
364 Merchant_Modules::create_module( new Merchant_Inactive_Tab_Message() );
365 } );
366