PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.2
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
← All changes | inc/modules/pre-orders/class-pre-orders.php +566 -336 1.72.3.2 View file →
@@ -1,336 +1,566 @@
1 -<?php
2 -
3 -/**
4 - * Pre Orders.
5 - *
6 - * @package Merchant
7 - */
8 -
9 -if ( ! defined( 'ABSPATH' ) ) {
10 - exit; // Exit if accessed directly
11 -}
12 -
13 -/**
14 - * Pre Orders Class.
15 - *
16 - */
17 -class Merchant_Pre_Orders extends Merchant_Add_Module {
18 -
19 - /**
20 - * Module ID.
21 - *
22 - */
23 - const MODULE_ID = 'pre-orders';
24 -
25 - /**
26 - * Is module preview.
27 - *
28 - */
29 - public static $is_module_preview = false;
30 -
31 - /**
32 - * Main functionality dependency.
33 - *
34 - */
35 - public $main_func;
36 -
37 - /**
38 - * Constructor.
39 - *
40 - */
41 - public function __construct( Merchant_Pre_Orders_Main_Functionality $main_func ) {
42 -
43 - // Module id.
44 - $this->module_id = self::MODULE_ID;
45 -
46 - // WooCommerce only.
47 - $this->wc_only = true;
48 -
49 - // Parent construct.
50 - parent::__construct();
51 -
52 - $this->main_func = $main_func;
53 -
54 - // Module section.
55 - $this->module_section = 'boost-revenue';
56 -
57 - // Module default settings.
58 - $this->module_default_settings = array(
59 - 'button_text' => __( 'Pre Order Now!', 'merchant' ),
60 - 'additional_text' => __( 'Ships on {date}.', 'merchant' )
61 - );
62 -
63 - // Mount preview url.
64 - $preview_url = site_url( '/' );
65 -
66 - if ( function_exists( 'wc_get_page_id' ) ) {
67 - $preview_url = get_permalink( wc_get_page_id( 'shop' ) );
68 - }
69 -
70 - // Module data.
71 - $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
72 - $this->module_data[ 'preview_url' ] = $preview_url;
73 -
74 - // Module options path.
75 - $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
76 -
77 - // Is module preview page.
78 - if ( is_admin() && parent::is_module_settings_page() ) {
79 - self::$is_module_preview = true;
80 -
81 - // Enqueue admin styles.
82 - add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_css' ) );
83 -
84 - // Render module essencial instructions before the module page body content.
85 - add_action( 'merchant_admin_after_module_page_page_header', array( $this, 'admin_module_essencial_instructions' ) );
86 -
87 - // Admin preview box.
88 - add_filter( 'merchant_module_preview', array( $this, 'render_admin_preview' ), 10, 2 );
89 -
90 - // Custom CSS.
91 - // The custom CSS should be added here as well due to ensure preview box works properly.
92 - add_filter( 'merchant_custom_css', array( $this, 'admin_custom_css' ) );
93 -
94 - }
95 -
96 - if ( ! Merchant_Modules::is_module_active( self::MODULE_ID ) ) {
97 - return;
98 - }
99 -
100 - // TODO: Refactor the 'Merchant_Pre_Orders_Main_Functionality' class to load admin things separated from frontend things.
101 - $main_func->init();
102 -
103 - // Return early if it's on admin but not in the respective module settings page.
104 - if ( is_admin() && ! parent::is_module_settings_page() ) {
105 - return;
106 - }
107 -
108 - // Enqueue styles.
109 - add_action( 'merchant_enqueue_before_main_css_js', array( $this, 'enqueue_css' ) );
110 -
111 - // Enqueue scripts.
112 - add_action( 'merchant_enqueue_after_main_css_js', array( $this, 'enqueue_scripts' ) );
113 -
114 - // Localize script.
115 - add_filter( 'merchant_localize_script', array( $this, 'localize_script' ) );
116 -
117 - // Custom CSS.
118 - add_filter( 'merchant_custom_css', array( $this, 'frontend_custom_css' ) );
119 -
120 - }
121 -
122 - /**
123 - * Admin enqueue CSS.
124 - *
125 - * @return void
126 - */
127 - public function admin_enqueue_css() {
128 - $page = ( ! empty( $_GET['page'] ) ) ? sanitize_text_field( wp_unslash( $_GET['page'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
129 - $module = ( ! empty( $_GET['module'] ) ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
130 -
131 - if ( 'merchant' === $page && self::MODULE_ID === $module ) {
132 - wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/pre-orders.min.css', [], MERCHANT_VERSION );
133 - wp_enqueue_style( 'merchant-admin-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/admin/preview.min.css', array(), MERCHANT_VERSION );
134 - }
135 - }
136 -
137 - /**
138 - * Enqueue CSS.
139 - *
140 - * @return void
141 - */
142 - public function enqueue_css() {
143 -
144 - // Specific module styles.
145 - wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/pre-orders.min.css', array(), MERCHANT_VERSION );
146 - }
147 -
148 - /**
149 - * Enqueue scripts.
150 - *
151 - * @return void
152 - */
153 - public function enqueue_scripts() {
154 -
155 - // Register and enqueue the main module script.
156 - wp_enqueue_script( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/pre-orders.min.js', array(), MERCHANT_VERSION, true );
157 - }
158 -
159 - /**
160 - * Localize script with module settings.
161 - *
162 - * @param array $setting The merchant global object setting parameter.
163 - * @return array $setting The merchant global object setting parameter.
164 - */
165 - public function localize_script( $setting ) {
166 - $module_settings = $this->get_module_settings();
167 -
168 - $setting[ 'pre_orders' ] = true;
169 - $setting[ 'pre_orders_add_button_title' ] = $module_settings[ 'button_text' ];
170 -
171 - return $setting;
172 - }
173 -
174 - /**
175 - * Render module essencial instructions.
176 - *
177 - * @return void
178 - */
179 - public function admin_module_essencial_instructions() { ?>
180 - <div class="merchant-module-page-settings">
181 - <div class="merchant-module-page-setting-box merchant-module-page-setting-box-style-2">
182 - <div class="merchant-module-page-setting-title"><?php echo esc_html__( 'Tag Pre-Orders', 'merchant' ); ?></div>
183 - <div class="merchant-module-page-setting-fields">
184 - <div class="merchant-module-page-setting-field merchant-module-page-setting-field-content">
185 - <div class="merchant-module-page-setting-field-inner">
186 - <div class="merchant-tag-pre-orders">
187 - <i class="dashicons dashicons-info"></i>
188 - <p><?php echo esc_html__( 'Pre-orders captured by Merchant are tagged with "MerchantPreOrder" and can be found in your WooCommerce Order Section.', 'merchant' ); ?> <?php echo sprintf( '<a href="%s" target="_blank">%s</a>', esc_url( admin_url( 'edit.php?post_type=shop_order' ) ), esc_html__( 'View Pre-Orders', 'merchant' ) ); ?></p>
189 - </div>
190 - </div>
191 - </div>
192 - </div>
193 - </div>
194 - </div>
195 -
196 - <?php
197 - }
198 -
199 - /**
200 - * Render admin preview
201 - *
202 - * @param Merchant_Admin_Preview $preview
203 - * @param string $module
204 - *
205 - * @return Merchant_Admin_Preview
206 - */
207 - public function render_admin_preview( $preview, $module ) {
208 - if ( self::MODULE_ID === $module ) {
209 - $settings = $this->get_module_settings();
210 -
211 - // Additional text.
212 - $additional_text = $settings[ 'additional_text' ];
213 - $time_format = date_i18n( get_option( 'date_format' ), strtotime( gmdate( 'Y-m-d', strtotime('+2 days') ) ) );
214 - $text = $this->main_func->replaceDateTxt( $additional_text, $time_format );
215 -
216 - ob_start();
217 - self::admin_preview_content( $settings, $text );
218 - $content = ob_get_clean();
219 -
220 - // HTML.
221 - $preview->set_html( $content );
222 -
223 - // Button Text.
224 - $preview->set_text( 'button_text', '.add_to_cart_button' );
225 -
226 - // Additional Text.
227 - $preview->set_text( 'additional_text', '.merchant-pre-orders-date', array(
228 - array(
229 - '{date}'
230 - ),
231 - array(
232 - $time_format
233 - )
234 - ) );
235 -
236 - }
237 -
238 - return $preview;
239 - }
240 -
241 - /**
242 - * Admin preview content.
243 - *
244 - * @return void
245 - */
246 - public function admin_preview_content( $settings, $text ) {
247 - ?>
248 -
249 - <div class="mrc-preview-single-product-elements">
250 - <div class="mrc-preview-left-column">
251 - <div class="mrc-preview-product-image-wrapper">
252 - <div class="mrc-preview-product-image"></div>
253 - <div class="mrc-preview-product-image-thumbs">
254 - <div class="mrc-preview-product-image-thumb"></div>
255 - <div class="mrc-preview-product-image-thumb"></div>
256 - <div class="mrc-preview-product-image-thumb"></div>
257 - </div>
258 - </div>
259 - </div>
260 - <div class="mrc-preview-right-column">
261 - <div class="mrc-preview-text-placeholder"></div>
262 - <div class="mrc-preview-text-placeholder mrc-mw-70"></div>
263 - <div class="mrc-preview-text-placeholder mrc-mw-40 mrc-hide-on-smaller-screens"></div>
264 - <div class="mrc-preview-text-placeholder mrc-mw-30 mrc-hide-on-smaller-screens"></div>
265 - <div class="merchant-pre-ordered-product">
266 - <div class="merchant-pre-orders-date"><?php echo sprintf( '<div class="merchant-pre-orders-date">%s</div>', esc_html( $text ) ); ?></div>
267 - <a href="#" class="add_to_cart_button"><?php echo esc_html( $settings[ 'button_text' ] ); ?></a>
268 - </div>
269 - </div>
270 - </div>
271 -
272 - <?php
273 - }
274 -
275 - /**
276 - * Custom CSS.
277 - *
278 - * @return string
279 - */
280 - public function get_module_custom_css() {
281 - $css = '';
282 -
283 - // Text Color.
284 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'text-color', '#FFF', '.merchant-pre-ordered-product', '--mrc-po-text-color' );
285 -
286 - // Text Color (hover).
287 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'text-hover-color', '#FFF', '.merchant-pre-ordered-product', '--mrc-po-text-hover-color' );
288 -
289 - // Border Color.
290 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-color', '#212121', '.merchant-pre-ordered-product', '--mrc-po-border-color' );
291 -
292 - // Border Color (hover).
293 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-hover-color', '#414141', '.merchant-pre-ordered-product', '--mrc-po-border-hover-color' );
294 -
295 - // Background Color.
296 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'background-color', '#212121', '.merchant-pre-ordered-product', '--mrc-po-background-color' );
297 -
298 - // Background Color (hover).
299 - $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'background-hover-color', '#414141', '.merchant-pre-ordered-product', '--mrc-po-background-hover-color' );
300 -
301 - return $css;
302 - }
303 -
304 - /**
305 - * Admin custom CSS.
306 - *
307 - * @param string $css The custom CSS.
308 - * @return string $css The custom CSS.
309 - */
310 - public function admin_custom_css( $css ) {
311 - $css .= $this->get_module_custom_css();
312 -
313 - return $css;
314 - }
315 -
316 - /**
317 - * Frontend custom CSS.
318 - *
319 - * @param string $css The custom CSS.
320 - * @return string $css The custom CSS.
321 - */
322 - public function frontend_custom_css( $css ) {
323 - $css .= $this->get_module_custom_css();
324 -
325 - return $css;
326 - }
327 -
328 -}
329 -
330 -// Main functionality.
331 -require MERCHANT_DIR . 'inc/modules/pre-orders/class-pre-orders-main-functionality.php';
332 -
333 -// Initialize the module.
334 -add_action( 'init', function() {
335 - new Merchant_Pre_Orders( new Merchant_Pre_Orders_Main_Functionality() );
336 -} );
1 +<?php
2 +/**
3 + * Merchant - Pre Orders
4 + *
5 + * @package Merchant
6 + */
7 +
8 +if ( ! defined( 'ABSPATH' ) ) {
9 + exit; // Exit if accessed directly
10 +}
11 +
12 +/**
13 + * Pre Orders Class.
14 + *
15 + * This class handles the initialization and setup of the Pre Orders module, including
16 + * admin settings, asset enqueueing, and frontend styling.
17 + *
18 + * @property string $module_id The module ID.
19 + * @property bool $wc_only The WooCommerce only flag.
20 + * @property string $module_section The module section.
21 + * @property array $module_default_settings The module default settings.
22 + * @property array $module_data The module data.
23 + * @property string $module_options_path The module options path.
24 + */
25 +class Merchant_Pre_Orders extends Merchant_Add_Module {
26 +
27 + /**
28 + * Module ID.
29 + *
30 + * @var string The module ID.
31 + */
32 + const MODULE_ID = 'pre-orders';
33 +
34 + /**
35 + * Is module preview.
36 + *
37 + * @var bool The is module preview flag.
38 + */
39 + public static $is_module_preview = false;
40 +
41 + /**
42 + * Main functionality dependency.
43 + *
44 + * @var Merchant_Pre_Orders_Main_Functionality The main functionality instance.
45 + */
46 + public $main_func;
47 +
48 + /**
49 + * Set the module as having analytics.
50 + *
51 + * @var bool
52 + */
53 + protected $has_analytics = true;
54 +
55 + /**
56 + * Initialize the module's option group definitions.
57 + *
58 + * @return array<int, array<string, mixed>> Array of option group arrays.
59 + */
60 + protected function init_option_groups() {
61 + return require MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
62 + }
63 +
64 + /**
65 + * Fire action before rendering option groups.
66 + *
67 + * @return void
68 + */
69 + protected function before_render_option_groups() {
70 + /**
71 + * Fires before module options are rendered.
72 + *
73 + * @since 1.0
74 + *
75 + * @param string $module_id The module ID.
76 + */
77 + do_action( 'merchant_admin_before_include_modules_options', self::MODULE_ID );
78 + }
79 +
80 + /**
81 + * Constructor.
82 + *
83 + * @param Merchant_Pre_Orders_Main_Functionality $main_func The main functionality instance.
84 + */
85 + public function __construct( Merchant_Pre_Orders_Main_Functionality $main_func ) {
86 + // Module id.
87 + $this->module_id = self::MODULE_ID;
88 +
89 + // WooCommerce only.
90 + $this->wc_only = true;
91 +
92 + // Parent construct.
93 + parent::__construct();
94 +
95 + $this->main_func = $main_func;
96 +
97 + // Module section.
98 + $this->module_section = 'boost-revenue';
99 +
100 + // Module default settings.
101 + $this->module_default_settings = array(
102 + 'button_text' => __( 'Pre Order Now!', 'merchant' ),
103 + 'additional_text' => __( 'Ships on {date}.', 'merchant' ),
104 + );
105 +
106 + // Module data.
107 + $this->module_data = Merchant_Admin_Modules::$modules_data[ self::MODULE_ID ];
108 +
109 + // AI prompt examples.
110 + $this->ai_examples = array(
111 + 'blurb' => esc_html__( 'See what AI can do for your pre-orders, from launching a new campaign to adjusting the discount, shipping date, or button text on one already running.', 'merchant' ),
112 + 'prompts' => array(
113 + esc_html__( 'Explore the abilities WPVibe gives you access to, then create a pre-order for the Galaxy Pro Headphones with an expected shipping date of March 15, 2026', 'merchant' ),
114 + esc_html__( 'Check what abilities you have available through WPVibe, then set up a pre-order for the entire Spring Collection category with a fixed $10 discount instead of a percentage', 'merchant' ),
115 + esc_html__( "Look at your available WPVibe abilities, then change the button text on the Galaxy Pro Headphones pre-order to 'Reserve Yours'", 'merchant' ),
116 + esc_html__( 'See what abilities WPVibe exposes, then exclude the Wired Earbuds product from the Spring Collection pre-order', 'merchant' ),
117 + ),
118 + );
119 +
120 + // Module options path.
121 + $this->module_options_path = MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/options.php';
122 +
123 + // Is module preview page.
124 + if ( is_admin() && parent::is_module_settings_page() ) {
125 + self::$is_module_preview = true;
126 +
127 + // Enqueue admin styles.
128 + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_css' ) );
129 + add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_js' ) );
130 +
131 + // Localize Script.
132 + add_filter( 'merchant_admin_localize_script', array( $this, 'localize_script' ) );
133 +
134 + // Admin preview box.
135 + add_filter( 'merchant_module_preview', array( $this, 'render_admin_preview' ), 10, 2 );
136 +
137 + // Custom CSS.
138 + // The custom CSS should be added here as well due to ensure preview box works properly.
139 + add_filter( 'merchant_custom_css', array( $this, 'admin_custom_css' ) );
140 + }
141 +
142 + add_action( 'merchant_admin_before_include_modules_options', array( $this, 'help_banner' ) );
143 +
144 + if ( Merchant_Modules::is_module_active( self::MODULE_ID ) && is_admin() ) {
145 + // Init translations.
146 + $this->init_translations();
147 +
148 + // Include product metabox for per-product settings.
149 + require_once MERCHANT_DIR . 'inc/modules/' . self::MODULE_ID . '/admin/class-pre-orders-metabox.php';
150 + }
151 +
152 +
153 + if ( ! Merchant_Modules::is_module_active( self::MODULE_ID ) ) {
154 + return;
155 + }
156 +
157 + // TODO: Refactor the 'Merchant_Pre_Orders_Main_Functionality' class to load admin things separated from frontend things.
158 + $main_func->init();
159 +
160 + // Return early if it's on admin but not in the respective module settings page.
161 + if ( is_admin() && ! wp_doing_ajax() && ! parent::is_module_settings_page() ) {
162 + return;
163 + }
164 +
165 + // Enqueue styles.
166 + add_action( 'merchant_enqueue_before_main_css_js', array( $this, 'enqueue_css' ) );
167 +
168 + // Enqueue scripts.
169 + add_action( 'merchant_enqueue_after_main_css_js', array( $this, 'enqueue_scripts' ) );
170 +
171 + // Localize script.
172 + add_filter( 'merchant_localize_script', array( $this, 'localize_script' ) );
173 +
174 + // Custom CSS.
175 + add_filter( 'merchant_custom_css', array( $this, 'frontend_custom_css' ) );
176 +
177 + $this->supply_missing_id( 'rules' );
178 + }
179 +
180 + /**
181 + * Init translations for module settings.
182 + *
183 + * Registers strings for the Merchant translator tool.
184 + *
185 + * @return void
186 + */
187 + public function init_translations() {
188 + $settings = $this->get_module_settings();
189 + if ( ! empty( $settings['rules'] ) ) {
190 + foreach ( $settings['rules'] as $rule ) {
191 + if ( ! empty( $rule['button_text'] ) ) {
192 + Merchant_Translator::register_string( $rule['button_text'], 'Pre order button text' );
193 + }
194 + if ( ! empty( $rule['additional_text'] ) ) {
195 + Merchant_Translator::register_string( $rule['additional_text'], 'Pre order additional information' );
196 + }
197 + if ( ! empty( $rule['cart_label_text'] ) ) {
198 + Merchant_Translator::register_string( $rule['cart_label_text'], 'Label text on cart' );
199 + }
200 + }
201 + }
202 + }
203 +
204 + /**
205 + * Enqueue admin-specific CSS.
206 + *
207 + * @return void
208 + */
209 + public function admin_enqueue_css() {
210 + if ( parent::is_module_settings_page() ) {
211 + wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/pre-orders.min.css', array(), MERCHANT_VERSION );
212 + wp_enqueue_style( 'merchant-admin-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/admin/preview.min.css', array(), MERCHANT_VERSION );
213 + }
214 + }
215 +
216 + /**
217 + * Enqueue admin-specific JavaScript.
218 + *
219 + * @return void
220 + */
221 + public function admin_enqueue_js() {
222 + if ( parent::is_module_settings_page() ) {
223 + wp_enqueue_script(
224 + 'merchant-admin-' . self::MODULE_ID,
225 + MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/admin/preview.min.js',
226 + array( 'jquery' ),
227 + MERCHANT_VERSION,
228 + true
229 + );
230 + }
231 + }
232 +
233 + /**
234 + * Enqueue frontend-specific CSS.
235 + *
236 + * @return void
237 + */
238 + public function enqueue_css() {
239 + // Specific module styles.
240 + wp_enqueue_style( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/css/modules/' . self::MODULE_ID . '/pre-orders.min.css', array(), MERCHANT_VERSION );
241 +
242 + // add inline style
243 + if ( is_singular( 'product' ) ) {
244 + wp_add_inline_style( 'merchant-' . self::MODULE_ID, $this->add_inline_style() );
245 + }
246 + }
247 +
248 + /**
249 + * Add inline CSS styles based on the active rule.
250 + *
251 + * @return string The generated inline CSS.
252 + */
253 + public function add_inline_style() {
254 + ob_start();
255 + $rule = $this->current_rule();
256 + if ( ! empty( $rule ) ) {
257 + ?>
258 + .woocommerce .merchant-pre-ordered-product{
259 + --mrc-po-text-color: <?php echo esc_attr( $rule['text-color'] ?? '#FFF' ); ?>;
260 + --mrc-po-text-hover-color: <?php echo esc_attr( $rule['text-hover-color'] ?? '#FFF' ); ?>;
261 + --mrc-po-border-color: <?php echo esc_attr( $rule['border-color'] ?? '#212121' ); ?>;
262 + --mrc-po-border-hover-color: <?php echo esc_attr( $rule['border-hover-color'] ?? '#414141' ); ?>;
263 + --mrc-po-border-width: <?php echo esc_attr( ( $rule['border-width'] ?? 0 ) . 'px' ); ?>;
264 + --mrc-po-border-radius: <?php echo esc_attr( ( $rule['border-radius'] ?? 0 ) . 'px' ); ?>;
265 + --mrc-po-background-color: <?php echo esc_attr( $rule['background-color'] ?? '#212121' ); ?>;
266 + --mrc-po-background-hover-color: <?php echo esc_attr( $rule['background-hover-color'] ?? '#414141' ); ?>;
267 + }
268 + <?php
269 + }
270 +
271 + return ob_get_clean();
272 + }
273 +
274 + /**
275 + * Enqueue frontend-specific scripts.
276 + *
277 + * @return void
278 + */
279 + public function enqueue_scripts() {
280 + // Register and enqueue the main module script.
281 + wp_enqueue_script( 'merchant-' . self::MODULE_ID, MERCHANT_URI . 'assets/js/modules/' . self::MODULE_ID . '/pre-orders.min.js', array(), MERCHANT_VERSION, true );
282 + }
283 +
284 + /**
285 + * Localize the main module script with settings and translations.
286 + *
287 + * @param array $setting The localized settings array.
288 + *
289 + * @return array The updated settings array.
290 + */
291 + public function localize_script( $setting ) {
292 + $setting['pre_orders'] = true;
293 + $rule = $this->current_rule();
294 + if ( ! empty( $rule ) && ! empty( $rule['button_text'] ) ) {
295 + $setting['pre_orders_add_button_title'] = Merchant_Translator::translate( $rule['button_text'] );
296 + } else {
297 + $setting['pre_orders_add_button_title'] = esc_html__( 'Pre Order Now!', 'merchant' );
298 + }
299 +
300 + $setting['shipping_date_missing_text'] = esc_html__( 'Please set a shipping date first', 'merchant' );
301 +
302 + return $setting;
303 + }
304 +
305 + /**
306 + * Render the admin preview for the module.
307 + *
308 + * @param Merchant_Admin_Preview $preview The preview object.
309 + * @param string $module The module ID.
310 + *
311 + * @return Merchant_Admin_Preview The updated preview object.
312 + */
313 + public function render_admin_preview( $preview, $module ) {
314 + if ( self::MODULE_ID === $module ) {
315 + $settings = $this->get_module_settings();
316 +
317 + // Additional text.
318 + $additional_text = $settings['additional_text'];
319 + $time_format = date_i18n( get_option( 'date_format' ), strtotime( gmdate( 'Y-m-d', strtotime( '+2 days' ) ) ) );
320 + $text = $this->main_func->replace_date_text( $additional_text, $time_format );
321 +
322 + ob_start();
323 + self::admin_preview_content( $settings, $text );
324 + $content = ob_get_clean();
325 +
326 + // HTML.
327 + $preview->set_html( $content );
328 +
329 + // Button Text.
330 + $preview->set_text( 'button_text', '.add_to_cart_button' );
331 +
332 + // Additional Text.
333 + $preview->set_text( 'additional_text', '.merchant-pre-orders-date', array(
334 + array(
335 + '{date}',
336 + ),
337 + array(
338 + $time_format,
339 + ),
340 + ) );
341 + }
342 +
343 + return $preview;
344 + }
345 +
346 + /**
347 + * Admin preview HTML content.
348 + *
349 + * @param array $settings The module settings.
350 + * @param string $text The formatted additional text.
351 + *
352 + * @return void
353 + */
354 + public function admin_preview_content( $settings, $text ) {
355 + ?>
356 + <div class="mrc-preview-single-product-elements">
357 + <div class="mrc-preview-left-column">
358 + <div class="mrc-preview-product-image-wrapper">
359 + <div class="mrc-preview-product-image"></div>
360 + <div class="mrc-preview-product-image-thumbs">
361 + <div class="mrc-preview-product-image-thumb"></div>
362 + <div class="mrc-preview-product-image-thumb"></div>
363 + <div class="mrc-preview-product-image-thumb"></div>
364 + </div>
365 + </div>
366 + </div>
367 + <div class="mrc-preview-right-column">
368 + <div class="mrc-preview-text-placeholder"></div>
369 + <div class="mrc-preview-text-placeholder mrc-mw-70"></div>
370 + <div class="mrc-preview-text-placeholder mrc-mw-40 mrc-hide-on-smaller-screens"></div>
371 + <div class="mrc-preview-text-placeholder mrc-mw-30 mrc-hide-on-smaller-screens"></div>
372 + <div class="merchant-pre-ordered-product">
373 + <div class="merchant-pre-orders-date"><?php echo esc_html( $text ); ?></div>
374 + <a href="#" class="add_to_cart_button"><?php echo esc_html( $settings['button_text'] ); ?></a>
375 + </div>
376 + </div>
377 + </div>
378 + <?php
379 + }
380 +
381 + /**
382 + * Get Custom CSS for the module.
383 + *
384 + * @return string The generated CSS.
385 + */
386 + public function get_module_custom_css() {
387 + $css = '';
388 +
389 + if ( is_admin() || is_singular( 'product' ) ) {
390 + // Text Color.
391 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'text-color', '#FFF', '.merchant-pre-ordered-product', '--mrc-po-text-color' );
392 +
393 + // Text Color (hover).
394 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'text-hover-color', '#FFF', '.merchant-pre-ordered-product', '--mrc-po-text-hover-color' );
395 +
396 + // Border Color.
397 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-color', '#212121', '.merchant-pre-ordered-product', '--mrc-po-border-color' );
398 +
399 + // Border Color (hover).
400 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-hover-color', '#414141', '.merchant-pre-ordered-product', '--mrc-po-border-hover-color' );
401 +
402 + // Border Width.
403 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-width', 0, '.merchant-pre-ordered-product', '--mrc-po-border-width', 'px' );
404 +
405 + // Border Radius.
406 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'border-radius', 0, '.merchant-pre-ordered-product', '--mrc-po-border-radius', 'px' );
407 +
408 + // Background Color.
409 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'background-color', '#212121', '.merchant-pre-ordered-product', '--mrc-po-background-color' );
410 +
411 + // Background Color (hover).
412 + $css .= Merchant_Custom_CSS::get_variable_css( 'pre-orders', 'background-hover-color', '#414141', '.merchant-pre-ordered-product', '--mrc-po-background-hover-color' );
413 + }
414 +
415 + return $css;
416 + }
417 +
418 + /**
419 + * Filter for admin custom CSS.
420 + *
421 + * @param string $css The custom CSS.
422 + *
423 + * @return string The updated custom CSS.
424 + */
425 + public function admin_custom_css( $css ) {
426 + $css .= $this->get_module_custom_css();
427 +
428 + return $css;
429 + }
430 +
431 + /**
432 + * Filter for frontend custom CSS.
433 + *
434 + * @param string $css The custom CSS.
435 + *
436 + * @return string The updated custom CSS.
437 + */
438 + public function frontend_custom_css( $css ) {
439 + $css .= $this->get_module_custom_css();
440 +
441 + return $css;
442 + }
443 +
444 + /**
445 + * Get the currently applicable product rule.
446 + *
447 + * @return array The rule array if found, empty array otherwise.
448 + */
449 + private function current_rule() {
450 + if ( is_singular( 'product' ) ) {
451 + $product_id = get_queried_object_id();
452 + $product = wc_get_product( $product_id );
453 +
454 + if ( ! $product ) {
455 + return array();
456 + }
457 +
458 + $rule = Merchant_Pre_Orders_Main_Functionality::available_product_rule( $product->get_id() );
459 + if ( empty( $rule ) && $product instanceof \WC_Product_Variable ) {
460 + $available_variations = $product->get_available_variations();
461 + foreach ( $available_variations as $variation ) {
462 + $rule = Merchant_Pre_Orders_Main_Functionality::available_product_rule( $variation['variation_id'] );
463 + if ( ! empty( $rule ) ) {
464 + break;
465 + }
466 + }
467 + }
468 +
469 + return $rule;
470 + }
471 +
472 + return array();
473 + }
474 +
475 + /**
476 + * Get the WooCommerce orders screen URL, aware of HPOS.
477 + *
478 + * @return string The orders screen URL.
479 + */
480 + private function orders_screen_url() {
481 + if ( class_exists( \Automattic\WooCommerce\Utilities\OrderUtil::class ) && \Automattic\WooCommerce\Utilities\OrderUtil::custom_orders_table_usage_is_enabled() ) {
482 + return admin_url( 'admin.php?page=wc-orders' );
483 + }
484 +
485 + return admin_url( 'edit.php?post_type=shop_order' );
486 + }
487 +
488 + /**
489 + * Display a help banner in the module settings page.
490 + *
491 + * @param string $module_id The module ID.
492 + *
493 + * @return void
494 + */
495 + public function help_banner( $module_id ) {
496 + if ( $module_id === self::MODULE_ID ) {
497 + $orders_url = $this->orders_screen_url();
498 + ?>
499 + <div class="merchant-module-page-setting-fields">
500 + <div class="merchant-module-page-setting-field merchant-module-page-setting-field-content">
501 + <div class="merchant-module-page-setting-field-inner">
502 + <div class="merchant-tag-pre-orders">
503 + <i class="dashicons dashicons-info"></i>
504 + <p>
505 + <?php
506 + echo esc_html__(
507 + 'Pre-orders captured by Merchant are tagged with "Merchant PreOrder" and can be found in your WooCommerce Order Section. You can control pre-order settings on a per-product basis from the individual product page.',
508 + 'merchant'
509 + );
510 + printf(
511 + '<a href="%1s" target="_blank">%2s</a>',
512 + esc_url( $orders_url ),
513 + esc_html__( 'View Pre-Orders', 'merchant' )
514 + );
515 + ?></p>
516 + </div>
517 + </div>
518 + </div>
519 + </div>
520 + <?php
521 + }
522 + }
523 +
524 + /**
525 + * Supply missing flexible_id for the rules setting.
526 + *
527 + * @param string $setting_key The setting key for the flexible items.
528 + *
529 + * @return void
530 + */
531 + public function supply_missing_id( $setting_key = 'offers' ) {
532 + $option = 'merchant_' . $this->module_id . '_missing_id_flag';
533 +
534 + if ( get_option( $option, false ) || ! method_exists( 'Merchant_Admin_Options', 'set' ) ) {
535 + return;
536 + }
537 +
538 + $flexible_items = Merchant_Admin_Options::get( $this->module_id, $setting_key, array() );
539 + if ( ! empty( $flexible_items ) ) {
540 + $update = 0;
541 + foreach ( $flexible_items as $key => $item ) {
542 + if ( empty( $item['flexible_id'] ) ) {
543 + $flexible_items[ $key ]['flexible_id'] = wp_generate_uuid4();
544 + ++ $update;
545 + }
546 + }
547 +
548 + if ( $update > 0 ) {
549 + Merchant_Admin_Options::set( $this->module_id, $setting_key, $flexible_items );
550 + }
551 +
552 + update_option( $option, true, false );
553 + }
554 + }
555 +}
556 +
557 +// Rules Repository.
558 +require_once MERCHANT_DIR . 'inc/modules/pre-orders/classes/class-pre-orders-rules.php';
559 +
560 +// Main functionality.
561 +require_once MERCHANT_DIR . 'inc/modules/pre-orders/class-pre-orders-main-functionality.php';
562 +
563 +// Initialize the module.
564 +add_action( 'init', function () {
565 + Merchant_Modules::create_module( new Merchant_Pre_Orders( new Merchant_Pre_Orders_Main_Functionality() ) );
566 +} );