PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.0
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.0
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 / pre-orders / admin / class-pre-orders-metabox.php

class-pre-orders-metabox.php in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 2.3.0, at inc/modules/pre-orders/admin/class-pre-orders-metabox.php

450 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Pre-Orders Product Metabox
5 *
6 * @package Merchant
7 */
8
9 if ( ! defined( 'ABSPATH' ) ) {
10 exit; // Exit if accessed directly
11 }
12
13 /**
14 * Pre-Orders Metabox Class
15 *
16 * @since 1.0.0
17 */
18 class Merchant_Pre_Orders_Metabox extends Merchant_Metabox {
19
20 /**
21 * Accepted date/time formats hint for the three date fields.
22 *
23 * @var string
24 */
25 const DATE_FORMAT_HINT = 'Accepts m-d-Y h:i A (e.g. 06-24-2026 03:30 PM), Y-m-d, Y-m-dTH:i:s, or m/d/y. Empty string clears the date.';
26
27 /**
28 * Constructor.
29 */
30 public function __construct() {
31 parent::__construct();
32
33 add_filter( 'merchant_metabox_options', array( $this, 'add_metabox_options' ), 10, 1 );
34 }
35
36 /**
37 * Add metabox options.
38 *
39 * @param array $options Existing metabox options.
40 *
41 * @return array Modified metabox options.
42 */
43 public function add_metabox_options( $options ) {
44 // Add Pre-Orders section
45 $this->add_section( 'merchant_pre_orders', array(
46 'title' => esc_html__( 'Pre-Orders', 'merchant' ),
47 'post_type' => array( 'product' ),
48 'priority' => 20,
49 ) );
50
51 foreach ( self::get_field_definitions() as $field_id => $field_def ) {
52 $this->add_field( $field_id, $field_def );
53 }
54
55 return $options;
56 }
57
58 /**
59 * Pure-data field definitions for the pre-orders product metabox.
60 *
61 * The single source of truth for both the admin metabox UI (via
62 * add_metabox_options()) and the product-settings ability pair (via
63 * Merchant_Product_Settings_Registry). Every field carries an inline
64 * 'ai_meta' key — presence of that key is what exposes the field to the
65 * ability layer.
66 *
67 * @return array<string, array<string, mixed>>
68 */
69 public static function get_field_definitions() {
70 return array(
71 '_merchant_pre_order_mode' => array(
72 'section' => 'merchant_pre_orders',
73 'type' => 'select',
74 'title' => esc_html__( 'Pre-Order Mode', 'merchant' ),
75 'desc' => esc_html__( 'Choose how pre-orders should be handled for this product.', 'merchant' ),
76 'options' => array(
77 'global' => esc_html__( 'Global Settings (Default)', 'merchant' ),
78 'product' => esc_html__( 'Product Specific Settings', 'merchant' ),
79 'disabled' => esc_html__( 'Disable Pre-Orders', 'merchant' ),
80 ),
81 'default' => 'global',
82 'ai_meta' => array(),
83 ),
84 '_merchant_pre_order_start' => array(
85 'section' => 'merchant_pre_orders',
86 'type' => 'date_time',
87 'title' => esc_html__( 'Pre-Order Starts At', 'merchant' ),
88 'desc' => esc_html__( 'If you want your pre-order settings to take effect immediately, leave the pre-order start empty.', 'merchant' ),
89 'placeholder' => esc_html__( 'Select date and time', 'merchant' ),
90 'options' => array( 'timepicker' => true, 'minDate' => 'today' ),
91 'conditions' => array(
92 'relation' => 'AND',
93 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
94 ),
95 'ai_meta' => array( 'allow_empty' => true, 'usage_hint' => self::DATE_FORMAT_HINT ),
96 ),
97 '_merchant_pre_order_end' => array(
98 'section' => 'merchant_pre_orders',
99 'type' => 'date_time',
100 'title' => esc_html__( 'Pre-Order Ends At', 'merchant' ),
101 'desc' => sprintf(
102 /* Translators: %1$s: Time zone, %2$s WordPress setting link */
103 esc_html__( 'Leave it empty if you don’t want to have an end date. The times set above are in the %1$s timezone, according to your settings from %2$s.', 'merchant' ),
104 '<strong>' . wp_timezone_string() . '</strong>',
105 '<a href="' . esc_url( admin_url( 'options-general.php' ) ) . '" target="_blank">' . esc_html__( 'WordPress Settings', 'merchant' ) . '</a>'
106 ),
107 'placeholder' => esc_html__( 'Select date and time', 'merchant' ),
108 'options' => array( 'timepicker' => true, 'minDate' => 'today' ),
109 'conditions' => array(
110 'relation' => 'AND',
111 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
112 ),
113 'ai_meta' => array( 'allow_empty' => true, 'usage_hint' => self::DATE_FORMAT_HINT ),
114 ),
115 '_merchant_pre_order_shipping_date' => array(
116 'section' => 'merchant_pre_orders',
117 'type' => 'date_time',
118 'title' => esc_html__( 'Expected Shipping Date', 'merchant' ),
119 'desc' => sprintf(
120 /* Translators: %1$s: Time zone, %2$s WordPress setting link */
121 esc_html__( 'The times set above are in the %1$s timezone, according to your settings from %2$s.', 'merchant' ),
122 '<strong>' . wp_timezone_string() . '</strong>',
123 '<a href="' . esc_url( admin_url( 'options-general.php' ) ) . '" target="_blank">' . esc_html__( 'WordPress Settings', 'merchant' ) . '</a>'
124 ),
125 'placeholder' => esc_html__( 'Select date and time', 'merchant' ),
126 'options' => array( 'timepicker' => true, 'minDate' => 'today' ),
127 'conditions' => array(
128 'relation' => 'AND',
129 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
130 ),
131 'ai_meta' => array( 'allow_empty' => true, 'usage_hint' => self::DATE_FORMAT_HINT ),
132 ),
133 '_merchant_pre_order_discount_toggle' => array(
134 'section' => 'merchant_pre_orders',
135 'type' => 'switcher',
136 'title' => esc_html__( 'Offer Discount', 'merchant' ),
137 'desc' => esc_html__( 'Enable to offer a discount for pre-ordering this product.', 'merchant' ),
138 'default' => 0,
139 'conditions' => array(
140 'relation' => 'AND',
141 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
142 ),
143 'ai_meta' => array(),
144 ),
145 '_merchant_pre_order_discount_type' => array(
146 'section' => 'merchant_pre_orders',
147 'type' => 'radio',
148 'title' => esc_html__( 'Discount Type', 'merchant' ),
149 'options' => array(
150 'percentage' => esc_html__( 'Percentage', 'merchant' ),
151 'fixed' => esc_html__( 'Fixed Amount', 'merchant' ),
152 ),
153 'default' => 'percentage',
154 'conditions' => array(
155 'relation' => 'AND',
156 'terms' => array(
157 array( '_merchant_pre_order_mode', '==', 'product' ),
158 array( '_merchant_pre_order_discount_toggle', '==', '1' ),
159 ),
160 ),
161 'ai_meta' => array(),
162 ),
163 '_merchant_pre_order_discount_amount' => array(
164 'section' => 'merchant_pre_orders',
165 'type' => 'number',
166 'title' => esc_html__( 'Discount Amount', 'merchant' ),
167 'desc' => esc_html__( 'Enter the discount amount (percentage or fixed).', 'merchant' ),
168 'default' => 0,
169 'conditions' => array(
170 'relation' => 'AND',
171 'terms' => array(
172 array( '_merchant_pre_order_mode', '==', 'product' ),
173 array( '_merchant_pre_order_discount_toggle', '==', '1' ),
174 ),
175 ),
176 'ai_meta' => array(),
177 ),
178 '_merchant_pre_order_user_condition' => array(
179 'section' => 'merchant_pre_orders',
180 'type' => 'select',
181 'title' => esc_html__( 'User Condition', 'merchant' ),
182 'desc' => esc_html__( 'Who can pre-order this product?', 'merchant' ),
183 'options' => array(
184 'all' => esc_html__( 'All Users', 'merchant' ),
185 'roles' => esc_html__( 'Specific Roles', 'merchant' ),
186 'users' => esc_html__( 'Specific Users', 'merchant' ),
187 ),
188 'default' => 'all',
189 'conditions' => array(
190 'relation' => 'AND',
191 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
192 ),
193 'ai_meta' => array(),
194 ),
195 '_merchant_pre_order_user_condition_roles' => array(
196 'section' => 'merchant_pre_orders',
197 'type' => 'select',
198 'title' => esc_html__( 'Allowed Roles', 'merchant' ),
199 'desc' => esc_html__( 'This will limit the rule to users with these roles.', 'merchant' ),
200 'options' => self::get_user_roles_choices(),
201 'multiple' => true,
202 'conditions' => array(
203 'relation' => 'AND',
204 'terms' => array(
205 array( '_merchant_pre_order_mode', '==', 'product' ),
206 array( '_merchant_pre_order_user_condition', '==', 'roles' ),
207 ),
208 ),
209 'ai_meta' => array( 'options_callback' => array( __CLASS__, 'get_role_options' ) ),
210 ),
211 '_merchant_pre_order_user_condition_users' => array(
212 'section' => 'merchant_pre_orders',
213 'type' => 'select-ajax',
214 'title' => esc_html__( 'Allowed Users', 'merchant' ),
215 'desc' => esc_html__( 'This will limit the rule to the selected customers.', 'merchant' ),
216 'source' => 'user',
217 'multiple' => true,
218 'conditions' => array(
219 'relation' => 'AND',
220 'terms' => array(
221 array( '_merchant_pre_order_mode', '==', 'product' ),
222 array( '_merchant_pre_order_user_condition', '==', 'users' ),
223 ),
224 ),
225 'ai_meta' => array(),
226 ),
227 '_merchant_pre_order_user_exclusion_enabled' => array(
228 'section' => 'merchant_pre_orders',
229 'type' => 'switcher',
230 'title' => esc_html__( 'Enable Exclusions', 'merchant' ),
231 'desc' => esc_html__( 'Select the users that will not show the offer.', 'merchant' ),
232 'default' => 0,
233 'conditions' => array(
234 'relation' => 'AND',
235 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
236 ),
237 'ai_meta' => array(),
238 ),
239 '_merchant_pre_order_exclude_roles' => array(
240 'section' => 'merchant_pre_orders',
241 'type' => 'select',
242 'title' => esc_html__( 'Excluded Roles', 'merchant' ),
243 'desc' => esc_html__( 'This will exclude the offer for users with these roles.', 'merchant' ),
244 'options' => self::get_user_roles_choices(),
245 'multiple' => true,
246 'conditions' => array(
247 'relation' => 'AND',
248 'terms' => array(
249 array( '_merchant_pre_order_mode', '==', 'product' ),
250 array( '_merchant_pre_order_user_exclusion_enabled', '==', '1' ),
251 ),
252 ),
253 'ai_meta' => array( 'options_callback' => array( __CLASS__, 'get_role_options' ) ),
254 ),
255 '_merchant_pre_order_exclude_users' => array(
256 'section' => 'merchant_pre_orders',
257 'type' => 'select-ajax',
258 'title' => esc_html__( 'Excluded Users', 'merchant' ),
259 'desc' => esc_html__( 'This will exclude the offer for the selected customers.', 'merchant' ),
260 'source' => 'user',
261 'multiple' => true,
262 'conditions' => array(
263 'relation' => 'AND',
264 'terms' => array(
265 array( '_merchant_pre_order_mode', '==', 'product' ),
266 array( '_merchant_pre_order_user_exclusion_enabled', '==', '1' ),
267 ),
268 ),
269 'ai_meta' => array(),
270 ),
271 '_merchant_pre_order_button_text' => array(
272 'section' => 'merchant_pre_orders',
273 'type' => 'text',
274 'title' => esc_html__( 'Button Text', 'merchant' ),
275 'desc' => esc_html__( 'Custom text for the pre-order button.', 'merchant' ),
276 'placeholder' => esc_html__( 'Pre-Order Now', 'merchant' ),
277 'conditions' => array(
278 'relation' => 'AND',
279 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
280 ),
281 'ai_meta' => array(),
282 ),
283 '_merchant_pre_order_cart_label_text' => array(
284 'section' => 'merchant_pre_orders',
285 'type' => 'text',
286 'title' => esc_html__( 'Cart Label Text', 'merchant' ),
287 'desc' => esc_html__( 'Text to display in the cart for pre-order items.', 'merchant' ),
288 'placeholder' => esc_html__( 'Pre-Order', 'merchant' ),
289 'conditions' => array(
290 'relation' => 'AND',
291 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
292 ),
293 'ai_meta' => array(),
294 ),
295 '_merchant_pre_order_additional_text' => array(
296 'section' => 'merchant_pre_orders',
297 'type' => 'text',
298 'title' => esc_html__( 'Additional Information Text', 'merchant' ),
299 'desc' => __( 'Additional text to display on the product page, use <strong>{date}</strong> to display the shipping date.', 'merchant' ),
300 'placeholder' => esc_html__( 'Ships on {date}', 'merchant' ),
301 'conditions' => array(
302 'relation' => 'AND',
303 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
304 ),
305 'ai_meta' => array(),
306 ),
307 '_merchant_pre_order_placement' => array(
308 'section' => 'merchant_pre_orders',
309 'type' => 'radio',
310 'title' => esc_html__( 'Placement', 'merchant' ),
311 'desc' => esc_html__( 'Choose where to display the pre-order information.', 'merchant' ),
312 'options' => array(
313 'before' => esc_html__( 'Before Button', 'merchant' ),
314 'after' => esc_html__( 'After Button', 'merchant' ),
315 ),
316 'default' => 'before',
317 'conditions' => array(
318 'relation' => 'AND',
319 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
320 ),
321 'ai_meta' => array(),
322 ),
323 '_merchant_pre_order_text_color' => array(
324 'section' => 'merchant_pre_orders',
325 'type' => 'color',
326 'title' => esc_html__( 'Button Text Color', 'merchant' ),
327 'default' => '#ffffff',
328 'conditions' => array(
329 'relation' => 'AND',
330 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
331 ),
332 'ai_meta' => array(),
333 ),
334 '_merchant_pre_order_text_hover_color' => array(
335 'section' => 'merchant_pre_orders',
336 'type' => 'color',
337 'title' => esc_html__( 'Button Text Color (Hover)', 'merchant' ),
338 'default' => '#ffffff',
339 'conditions' => array(
340 'relation' => 'AND',
341 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
342 ),
343 'ai_meta' => array(),
344 ),
345 '_merchant_pre_order_border_color' => array(
346 'section' => 'merchant_pre_orders',
347 'type' => 'color',
348 'title' => esc_html__( 'Button Border Color', 'merchant' ),
349 'default' => '#212121',
350 'conditions' => array(
351 'relation' => 'AND',
352 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
353 ),
354 'ai_meta' => array(),
355 ),
356 '_merchant_pre_order_border_hover_color' => array(
357 'section' => 'merchant_pre_orders',
358 'type' => 'color',
359 'title' => esc_html__( 'Button Border Color (Hover)', 'merchant' ),
360 'default' => '#000000',
361 'conditions' => array(
362 'relation' => 'AND',
363 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
364 ),
365 'ai_meta' => array(),
366 ),
367 '_merchant_pre_order_border_width' => array(
368 'section' => 'merchant_pre_orders',
369 'type' => 'range',
370 'title' => esc_html__( 'Button Border Width (px)', 'merchant' ),
371 'min' => 0,
372 'max' => 10,
373 'step' => 1,
374 'default' => 0,
375 'conditions' => array(
376 'relation' => 'AND',
377 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
378 ),
379 'ai_meta' => array(),
380 ),
381 '_merchant_pre_order_border_radius' => array(
382 'section' => 'merchant_pre_orders',
383 'type' => 'range',
384 'title' => esc_html__( 'Button Border Radius (px)', 'merchant' ),
385 'min' => 0,
386 'max' => 50,
387 'step' => 1,
388 'default' => 0,
389 'conditions' => array(
390 'relation' => 'AND',
391 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
392 ),
393 'ai_meta' => array(),
394 ),
395 '_merchant_pre_order_background_color' => array(
396 'section' => 'merchant_pre_orders',
397 'type' => 'color',
398 'title' => esc_html__( 'Button Background Color', 'merchant' ),
399 'default' => '#212121',
400 'conditions' => array(
401 'relation' => 'AND',
402 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
403 ),
404 'ai_meta' => array(),
405 ),
406 '_merchant_pre_order_background_hover_color' => array(
407 'section' => 'merchant_pre_orders',
408 'type' => 'color',
409 'title' => esc_html__( 'Button Background Color (Hover)', 'merchant' ),
410 'default' => '#000000',
411 'conditions' => array(
412 'relation' => 'AND',
413 'terms' => array( array( '_merchant_pre_order_mode', '==', 'product' ) ),
414 ),
415 'ai_meta' => array(),
416 ),
417 );
418 }
419
420 /**
421 * Resolve the allowed role slugs for the multiselect role fields.
422 *
423 * REST-safe (wp_roles() is always available); the ability validator's
424 * options_callback for the two role fields resolves through this.
425 *
426 * @return array<int, string>
427 */
428 public static function get_role_options() {
429 return array_keys( wp_roles()->roles );
430 }
431
432 /**
433 * Get user roles for select choices.
434 *
435 * @return array User roles choices.
436 */
437 private static function get_user_roles_choices() {
438 $user_roles = Merchant_Admin_Options::get_user_roles_select2_choices();
439
440 if ( empty( $user_roles ) || ! is_array( $user_roles ) ) {
441 return array();
442 }
443
444 return array_column( $user_roles, 'text', 'id' );
445 }
446 }
447
448 // Initialize the metabox
449 new Merchant_Pre_Orders_Metabox();
450