PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 1.9.11
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v1.9.11
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 / admin / classes / class-merchant-admin-options.php

class-merchant-admin-options.php in Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant 1.9.11, at admin/classes/class-merchant-admin-options.php

2,466 lines 82.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Merchant_Admin_Options Class.
4 */
5
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit; // Exit if accessed directly
8 }
9
10 if ( ! class_exists( 'Merchant_Admin_Options' ) ) {
11 class Merchant_Admin_Options {
12
13 /**
14 * The single class instance.
15 */
16 private static $instance = null;
17
18 /**
19 * Instance.
20 */
21 public static function instance() {
22 if ( is_null( self::$instance ) ) {
23 self::$instance = new self();
24 }
25
26 return self::$instance;
27 }
28
29 /**
30 * Constructor.
31 */
32 public function __construct() {
33 // Enqueue hooks.
34 add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
35
36 // Ajax callbacks.
37 add_action( 'wp_ajax_merchant_create_page_control', array( $this, 'create_page_control_ajax_callback' ) );
38 add_action( 'wp_ajax_merchant_admin_options_select_ajax', array( $this, 'select_content_ajax' ) );
39 add_action( 'wp_ajax_merchant_admin_products_search', array( $this, 'products_search' ) );
40
41 add_action( 'clean_user_cache', array( $this, 'clear_customer_choices_cache' ), 10, 2 );
42 }
43
44 /**
45 * Enqueue scripts.
46 */
47 public function enqueue_scripts() {
48 if (
49 isset( $_GET['page'] ) && 'merchant' === $_GET['page'] // phpcs:ignore WordPress.Security.NonceVerification.Recommended
50 && isset( $_GET['module'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended
51 ) {
52 wp_enqueue_script( 'merchant-select2', MERCHANT_URI . 'assets/vendor/select2/select2.full.min.js', array( 'jquery' ), '4.0.13', true );
53 wp_enqueue_style( 'merchant-select2', MERCHANT_URI . 'assets/vendor/select2/select2.min.css', array(), '4.0.13', 'all' );
54
55 wp_localize_script( 'merchant-select2', 'merchant_admin_options', array(
56 'ajaxurl' => admin_url( 'admin-ajax.php' ),
57 'ajaxnonce' => wp_create_nonce( 'merchant_admin_options' ),
58 'product_delete_confirmation_message' => esc_html__( 'Are you sure you want to remove this product?', 'merchant' ),
59 ) );
60
61 wp_enqueue_style('date-picker', MERCHANT_URI . 'assets/vendor/air-datepicker/air-datepicker.css', array(), MERCHANT_VERSION, 'all' );
62 wp_enqueue_script('date-picker', MERCHANT_URI . 'assets/vendor/air-datepicker/air-datepicker.js', array( 'jquery' ), MERCHANT_VERSION, true );
63 wp_localize_script( 'date-picker', 'merchant_datepicker_locale', array(
64 wp_json_encode(
65 array(
66 'days' => array(
67 esc_html__( 'Sunday', 'merchant' ),
68 esc_html__( 'Monday', 'merchant' ),
69 esc_html__( 'Tuesday', 'merchant' ),
70 esc_html__( 'Wednesday', 'merchant' ),
71 esc_html__( 'Thursday', 'merchant' ),
72 esc_html__( 'Friday', 'merchant' ),
73 esc_html__( 'Saturday', 'merchant' ),
74 ),
75 'daysShort' => array(
76 esc_html__( 'Sun', 'merchant' ),
77 esc_html__( 'Mon', 'merchant' ),
78 esc_html__( 'Tue', 'merchant' ),
79 esc_html__( 'Wed', 'merchant' ),
80 esc_html__( 'Thu', 'merchant' ),
81 esc_html__( 'Fri', 'merchant' ),
82 esc_html__( 'Sat', 'merchant' ),
83 ),
84 'daysMin' => array(
85 esc_html__( 'Su', 'merchant' ),
86 esc_html__( 'Mo', 'merchant' ),
87 esc_html__( 'Tu', 'merchant' ),
88 esc_html__( 'We', 'merchant' ),
89 esc_html__( 'Th', 'merchant' ),
90 esc_html__( 'Fr', 'merchant' ),
91 esc_html__( 'Sa', 'merchant' ),
92 ),
93 'months' => array(
94 esc_html__( 'January', 'merchant' ),
95 esc_html__( 'February', 'merchant' ),
96 esc_html__( 'March', 'merchant' ),
97 esc_html__( 'April', 'merchant' ),
98 esc_html__( 'May', 'merchant' ),
99 esc_html__( 'June', 'merchant' ),
100 esc_html__( 'July', 'merchant' ),
101 esc_html__( 'August', 'merchant' ),
102 esc_html__( 'September', 'merchant' ),
103 esc_html__( 'October', 'merchant' ),
104 esc_html__( 'November', 'merchant' ),
105 esc_html__( 'December', 'merchant' ),
106 ),
107 'monthsShort' => array(
108 esc_html__( 'Jan', 'merchant' ),
109 esc_html__( 'Feb', 'merchant' ),
110 esc_html__( 'Mar', 'merchant' ),
111 esc_html__( 'Apr', 'merchant' ),
112 esc_html__( 'May', 'merchant' ),
113 esc_html__( 'Jun', 'merchant' ),
114 esc_html__( 'Jul', 'merchant' ),
115 esc_html__( 'Aug', 'merchant' ),
116 esc_html__( 'Sep', 'merchant' ),
117 esc_html__( 'Oct', 'merchant' ),
118 esc_html__( 'Nov', 'merchant' ),
119 esc_html__( 'Dec', 'merchant' ),
120 ),
121 )
122 ),
123 ) );
124 }
125 }
126
127 /**
128 * Ajax callbacks.
129 */
130 public function create_page_control_ajax_callback() {
131 check_ajax_referer( 'customize-create-page-control-nonce', 'nonce' );
132
133 // Check current user capabilities
134 if ( ! current_user_can( 'manage_options' ) ) {
135 wp_send_json_error( 'You are not allowed to do this.' );
136 }
137
138 $page_title = isset( $_POST['page_title'] ) ? sanitize_text_field( $_POST['page_title'] ) : '';
139 $page_meta_key = isset( $_POST['page_meta_key'] ) ? sanitize_text_field( $_POST['page_meta_key'] ) : '';
140 $page_meta_value = isset( $_POST['page_meta_value'] ) ? sanitize_text_field( $_POST['page_meta_value'] ) : '';
141 $option_name = isset( $_POST['option_name'] ) ? sanitize_text_field( $_POST['option_name'] ) : '';
142
143 $meta_input = array();
144 if ( $page_meta_key && $page_meta_value ) {
145 $meta_input = array(
146 $page_meta_key => $page_meta_value,
147 );
148 }
149
150 $postarr = array(
151 'post_type' => 'page',
152 'post_status' => 'publish',
153 'post_title' => $page_title,
154 'post_content' => '',
155 'meta_input' => $meta_input,
156 );
157
158 $page_id = wp_insert_post( $postarr );
159
160 if ( ! is_wp_error( $page_id ) ) {
161 if ( $option_name ) {
162 update_option( $option_name, $page_id );
163 }
164
165 wp_send_json( array(
166 'status' => 'success',
167 'page_id' => $page_id,
168 ) );
169 } else {
170 wp_send_json( array(
171 'status' => 'error',
172 ) );
173 }
174 }
175
176 /**
177 * Select content ajax callback.
178 *
179 */
180 public function select_content_ajax() {
181 $term = ( isset( $_GET['term'] ) ) ? sanitize_text_field( wp_unslash( $_GET['term'] ) ) : '';
182 $nonce = ( isset( $_GET['nonce'] ) ) ? sanitize_text_field( wp_unslash( $_GET['nonce'] ) ) : '';
183 $source = ( isset( $_GET['source'] ) ) ? sanitize_text_field( wp_unslash( $_GET['source'] ) ) : '';
184
185 // Check current user capabilities
186 if ( ! current_user_can( 'manage_options' ) ) {
187 wp_send_json_error( 'You are not allowed to do this.' );
188 }
189
190 if ( ! empty( $term ) && ! empty( $source ) && ! empty( $nonce ) && wp_verify_nonce( $nonce, 'merchant_admin_options' ) ) {
191 $options = array();
192
193 switch ( $source ) {
194 case 'post':
195 case 'product':
196 $query = new WP_Query( array(
197 's' => $term,
198 'post_type' => $source,
199 'post_status' => 'publish',
200 'posts_per_page' => 25,
201 'order' => 'DESC',
202 ) );
203
204 if ( ! empty( $query->posts ) ) {
205 foreach ( $query->posts as $post ) {
206 $options[] = array(
207 'id' => $post->ID,
208 'text' => $post->post_title,
209 );
210 }
211 }
212
213 break;
214
215 case 'user':
216 $query = new WP_User_Query( array(
217 'search' => '*' . $term . '*',
218 'search_columns' => array( 'user_login', 'user_nicename', 'user_email', 'user_url' ),
219 'number' => 25,
220 ) );
221
222 if ( ! empty( $query->results ) ) {
223 foreach ( $query->results as $user ) {
224 $options[] = array(
225 'id' => $user->ID,
226 'text' => $user->display_name,
227 );
228 }
229 }
230
231 break;
232 }
233
234 wp_send_json_success( $options );
235 } else {
236 wp_send_json_error();
237 }
238 }
239
240 /**
241 * Get option.
242 */
243 public static function get( $module, $setting, $default_val ) {
244 $options = get_option( 'merchant', array() );
245
246 $value = $default_val;
247
248 if ( isset( $options[ $module ][ $setting ] ) ) {
249 $value = $options[ $module ][ $setting ];
250 }
251
252 /**
253 * Hook: merchant_get_option filter.
254 * Fires after getting module option.
255 *
256 * @param mixed $value Option value.
257 * @param string $module Module ID.
258 * @param string $setting Setting ID.
259 * @param mixed $default_val Default value.
260 *
261 * @since 1.9.3
262 */
263 return apply_filters( 'merchant_get_option', $value, $module, $setting, $default_val );
264 }
265
266 /**
267 * Set option.
268 */
269 public static function set( $module, $setting, $value ) {
270 $options = get_option( 'merchant', array() );
271 $options[ $module ][ $setting ] = $value;
272 update_option( 'merchant', $options );
273 }
274
275 /**
276 * Delete option.
277 */
278 public static function delete( $module, $setting ) {
279 $options = get_option( 'merchant', array() );
280 unset( $options[ $module ][ $setting ] );
281 update_option( 'merchant', $options );
282 }
283
284 /**
285 * Get all options.
286 */
287 public static function get_all( $module ) {
288 $options = get_option( 'merchant', array() );
289 $value = array();
290
291 if ( isset( $options[ $module ] ) ) {
292 $value = $options[ $module ];
293 }
294
295 return $value;
296 }
297
298 /**
299 * Create options.
300 */
301 public static function create( $settings ) {
302 $module_id = ( isset( $_GET['module'] ) ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
303
304 /**
305 * Hook: merchant_module_settings
306 *
307 * @param array $settings Module settings.
308 * @param string $module_id Module ID.
309 *
310 * @since 1.0
311 */
312 $settings = apply_filters( 'merchant_module_settings', $settings, $module_id );
313
314 self::save_options( $settings );
315
316 $options = get_option( 'merchant', array() );
317
318 ?>
319 <div class="merchant-module-page-settings">
320 <div class="merchant-module-page-setting-box">
321 <?php
322 if ( ! empty( $settings['title'] ) ) : ?>
323 <div class="merchant-module-page-setting-title">
324 <?php
325 echo esc_html( $settings['title'] ); ?>
326 <?php
327 if ( ! empty( $settings['subtitle'] ) ) : ?>
328 <div class="merchant-module-page-setting-subtitle"><?php
329 echo esc_html( $settings['subtitle'] ); ?></div>
330 <?php
331 endif; ?>
332 </div>
333 <?php
334 endif; ?>
335 <div class="merchant-module-page-setting-fields">
336 <?php
337
338 if ( ! empty( $settings['fields'] ) ) {
339 foreach ( $settings['fields'] as $field ) {
340 $value = null;
341
342 if ( isset( $field['default'] ) ) {
343 $value = $field['default'];
344 }
345
346 if ( isset( $field['id'] ) && isset( $options[ $settings['module'] ] ) && isset( $options[ $settings['module'] ][ $field['id'] ] ) ) {
347 $value = $options[ $settings['module'] ][ $field['id'] ];
348 }
349
350 $module_info = Merchant_Admin_Modules::get_module_info( $settings['module'] );
351 if ( ( $module_info && $module_info['pro'] ) && ! defined( 'MERCHANT_PRO_DIR' ) ) {
352 self::disabled_field( $field, $value );
353 } else {
354 self::field( $field, $value, $module_id );
355 }
356 }
357 }
358
359 ?>
360 </div>
361 </div>
362 </div>
363 <?php
364 }
365
366 /**
367 * Save options.
368 */
369 public static function save_options( $settings ) {
370 $save = ( isset( $_POST['merchant_save'] ) ) ? sanitize_text_field( wp_unslash( $_POST['merchant_save'] ) ) : '';
371 $reset = ( isset( $_POST['merchant_reset'] ) ) ? sanitize_text_field( wp_unslash( $_POST['merchant_reset'] ) ) : '';
372 $nonce = ( isset( $_POST['merchant_nonce'] ) ) ? sanitize_text_field( wp_unslash( $_POST['merchant_nonce'] ) ) : '';
373
374 if ( ! wp_verify_nonce( $nonce, 'merchant_nonce' ) ) {
375 return;
376 }
377
378 if ( ! current_user_can( 'manage_options' ) ) {
379 return;
380 }
381
382 $options = get_option( 'merchant', array() );
383
384 if ( ! empty( $save ) ) {
385 if ( ! empty( $settings['fields'] ) ) {
386 foreach ( $settings['fields'] as $field ) {
387 if ( ! isset( $field['id'] ) ) {
388 continue;
389 }
390
391 $value = null;
392
393 if ( isset( $_POST['merchant'] ) && isset( $_POST['merchant'][ $field['id'] ] ) ) {
394 if ( 'textarea_code' === $field['type'] ) {
395 $value = wp_kses( $_POST['merchant'][ $field['id'] ], merchant_kses_allowed_tags_for_code_snippets() );
396 } elseif ( 'textarea_multiline' === $field['type'] ) {
397 $value = sanitize_textarea_field( $_POST['merchant'][ $field['id'] ] );
398 } elseif ( is_array( $_POST['merchant'][ $field['id'] ] ) ) {
399 $value = array_filter( map_deep( wp_unslash( $_POST['merchant'][ $field['id'] ] ), 'sanitize_text_field' ) );
400 } else {
401 $value = sanitize_text_field( wp_unslash( $_POST['merchant'][ $field['id'] ] ) );
402 }
403 }
404
405
406 $options[ $settings['module'] ][ $field['id'] ] = self::sanitize( $field, $value );
407 }
408 }
409 } elseif ( ! empty( $reset ) ) {
410 $options[ $settings['module'] ] = array();
411 }
412
413 update_option( 'merchant', $options );
414
415 /**
416 * Hook: merchant_options_saved, fired after saving module options.
417 *
418 * @param string $module module ID.
419 * @param array $options module options.
420 *
421 * @since 1.9.3
422 */
423 do_action( 'merchant_options_saved', $settings['module'], $options[ $settings['module'] ] );
424
425 /**
426 * Hook: merchant_options_saved, fired after saving specific module options.
427 *
428 * @param array $options module options.
429 *
430 * @since 1.9.3
431 */
432 do_action( "merchant_options_saved_{$settings['module']}", $options[ $settings['module'] ] );
433 }
434
435 /**
436 * Sanitize options.
437 */
438 public static function sanitize( $field, $value ) {
439 // Callback for custom sanitize methods.
440 if ( ! empty( $field['sanitize'] ) && is_callable( $field['sanitize'] ) ) {
441 return call_user_func( $field['sanitize'], $value );
442 }
443
444 switch ( $field['type'] ) {
445 case 'text':
446 case 'color':
447 case 'number':
448 case 'select_size_chart':
449 $value = sanitize_text_field( $value );
450 break;
451
452 case 'textarea':
453 $value = sanitize_textarea_field( $value );
454 break;
455
456 case 'textarea_code':
457 $value = $value;
458 break;
459
460 case 'checkbox_multiple':
461 if ( is_array( $value ) && ! empty( $value ) ) {
462 $value = array_filter( array_map( 'sanitize_text_field', $value ) );
463 } else {
464 $value = array();
465 }
466 break;
467
468 case 'checkbox':
469 case 'switcher':
470 $value = ( '1' === $value ) ? 1 : 0;
471 break;
472
473 case 'range':
474 case 'number':
475 $value = absint( $value );
476 break;
477 case 'select_ajax':
478 if ( is_array( $value ) && ! empty( $value ) ) {
479 $value = array_filter( array_map( 'sanitize_text_field', $value ) );
480 } elseif ( is_string( $value ) ) {
481 $value = sanitize_text_field( $value );
482 } else {
483 $value = isset( $field['multiple'] ) && $field['multiple'] === false ? '' : array();
484 }
485 break;
486 case 'radio':
487 case 'radio_alt':
488 case 'select':
489 case 'choices':
490 case 'buttons':
491 case 'buttons_alt':
492 case 'buttons_content':
493 $value = ( in_array( $value, array_keys( $field['options'] ), true ) ) ? sanitize_key( $value ) : '';
494 break;
495
496 case 'hook_select':
497 $value = is_array( $value ) ? $value : array();
498
499 foreach ( $value as $key => $val ) {
500 if ( $key === 'hook_name' ) {
501 $value[ $key ] = in_array( $val, array_keys( $field['options'] ), true ) ? sanitize_key( $val ) : '';
502 } else {
503 $value[ $key ] = (int) $val;
504 }
505 }
506
507 break;
508
509 case 'code-editor':
510 $value = wp_kses_post( $value );
511 break;
512
513 case 'sortable':
514 $values = json_decode( $value );
515 $value = array();
516
517 foreach ( $values as $val ) {
518 if ( in_array( $val, array_keys( $field['options'] ), true ) ) {
519 $value[] = sanitize_key( $val );
520 }
521 }
522 break;
523 case 'dimensions':
524 $values = is_array( $value ) ? $value : array();
525
526 foreach ( $values as $key => $val ) {
527 if ( $key === 'unit' ) {
528 $value[ $key ] = sanitize_key( $value[ $key ] );
529 } else {
530 $value[ $key ] = absint( $value[ $key ] );
531 }
532 }
533 break;
534 case 'responsive_dimensions':
535 $values = is_array( $value ) ? $value : array();
536
537 foreach ( $values as $device => $device_fields ) {
538 foreach ( $device_fields as $device_field => $device_field_val ) {
539 if ( $device_field === 'unit' ) {
540 $value[ $device ][ $device_field ] = sanitize_key( $device_field_val );
541 } else {
542 $value[ $device ][ $device_field ] = absint( $device_field_val );
543 }
544 }
545 }
546 break;
547
548 case 'sortable_repeater':
549 $values = json_decode( $value );
550 $value = array_map( 'sanitize_text_field', $values );
551 break;
552 case 'flexible_content':
553 $value = ! is_array( $value ) || empty( $value ) ? array() : $value;
554
555 $value = array_map( function ( $sub_fields ) use ( $field ) {
556 foreach ( $sub_fields as $sub_field => $value ) {
557 if ( $sub_field === 'layout' ) {
558 $sub_fields[ $sub_field ] = sanitize_text_field( $value );
559 } else {
560 $layout_field = array_filter( $field['layouts'][ $sub_fields['layout'] ]['fields'], function ( $layout_field ) use ( $sub_field ) {
561 return $layout_field['id'] === $sub_field;
562 } );
563
564
565 $sub_fields[ $sub_field ] = self::sanitize( reset( $layout_field ), $value );
566 }
567 }
568
569 return $sub_fields;
570 }, $value );
571
572 break;
573 }
574
575 return $value;
576 }
577
578 /**
579 * Field
580 */
581 public static function field( $settings, $value, $module_id = '') {
582
583 if ( ! empty( $settings['type'] ) ) {
584 $type = $settings['type'];
585
586 $id = ( ! empty( $settings['id'] ) ) ? $settings['id'] : '';
587 $class = ( ! empty( $settings['class'] ) ) ? ' ' . $settings['class'] : '';
588 $condition = ( ! empty( $settings['condition'] ) ) ? $settings['condition'] : array();
589 $conditions = ( ! empty( $settings['conditions'] ) ) ? $settings['conditions'] : ''; //Docs here: https://github.com/athemes/Merchant/pull/133
590 $default = ( ! empty( $settings['default'] ) ) ? $settings['default'] : null;
591
592 if ( ! $value && ( 0 !== $value && '0' !== $value ) ) {
593 if ( $type === 'checkbox_multiple' ) {
594 $value = is_array( $default ) ? $default : array();
595 } else {
596 $value = $default;
597 }
598 }
599
600 $wrapper_classes = array( 'merchant-module-page-setting-field' );
601 $wrapper_classes[] = 'merchant-module-page-setting-field-' . $type;
602
603 if ( ! empty( $class ) ) {
604 $wrapper_classes[] = $class;
605 }
606
607 /**
608 * Hook 'merchant_admin_module_field_wrapper_classes'
609 *
610 * @since 1.9.3
611 */
612 $wrapper_classes = apply_filters( 'merchant_admin_module_field_wrapper_classes', $wrapper_classes, $settings, $value, $module_id );
613
614 echo '<div class="'. esc_attr( implode( ' ', $wrapper_classes ) ) .'" data-id="'
615 . esc_attr( $id ) . '" data-type="' . esc_attr( $type ) . '" data-condition="' . esc_attr( wp_json_encode( $condition ) ) .
616 '" data-conditions="' . ( $conditions ? esc_attr( wp_json_encode( $conditions ) ) : "" ) . '">';
617 if ( ! empty( $settings['title'] ) ) {
618 printf( '<div class="merchant-module-page-setting-field-title">%s</div>', esc_html( $settings['title'] ) );
619 }
620
621 echo '<div class="merchant-module-page-setting-field-inner merchant-field-' . esc_attr( $id ) . '">';
622 if ( method_exists( 'Merchant_Admin_Options', $type ) ) {
623 call_user_func( array( 'Merchant_Admin_Options', $type ), $settings, $value, $module_id );
624 } else {
625 esc_html_e( 'Field not found!', 'merchant' );
626 }
627 echo '</div>';
628
629 $hidden_desc = $settings['hidden_desc'] ?? '';
630
631 /**
632 * Hook 'merchant_admin_module_field_hidden_description'
633 *
634 * @since 1.9.3
635 */
636 $hidden_desc = apply_filters( 'merchant_admin_module_field_hidden_description', $hidden_desc, $settings, $value, $module_id );
637
638 $desc = ( ! empty( $settings['desc'] ) ) ? $settings['desc'] : '';
639
640 /**
641 * Hook 'merchant_admin_module_field_description'
642 *
643 * @since 1.9.3
644 */
645 $desc = apply_filters( 'merchant_admin_module_field_description', $desc, $settings, $value, $module_id );
646
647 if ( ! empty( $desc ) ) {
648 $hidden_desc_html = '';
649 if ( ! empty( $hidden_desc ) ) {
650 $hidden_desc_html = '<div class="merchant-module-page-setting-field-hidden-desc-trigger" data-show-text="' . esc_html__( 'Show more', 'merchant' ) . '" data-hidden-text="' . esc_html__( 'Show less', 'merchant' ) . '"><span>' . esc_html__( 'Show more', 'merchant' ) . '</span>';
651 $hidden_desc_html .= '<img src="' . esc_url( MERCHANT_URI . '/assets/images/arrow-down.svg' ) . '" alt="Merchant" />';
652 $hidden_desc_html .= '</div>';
653 }
654
655 printf( '<div class="merchant-module-page-setting-field-desc' . esc_attr( $hidden_desc ? ' merchant-module-page-setting-field-desc-has-hidden-desc' : '' ) .'">%s%s</div>', wp_kses_post( $desc ), wp_kses_post( $hidden_desc_html ) );
656 }
657
658 if ( ! empty( $hidden_desc ) ) {
659 printf( '<div class="merchant-module-page-setting-field-hidden-desc">%s</div>', wp_kses_post( nl2br( $hidden_desc ) ) );
660 }
661
662 echo '</div>';
663 }
664 }
665
666 /**
667 * Disabled field
668 *
669 * @param array $settings
670 * @param mixed $value
671 *
672 * @return void
673 */
674 public static function disabled_field( $settings, $value, $module_id = '') {
675 static::replace_field(
676 $settings,
677 $value,
678 array(
679 '<input ',
680 '<select ',
681 'merchant-module-page-setting-field-inner',
682 ),
683 array(
684 '<input disabled ',
685 '<select disabled ',
686 'merchant-module-page-setting-field-inner disabled',
687 ),
688 $module_id
689 );
690 }
691
692 /**
693 * Modified field.
694 *
695 * @param $settings
696 * @param $value
697 * @param $search
698 * @param $replace
699 *
700 * @return void
701 */
702 public static function replace_field( $settings, $value, $search, $replace, $module_id = '') {
703 ob_start();
704 self::field( $settings, $value, $module_id );
705 $field = ob_get_clean();
706
707 echo wp_kses( str_replace( $search, $replace, $field ), merchant_kses_allowed_tags( array( 'all' ) ) );
708 }
709
710 /**
711 * Field: Text
712 */
713 public static function text( $settings, $value, $module_id = '' ) {
714 ?>
715 <input type="text" name="merchant[<?php
716 echo esc_attr( $settings['id'] ); ?>]" value="<?php
717 echo esc_attr( $value ); ?>"/>
718 <?php
719 }
720
721 /**
722 * Field: Text (readonly)
723 */
724 public static function text_readonly( $settings, $value, $module_id = '' ) {
725 ?>
726 <input type="text" value="<?php
727 echo esc_attr( $value ); ?>" readonly/>
728 <?php
729 }
730
731 /**
732 * Field: Number
733 */
734 public static function number( $settings, $value, $module_id = '' ) {
735 ?>
736 <input type="number" name="merchant[<?php
737 echo esc_attr( $settings['id'] ); ?>]" value="<?php
738 echo esc_attr( $value ); ?>"<?php
739 echo isset( $settings['step'] ) ? ' step="' . esc_attr( $settings['step'] ) . '"' : '';
740 echo isset( $settings['max'] ) ? ' max="' . esc_attr( $settings['max'] ) . '"' : '';
741 echo isset( $settings['min'] ) ? ' min="' . esc_attr( $settings['min'] ) . '"' : '' ?>
742 placeholder="<?php echo esc_attr( $settings['placeholder'] ?? '' ); ?>"/>
743 <?php
744 }
745
746 /**
747 * Field: Textarea
748 */
749 public static function textarea( $settings, $value, $module_id = '' ) {
750 $value = ( $value ) ? $value : '';
751 ?>
752 <textarea name="merchant[<?php
753 echo esc_attr( $settings['id'] ); ?>]"><?php
754 echo wp_kses_post( $value ); ?></textarea>
755 <?php
756 }
757
758 /**
759 * Field: Textarea
760 */
761 public static function textarea_multiline( $settings, $value, $module_id = '' ) {
762 $value = ( $value ) ? $value : '';
763 ?>
764 <textarea name="merchant[<?php
765 echo esc_attr( $settings['id'] ); ?>]"><?php
766 echo wp_kses_post( $value ); ?></textarea>
767 <?php
768 }
769
770 /**
771 * Field: Textarea Code Snippet.
772 */
773 public static function textarea_code( $settings, $value, $module_id = '' ) {
774 $value = ( $value ) ? $value : '';
775 ?>
776 <textarea name="merchant[<?php
777 echo esc_attr( $settings['id'] ); ?>]"><?php
778 echo wp_kses( $value, merchant_kses_allowed_tags_for_code_snippets() ); ?></textarea>
779 <?php
780 }
781
782 /**
783 * Field: Checkbox
784 */
785 public static function checkbox( $settings, $value, $module_id = '' ) {
786 ?>
787 <div>
788 <label>
789 <input type="checkbox" name="merchant[<?php
790 echo esc_attr( $settings['id'] ); ?>]" value="1" <?php
791 checked( $value, 1, true ); ?> />
792 <?php
793 if ( ! empty( $settings['label'] ) ) : ?>
794 <span><?php
795 echo esc_html( $settings['label'] ); ?></span>
796 <?php
797 endif; ?>
798 </label>
799 </div>
800 <?php
801 }
802
803 /**
804 * Field: Checkbox multiple
805 */
806 public static function checkbox_multiple( $settings, $value ) {
807 if ( ! empty( $settings['options'] ) ) : ?>
808 <?php
809 foreach ( $settings['options'] as $key => $option ) : ?>
810 <label>
811 <input
812 type="checkbox" name="merchant[<?php echo esc_attr( $settings['id'] ); ?>][]"
813 value="<?php echo esc_attr( $key ); ?>"
814 <?php checked( in_array( $key, $value, true ), true ); ?>
815 />
816 <span><?php echo esc_html( $option ); ?></span>
817 </label>
818 <?php
819 endforeach; ?>
820 <?php
821 endif;
822 }
823
824 /**
825 * Field: Switcher
826 */
827 public static function switcher( $settings, $value, $module_id = '' ) {
828 ?>
829 <div class="merchant-toggle-switch">
830 <input type="checkbox" id="<?php
831 echo esc_attr( $settings['id'] ); ?>" name="merchant[<?php
832 echo esc_attr( $settings['id'] ); ?>]" value="1" <?php
833 checked( $value, 1, true ); ?>
834 class="toggle-switch-checkbox"/>
835 <label class="toggle-switch-label" for="<?php
836 echo esc_attr( $settings['id'] ); ?>">
837 <span class="toggle-switch-inner"></span>
838 <span class="toggle-switch-switch"></span>
839 </label>
840 <?php
841 if ( ! empty( $settings['label'] ) ) : ?>
842 <span><?php
843 echo esc_html( $settings['label'] ); ?></span>
844 <?php
845 endif; ?>
846 </div>
847 <?php
848 }
849
850 /**
851 * Field: Radio
852 */
853 public static function radio( $settings, $value, $module_id = '' ) {
854 ?>
855 <?php
856 if ( ! empty( $settings['options'] ) ) : ?>
857 <?php
858 foreach ( $settings['options'] as $key => $option ) : ?>
859 <label>
860 <input type="radio" name="merchant[<?php
861 echo esc_attr( $settings['id'] ); ?>]" value="<?php
862 echo esc_attr( $key ); ?>" <?php
863 checked( $value, $key, true ); ?>/>
864 <span><?php
865 echo esc_html( $option ); ?></span>
866 </label>
867 <?php
868 endforeach; ?>
869 <?php
870 endif; ?>
871 <?php
872 }
873
874 /**
875 * Field: Image picker
876 */
877 public static function image_picker( $settings, $value, $module_id = '' ) {
878 ?>
879 <div class="merchant-image-picker">
880 <?php
881 if ( ! empty( $settings['options'] ) ) : ?>
882 <?php
883 foreach ( $settings['options'] as $key => $option ) : ?>
884 <label>
885 <input type="radio" name="merchant[<?php
886 echo esc_attr( $settings['id'] ); ?>]" value="<?php
887 echo esc_attr( $key ); ?>" <?php
888 checked( $value, $key, true ); ?>/>
889 <?php
890 if ( isset( $option['image'] ) ) { ?>
891 <img src="<?php
892 echo esc_url( $option['image'] ) ?>" alt="">
893 <?php
894 } ?>
895 <?php
896 if ( isset( $option['title'] ) ) { ?>
897 <span class="tool-tip-text"><?php
898 echo esc_html( $option['title'] ) ?></span>
899 <?php
900 } ?>
901 </label>
902 <?php
903 endforeach; ?>
904 <?php
905 endif; ?>
906 </div>
907 <?php
908 }
909
910 /**
911 * Field: Radio Alt
912 */
913 public static function radio_alt( $settings, $value, $module_id = '' ) {
914 ?>
915 <?php
916 if ( ! empty( $settings['options'] ) ) : ?>
917 <?php
918 foreach ( $settings['options'] as $key => $option ) : ?>
919 <div>
920 <label>
921 <input type="radio" name="merchant[<?php
922 echo esc_attr( $settings['id'] ); ?>]" value="<?php
923 echo esc_attr( $key ); ?>" <?php
924 checked( $value, $key, true ); ?>/>
925 <span><?php
926 echo esc_html( $option['title'] ); ?></span>
927 </label>
928 <p><?php
929 echo esc_html( $option['desc'] ); ?></p>
930 </div>
931 <?php
932 endforeach; ?>
933 <?php
934 endif; ?>
935 <?php
936 }
937
938 /**
939 * Field: Choices
940 */
941 public static function choices( $settings, $value, $module_id = '' ) {
942 ?>
943 <div class="merchant-choices merchant-choices-<?php
944 echo esc_attr( $settings['id'] ) ?>">
945 <?php
946 if ( ! empty( $settings['options'] ) ) : ?>
947 <?php
948 foreach ( $settings['options'] as $key => $option ) : ?>
949 <label>
950 <input type="radio" name="merchant[<?php
951 echo esc_attr( $settings['id'] ); ?>]" value="<?php
952 echo esc_attr( $key ); ?>" <?php
953 checked( $value, $key, true ); ?>/>
954 <?php
955 if ( ! empty( $option['svg'] ) ) : ?>
956 <span class="merchant-svg">
957 <?php
958 echo wp_kses( Merchant_SVG_Icons::get_svg_icon( $option['svg'] ), merchant_kses_allowed_tags( array(), false ) ); ?>
959
960 <?php
961 if ( ! empty( $option['label'] ) ) : ?>
962 <span class="merchant-tooltip"><?php
963 echo esc_html( $option['label'] ); ?></span>
964 <?php
965 endif; ?>
966 </span>
967 <?php
968 else : ?>
969 <figure>
970 <?php if ( ! empty( $option['image'] ) ) :
971 $title = $option['title'] ?? '';
972 ?>
973 <img src="<?php echo esc_url( sprintf( $option['image'], MERCHANT_URI . 'assets/images' ) ); ?>" alt="<?php echo esc_attr( $title ); ?>" title="<?php echo esc_attr( $title ); ?>"/>
974 <?php
975 else : ?>
976 <img src="<?php
977 echo esc_url( sprintf( $option, MERCHANT_URI . 'assets/images' ) ); ?>"/>
978 <?php
979 endif; ?>
980 <?php
981 if ( ! empty( $option['label'] ) ) : ?>
982 <span class="merchant-tooltip"><?php
983 echo esc_html( $option['label'] ); ?></span>
984 <?php
985 endif; ?>
986 </figure>
987 <?php
988 endif; ?>
989 </label>
990 <?php
991 endforeach; ?>
992 <?php
993 endif; ?>
994 </div>
995 <?php
996 }
997
998 /**
999 * Field: Select
1000 */
1001 public static function select( $settings, $value, $module_id = '' ) {
1002 ?>
1003 <?php
1004 if ( ! empty( $settings['options'] ) ) : ?>
1005 <select name="merchant[<?php
1006 echo esc_attr( $settings['id'] ); ?>]">
1007 <?php
1008 foreach ( $settings['options'] as $key => $option ) : ?>
1009 <option value="<?php
1010 echo esc_attr( $key ); ?>" <?php
1011 selected( $value, $key, true ); ?>><?php
1012 echo esc_html( $option ); ?></option>
1013 <?php
1014 endforeach; ?>
1015 </select>
1016 <?php
1017 endif; ?>
1018 <?php
1019 }
1020
1021 /**
1022 * Field: Hook Select
1023 */
1024 public static function hook_select( $settings, $value, $module_id = '' ) {
1025 $hook_name = isset( $value['hook_name'] ) ? $value['hook_name'] : '';
1026 $hook_priority = isset( $value['hook_priority'] ) ? $value['hook_priority'] : '';
1027
1028 ?>
1029 <div class="merchant-module-page-setting-field-hook_select-wrapper">
1030 <div class="merchant-module-page-setting-field-select">
1031 <select name="merchant[<?php
1032 echo esc_attr( $settings['id'] ); ?>][hook_name]">
1033 <?php
1034 if ( ! empty( $settings['options'] ) ) : ?>
1035 <?php
1036 foreach ( $settings['options'] as $key => $option ) : ?>
1037 <option value="<?php
1038 echo esc_attr( $key ); ?>" <?php
1039 selected( $hook_name, $key, true ); ?>><?php
1040 echo esc_html( $option ); ?></option>
1041 <?php
1042 endforeach; ?>
1043 <?php
1044 endif; ?>
1045 </select>
1046 </div>
1047 <?php
1048
1049 if ( isset( $settings['order'] ) && true === $settings['order'] ) {
1050 ?>
1051 <div class="merchant-module-page-setting-field-number">
1052 <input type="number" name="merchant[<?php
1053 echo esc_attr( $settings['id'] ); ?>][hook_priority]" value="<?php
1054 echo esc_attr( $hook_priority ); ?>"/>
1055 </div>
1056 <?php
1057 } ?>
1058 </div>
1059
1060 <?php
1061 }
1062
1063 /**
1064 * Field: Select ajax
1065 *
1066 * @param $settings
1067 * @param $value
1068 *
1069 * @return void
1070 */
1071 public static function select_ajax( $settings, $value, $module_id = '' ) {
1072 $settings = wp_parse_args( $settings, array(
1073 'source' => 'post',
1074 ) );
1075
1076 $ids = ( is_array( $value ) && ! empty( $value ) ) ? $value : (array) $value;
1077
1078 if ( isset( $settings['multiple'] ) ) {
1079 $multiple = $settings['multiple'] === true ? 'multiple' : '';
1080 } else {
1081 $multiple = 'multiple';
1082 }
1083
1084 $placeholder = $settings['placeholder'] ?? '';
1085 ?>
1086 <select
1087 name="merchant[<?php echo esc_attr( $settings['id'] ); ?>]<?php echo esc_attr( $multiple ? '[]' : '' ); ?>"
1088 <?php echo esc_attr( $multiple ); ?>
1089 data-source="<?php echo esc_attr( $settings['source'] ); ?>"
1090 data-placeholder="<?php echo esc_attr( $placeholder ); ?>">
1091 <?php
1092 if ( ! empty( $ids ) ) {
1093 foreach ( $ids as $id ) {
1094 switch ( $settings['source'] ) {
1095 case 'post':
1096 case 'product':
1097 $post = get_post( $id );
1098
1099 if ( ! empty( $post ) ) {
1100 echo '<option value="' . esc_attr( $post->ID ) . '" selected>' . esc_html( $post->post_title ) . '</option>';
1101 }
1102 break;
1103 case 'user':
1104 $user = get_user_by( 'ID', $id );
1105 if( $user ) {
1106 echo '<option value="' . esc_attr( $user->ID ) . '" selected>' . esc_html( $user->display_name ) . '</option>';
1107 }
1108 break;
1109 case 'options':
1110 }
1111 }
1112 }
1113 if ( $settings['source'] === 'options' ) {
1114 $value = ! empty( $value ) ? $value : '';
1115
1116 foreach ( $settings['options'] as $option ) {
1117 if ( isset( $option['options'] ) ) {
1118 echo '<optgroup label="' . esc_attr( $option['text'] ) . '">';
1119
1120 foreach ( $option['options'] as $child_option ) {
1121 $selected_value = is_array( $value ) ? in_array( $child_option['id'], $value, true ) : $child_option['id'];
1122 echo '<option value="' . esc_attr( $child_option['id'] ) . '" ' . selected( $selected_value, is_array( $value ) ? true : $value, false ) . '>' . esc_html( $child_option['text'] )
1123 . '</option>';
1124 }
1125
1126 echo '</optgroup>';
1127 } else {
1128 $selected_value = is_array( $value ) ? in_array( $option['id'], $value, true ) : $option['id'];
1129 echo '<option value="' . esc_attr( $option['id'] ) . '" ' . selected( $selected_value, is_array( $value ) ? true : $value, false ) . '>' . esc_html( $option['text'] ) . '</option>';
1130 }
1131 }
1132 } ?>
1133 </select>
1134 <?php
1135 }
1136
1137 /**
1138 * Field: Info Block
1139 *
1140 * @return void
1141 */
1142 public static function info_block( $settings, $value, $module_id = '' ) {
1143 ?>
1144 <div class="merchant-info-block">
1145 <i class="dashicons dashicons-info"></i>
1146 <p><?php
1147 echo ! empty( $settings['description'] ) ? esc_html( $settings['description'] ) : ''; ?><?php
1148 if ( ! empty( $settings['button_text'] ) && ! empty( $settings['button_link'] ) ) {
1149 printf( '<a href="%s" target="_blank">%s</a>', esc_url( $settings['button_link'] ), esc_html( $settings['button_text'] ) );
1150 } ?></p>
1151 </div>
1152 <?php
1153 }
1154
1155 /**
1156 * Field: Products Selector
1157 *
1158 * @param $settings
1159 * @param $value
1160 *
1161 * @return void
1162 */
1163 public static function products_selector( $settings, $value, $module_id = '' ) {
1164 if ( ! class_exists( 'WooCommerce' ) ) {
1165 echo '<p class="merchant-notice">' . esc_html__( 'WooCommerce is not installed or activated.', 'merchant' ) . '</p>';
1166
1167 return;
1168 }
1169
1170 $ids = $value ? explode( ',', $value ) : array();
1171
1172 if ( isset( $settings['multiple'] ) ) {
1173 $multiple = $settings['multiple'] === true ? 'multiple' : 'false';
1174 } else {
1175 $multiple = 'multiple';
1176 }
1177
1178 if ( ! isset( $settings['allowed_types'] ) ) {
1179 $settings['allowed_types'] = array( 'all' );
1180 }
1181 ?>
1182
1183 <div class="merchant-products-search-container" data-multiple="<?php
1184 echo esc_attr( $multiple ); ?>">
1185 <div class="merchant-search-area">
1186 <input type="text" name="merchant-search-field" data-allowed-types="<?php
1187 echo esc_attr( implode( ',', $settings['allowed_types'] ) ) ?>" placeholder="<?php
1188 esc_attr_e( 'Search products', 'merchant' ); ?>" class="merchant-search-field">
1189 <span class="merchant-searching"><?php
1190 esc_html_e( 'Searching...', 'merchant' ); ?></span>
1191 <img src="<?php echo esc_url( MERCHANT_URI . 'assets/images/admin/products-search-icon.svg' ); ?>" class="merchant-search-icon"
1192 alt="<?php esc_attr_e( 'Search icon', 'merchant' ); ?>">
1193 <div class="merchant-selections-products-preview"></div>
1194 </div>
1195 <div class="merchant-selected-products-preview">
1196 <ul>
1197 <?php
1198 if ( ! empty( $ids ) ) {
1199 foreach ( $ids as $product_id ) {
1200 $product = wc_get_product( $product_id );
1201 if ( $product ) {
1202 self::product_data_li( $product );
1203 }
1204 }
1205 }
1206 ?>
1207 </ul>
1208 </div>
1209 <input type="hidden" name="merchant[<?php
1210 echo esc_attr( $settings['id'] ); ?>]" class="merchant-selected-products" value="<?php
1211 echo esc_attr( $value ) ?>">
1212 </div>
1213 <?php
1214 }
1215
1216 public static function product_data_li( $product, $search = false, $hierarchy = false ) {
1217 $product_id = $product->get_id();
1218 $product_sku = $product->get_sku();
1219 $product_name = $product->get_name();
1220 $edit_link = get_edit_post_link( $product_id );
1221 if ( $product->is_type( 'variation' ) ) {
1222 $edit_link = get_edit_post_link( $product->get_parent_id() );
1223 }
1224
1225 /**
1226 * Filter product image.
1227 *
1228 * @since 1.9.1
1229 */
1230 $product_image = apply_filters(
1231 'merchant_product_item_product_image',
1232 '<span class="img">' . $product->get_image( array( 30, 30 ) ) . '</span>',
1233 $product
1234 );
1235
1236 $price = $product->get_price();
1237 $key = $product_id . '_' . $product_sku;
1238
1239 /**
1240 * Filter the product bundle item product info.
1241 *
1242 * @param string $product_info The product bundle item product info.
1243 * @param WC_Product $product The product object.
1244 *
1245 * @since 1.9.0
1246 */
1247 $product_info = apply_filters( 'merchant_pro_product_bundle_item_product_info', $product->get_type() . '<br/>#' . $product_id, $product );
1248 if ( $search ) {
1249 $remove_btn = '<span class="remove hint--left" aria-label="' . esc_html__( 'Add', 'merchant' ) . '">+</span>';
1250 } else {
1251 $remove_btn = '<span class="remove hint--left" aria-label="' . esc_html__( 'Remove', 'merchant' ) . '">×</span>';
1252 }
1253
1254 $item_class = 'product-item';
1255 if( $hierarchy && $product->is_type( 'variation' ) ) {
1256 $item_class .= ' hierarchy-style';
1257 }
1258
1259 echo '<li class="' . esc_attr( $item_class ) . '" data-key="' . esc_attr( $key ) . '" data-name="' . esc_attr( $product_name ) . '" data-sku="'
1260 . esc_attr( $product_sku ) . '" data-id="' . esc_attr( $product_id ) . '" data-price="' . esc_attr( $price ) . '">'
1261 . wp_kses( $product_image, array(
1262 'span' => array(
1263 'class' => true,
1264 ),
1265 'img' => array(
1266 'src' => true,
1267 'alt' => true,
1268 'decoding' => true,
1269 'srcset' => true,
1270 'loading' => true,
1271 'sizes' => true,
1272 'class' => true,
1273 'width' => true,
1274 'height' => true,
1275 ),
1276 ) ) . '<span class="data">'
1277 . '<span class="name">' . esc_html( $product_name ) . '</span><span class="info">' . wp_kses( $product->get_price_html(), array(
1278 'span' => array(
1279 'class' => true,
1280 ),
1281 'del' => array(
1282 'aria-hidden' => true,
1283 ),
1284 'ins' => array(),
1285 'bdi' => array(),
1286
1287 ) ) . '</span> ' . ( $product->is_sold_individually()
1288 ? '<span class="info">' . esc_html__( 'sold individually', 'merchant' ) . '</span> ' : '' ) . '</span>'
1289 . '<span class="type"><a href="' . esc_url( $edit_link ) . '" target="_blank">' . wp_kses_post( $product_info ) . '</a></span> ' . wp_kses( $remove_btn, array(
1290 'span' => array(
1291 'class' => true,
1292 'aria-label' => true,
1293 ),
1294 ) );
1295
1296 echo '</li>';
1297 }
1298
1299 public function products_search() {
1300 check_ajax_referer( 'merchant_admin_options', 'nonce' );
1301
1302 if ( ! isset( $_POST['keyword'] ) || empty( $_POST['keyword'] ) ) {
1303 exit();
1304 }
1305
1306 $types = array( 'simple', 'variable' ); // limit search to product types
1307
1308 if ( isset( $_POST['product_types'] ) || ! empty( $_POST['product_types'] ) ) {
1309 $types = explode( ',', sanitize_text_field( $_POST['product_types'] ) );
1310 }
1311
1312 $hierarchy = false;
1313 if (
1314 in_array( 'all', $types, true )
1315 || ( in_array( 'variation', $types, true ) && in_array( 'variable', $types, true ) )
1316 ) {
1317 $hierarchy = true;
1318 }
1319
1320 $added_ids = isset( $_POST['ids'] ) ? explode( ',', sanitize_text_field( $_POST['ids'] ) ) : array();
1321 $keyword = sanitize_text_field( $_POST['keyword'] );
1322 if ( is_numeric( $keyword ) ) {
1323 // search by id
1324 $query_args = array(
1325 'p' => absint( $keyword ),
1326 'post_type' => 'product',
1327 );
1328 } else {
1329 $query_args = array(
1330 'post_type' => 'product',
1331 'post_status' => array( 'publish', 'private' ),
1332 's' => $keyword,
1333 'posts_per_page' => 10,
1334 );
1335
1336 if ( ! empty( $types ) && ! in_array( 'all', $types, true ) ) {
1337 $product_types = $types;
1338
1339 if ( in_array( 'variation', $types, true ) ) {
1340 $product_types[] = 'variable';
1341 }
1342
1343 // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_tax_query
1344 $query_args['tax_query'] = array(
1345 array(
1346 'taxonomy' => 'product_type',
1347 'field' => 'slug',
1348 'terms' => $product_types,
1349 ),
1350 );
1351 }
1352
1353 $query_args['post__not_in'] = array_map( 'absint', $added_ids );
1354 }
1355
1356 $query = new WP_Query( $query_args );
1357
1358 if ( $query->have_posts() ) {
1359 echo '<ul>';
1360
1361 while ( $query->have_posts() ) {
1362 $query->the_post();
1363 $_product = wc_get_product( get_the_ID() );
1364
1365 if ( ! $_product ) {
1366 continue;
1367 }
1368
1369 if (
1370 ! $_product->is_type( 'variable' )
1371 || in_array( 'variable', $types, true )
1372 || in_array( 'all', $types, true )
1373 ) {
1374 self::product_data_li( $_product, array( 'qty' => 1 ), true, $hierarchy );
1375 }
1376
1377 if (
1378 $_product->is_type( 'variable' )
1379 && (
1380 empty( $types )
1381 || in_array( 'all', $types, true )
1382 || in_array( 'variation', $types, true )
1383 )
1384 ) {
1385 // show all children
1386 $children = $_product->get_children();
1387
1388 if ( is_array( $children ) && count( $children ) > 0 ) {
1389 foreach ( $children as $child ) {
1390 $child_product = wc_get_product( $child );
1391 /**
1392 * @var WC_Product_Variation $child_product
1393 */
1394 if ( ! $this->are_variation_attributes_set( $child_product ) ) {
1395 // Don't display variations that don't have all attributes set.
1396 continue;
1397 }
1398 self::product_data_li( $child_product, true, $hierarchy );
1399 }
1400 }
1401 }
1402 }
1403
1404 echo '</ul>';
1405 wp_reset_postdata();
1406 } else {
1407 // translators: %s is the search keyword
1408 echo wp_kses( '<ul><span>' . sprintf( esc_html__( 'No results found for "%s"', 'merchant' ), $keyword ) . '</span></ul>', array(
1409 'ul' => array(),
1410 'span' => array(),
1411 ) );
1412 }
1413
1414 exit;
1415 }
1416
1417 /**
1418 * Check if all variation attributes are set.
1419 *
1420 * @param $variation WC_Product_Variation variation product object
1421 *
1422 * @return bool
1423 */
1424 public function are_variation_attributes_set( $variation ) {
1425 // Check if the product is a variation and has attributes
1426 if ( $variation && $variation->is_type( 'variation' ) ) {
1427 // Get the variation attributes
1428 $variation_attributes = $variation->get_variation_attributes();
1429
1430 // Check if all variation attributes are set
1431 foreach ( $variation_attributes as $attribute => $value ) {
1432 if ( empty( $value ) ) {
1433 return false; // At least one attribute is not set
1434 }
1435 }
1436
1437 return true; // All variation attributes are set
1438 }
1439
1440 return false; // Not a valid variation product
1441 }
1442
1443 /**
1444 * Field: Select Size Chart
1445 */
1446 public static function select_size_chart( $settings, $value, $module_id = '' ) {
1447 $options = array(
1448 '' => esc_html__( 'Default', 'merchant' ),
1449 );
1450
1451 $posts = get_posts( array(
1452 'post_type' => 'merchant_size_chart',
1453 'posts_per_page' => - 1,
1454 'post_status' => 'publish',
1455 ) );
1456
1457 if ( ! is_wp_error( $posts ) && ! empty( $posts ) ) {
1458 foreach ( $posts as $_post ) {
1459 $options[ $_post->ID ] = $_post->post_title;
1460 }
1461 }
1462
1463 ?>
1464 <?php
1465 if ( ! empty( $options ) ) : ?>
1466 <select name="merchant[<?php
1467 echo esc_attr( $settings['id'] ); ?>]">
1468 <?php
1469 foreach ( $options as $key => $option ) : ?>
1470 <option value="<?php
1471 echo esc_attr( $key ); ?>" <?php
1472 selected( $value, $key, true ); ?>><?php
1473 echo esc_html( $option ); ?></option>
1474 <?php
1475 endforeach; ?>
1476 </select>
1477 <?php
1478 endif; ?>
1479 <?php
1480 }
1481
1482 /**
1483 * Field: Buttons
1484 */
1485 public static function buttons( $settings, $value, $module_id = '' ) {
1486 ?>
1487 <div class="merchant-buttons">
1488 <?php
1489 if ( ! empty( $settings['options'] ) ) : ?>
1490 <?php
1491 foreach ( $settings['options'] as $key => $option ) : ?>
1492 <label class="merchant-button-<?php
1493 echo esc_attr( $key ); ?>"">
1494 <input type="radio" name="merchant[<?php
1495 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1496 echo esc_attr( $key ); ?>" <?php
1497 checked( $value, $key, true ); ?>/>
1498 <span><?php
1499 echo esc_html( $option ); ?></span>
1500 </label>
1501 <?php
1502 endforeach; ?>
1503 <?php
1504 endif; ?>
1505 </div>
1506 <?php
1507 }
1508
1509 /**
1510 * Field: Buttons Alt
1511 */
1512 public static function buttons_alt( $settings, $value, $module_id = '' ) {
1513 ?>
1514 <div class="merchant-buttons">
1515 <?php
1516 if ( ! empty( $settings['options'] ) ) : ?>
1517 <?php
1518 foreach ( $settings['options'] as $key => $option ) : ?>
1519 <label class="merchant-button-<?php
1520 echo esc_attr( $key ); ?>">
1521 <input type="radio" name="merchant[<?php
1522 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1523 echo esc_attr( $key ); ?>" <?php
1524 checked( $value, $key, true ); ?>/>
1525 <span><?php
1526 echo esc_html( $option ); ?></span>
1527 </label>
1528 <?php
1529 endforeach; ?>
1530 <?php
1531 endif; ?>
1532 </div>
1533 <?php
1534 }
1535
1536 /**
1537 * Field: Buttons Content
1538 */
1539 public static function buttons_content( $settings, $value, $module_id = '' ) {
1540 ?>
1541 <div class="merchant-buttons-content">
1542 <?php
1543 if ( ! empty( $settings['options'] ) ) : ?>
1544 <?php
1545 foreach ( $settings['options'] as $key => $option ) : ?>
1546 <label class="merchant-button-content-<?php echo esc_attr( $key ); ?>">
1547 <input
1548 type="radio"
1549 name="merchant[<?php echo esc_attr( $settings['id'] ); ?>]"
1550 value="<?php echo esc_attr( $key ); ?>"
1551 <?php checked( $value, $key, true ); ?>
1552 />
1553
1554 <span class="merchant-buttons-inner-content">
1555 <?php if ( $option['icon'] ) : ?>
1556 <img src="<?php echo esc_url( $option['icon'] ); ?>" alt="">
1557 <?php endif; ?>
1558 <span>
1559 <span><?php echo esc_html( $option['title'] ?? '' ); ?></span>
1560 <span><?php echo esc_html( $option['desc'] ?? '' ); ?></span>
1561 </span>
1562 </span>
1563 </label>
1564 <?php
1565 endforeach; ?>
1566 <?php
1567 endif; ?>
1568 </div>
1569 <?php
1570 }
1571
1572 /**
1573 * Field: Range
1574 */
1575 public static function range( $settings, $value, $module_id = '' ) {
1576 $settings = wp_parse_args( $settings, array(
1577 'min' => '',
1578 'max' => '',
1579 'step' => '',
1580 'unit' => '',
1581 ) );
1582
1583 ?>
1584 <div class="merchant-range">
1585 <input type="range" class="merchant-range-input" name="" min="<?php
1586 echo esc_attr( $settings['min'] ); ?>" max="<?php
1587 echo esc_attr( $settings['max'] ); ?>"
1588 step="<?php
1589 echo esc_attr( $settings['step'] ); ?>" value="<?php
1590 echo esc_attr( $value ); ?>"/>
1591 <input type="number" class="merchant-range-number-input" name="merchant[<?php
1592 echo esc_attr( $settings['id'] ); ?>]" min="<?php
1593 echo esc_attr( $settings['min'] ); ?>"
1594 max="<?php
1595 echo esc_attr( $settings['max'] ); ?>" step="<?php
1596 echo esc_attr( $settings['step'] ); ?>" value="<?php
1597 echo esc_attr( $value ); ?>"/>
1598 <?php
1599 if ( ! empty( $settings['unit'] ) ) : ?>
1600 <span class="merchant-range-unit"><?php
1601 echo esc_html( $settings['unit'] ); ?></span>
1602 <?php
1603 endif; ?>
1604 </div>
1605 <?php
1606 }
1607
1608 /**
1609 * Field: Color
1610 */
1611 public static function color( $settings, $value, $module_id = '' ) {
1612 $settings = wp_parse_args( $settings, array(
1613 'default' => '#212121',
1614 ) );
1615
1616 ?>
1617 <div class="merchant-color">
1618 <div class="merchant-color-picker" data-default-color="<?php
1619 echo esc_attr( $settings['default'] ); ?>" style="background-color: <?php
1620 echo esc_attr( $value ); ?>;"></div>
1621 <input type="text" class="merchant-color-input" name="merchant[<?php
1622 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1623 echo esc_attr( $value ); ?>"/>
1624 </div>
1625 <?php
1626 }
1627
1628 /**
1629 * Field: Gallery
1630 */
1631 public static function gallery( $settings, $value, $module_id = '' ) {
1632 $settings = wp_parse_args( $settings, array(
1633 'label' => esc_html__( 'Select Images', 'merchant' ),
1634 ) );
1635
1636 $images = ( ! empty( $value ) ) ? explode( ',', $value ) : array();
1637
1638
1639 echo '<div class="merchant-gallery-images">';
1640
1641 if ( ! empty( $images ) ) :
1642
1643 foreach ( $images as $image_id ) :
1644
1645 $image = wp_get_attachment_image_src( $image_id, 'thumbnail' );
1646
1647 if ( ! empty( $image ) && ! empty( $image[0] ) ) :
1648
1649 printf( '<div class="merchant-gallery-image" data-item-id="%s">', esc_attr( $image_id ) );
1650
1651 echo '<i class="merchant-gallery-remove dashicons dashicons-no-alt"></i>';
1652
1653 printf( '<img src="%s" />', esc_url( $image[0] ) );
1654
1655 echo '</div>';
1656
1657 endif;
1658
1659 endforeach;
1660
1661 endif;
1662
1663 echo '</div>';
1664
1665 ?>
1666 <a href="#" class="merchant-gallery-button"><?php
1667 echo esc_html( $settings['label'] ); ?></a>
1668 <input type="hidden" class="merchant-gallery-input" name="merchant[<?php
1669 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1670 echo esc_attr( $value ); ?>"/>
1671 <?php
1672 }
1673
1674 /**
1675 * Field: Upload
1676 */
1677 public static function upload( $settings, $value, $module_id = '' ) {
1678 $settings = wp_parse_args( $settings, array(
1679 'label' => esc_html__( 'Select Image', 'merchant' ),
1680 ) );
1681
1682 echo '<div class="merchant-upload-wrapper">';
1683 if ( ! empty( $value ) ) :
1684 $image = wp_get_attachment_image_src( $value, 'thumbnail' );
1685 if ( ! empty( $image ) && ! empty( $image[0] ) ) :
1686 echo '<div class="merchant-upload-image">';
1687 echo '<i class="merchant-upload-remove dashicons dashicons-no-alt"></i>';
1688 printf( '<img src="%s" />', esc_url( $image[0] ) );
1689 echo '</div>';
1690 endif;
1691 endif;
1692 echo '</div>';
1693
1694 $drag_drop = $settings['drag_drop'] ?? false;
1695 ?>
1696 <div class="merchant-upload-button-wrapper<?php echo esc_attr( $drag_drop ? ' merchant-upload-button-drag-drop' : '' ); ?>">
1697 <?php if ( $drag_drop ) : ?>
1698 <img src="<?php echo esc_url( esc_url( MERCHANT_URI . '/assets/images/upload-icon.svg' ) ); ?>" alt="<?php echo esc_attr__( 'Upload image', 'merchant' ); ?>"/>
1699 <?php endif; ?>
1700 <a href="#" class="merchant-upload-button"><?php echo esc_html( $settings['label'] ?? '' ); ?></a>
1701 </div>
1702 <input type="hidden" class="merchant-upload-input" name="merchant[<?php echo esc_attr( $settings['id'] ); ?>]" value="<?php echo esc_attr( $value ); ?>"/>
1703 <?php
1704 }
1705
1706 /**
1707 * Field: Warning
1708 */
1709 public static function warning( $settings ) {
1710 echo wp_kses_post( $settings['content'] );
1711 }
1712
1713 /**
1714 * Field: Warning
1715 */
1716 public static function info( $settings ) {
1717 echo wp_kses_post( $settings['content'] );
1718 }
1719
1720 /**
1721 * Field: Divider
1722 */
1723 public static function divider() {
1724 }
1725
1726 /**
1727 * Field: Content
1728 */
1729 public static function content( $settings ) {
1730 echo wp_kses_post( $settings['content'] );
1731 }
1732
1733 /**
1734 * Field: Sortable
1735 */
1736 public static function sortable( $settings, $value, $module_id = '' ) {
1737 ?>
1738 <div class="merchant-sortable">
1739 <ul class="merchant-sortable-list ui-sortable">
1740 <?php
1741 foreach ( $value as $option_key ) :
1742 $option_val = $settings['options'][ $option_key ];
1743
1744 if ( in_array( $option_key, $value, true ) ) :
1745 ?>
1746 <li class="merchant-sortable-item" data-value="<?php
1747 echo esc_attr( $option_key ); ?>">
1748 <i class='dashicons dashicons-menu'></i>
1749 <i class="dashicons dashicons-visibility visibility"></i>
1750 <?php
1751 echo esc_html( $option_val ); ?>
1752 </li>
1753 <?php
1754 endif; ?>
1755 <?php
1756 endforeach; ?>
1757
1758 <?php
1759 foreach ( $settings['options'] as $option_key => $option_val ) :
1760 if ( ! in_array( $option_key, $value, true ) ) :
1761 $invisible = ! in_array( $option_key, $value, true ) ? ' invisible' : '';
1762
1763 ?>
1764 <li class="merchant-sortable-item<?php
1765 echo esc_attr( $invisible ); ?>" data-value="<?php
1766 echo esc_attr( $option_key ); ?>">
1767 <i class='dashicons dashicons-menu'></i>
1768 <i class="dashicons dashicons-visibility visibility"></i>
1769 <?php
1770 echo esc_html( $option_val ); ?>
1771 </li>
1772 <?php
1773 endif; ?>
1774 <?php
1775 endforeach; ?>
1776 </ul>
1777
1778 <input class="merchant-sortable-input" type="hidden" name="merchant[<?php
1779 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1780 echo esc_attr( wp_json_encode( $value ) ); ?>"/>
1781 </div>
1782 <?php
1783 }
1784
1785 /**
1786 * Field: Sortable Repeater.
1787 */
1788 public static function sortable_repeater( $settings, $value, $module_id = '' ) {
1789 ?>
1790 <div class="merchant-sortable-repeater-control<?php
1791 echo isset( $settings['sorting'] ) && false === $settings['sorting'] ? ' disable-sorting' : ''; ?>">
1792 <div class="merchant-sortable-repeater sortable regular-field">
1793 <div class="repeater">
1794 <input type="text" value="" class="repeater-input"/><span class="dashicons dashicons-menu"></span><a class="customize-control-sortable-repeater-delete"
1795 href="#"><span
1796 class="dashicons dashicons-no-alt"></span></a>
1797 </div>
1798 </div>
1799 <button class="button customize-control-sortable-repeater-add" type="button"><?php
1800 echo esc_html( $settings['button_label'] ); ?></button>
1801 <input class="merchant-sortable-repeater-input" type="hidden" name="merchant[<?php
1802 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1803 echo esc_attr( wp_json_encode( $value ) ); ?>"/>
1804 </div>
1805 <?php
1806 }
1807
1808 public static function wc_coupons( $settings, $value ) {
1809 $coupons = get_posts( array(
1810 'posts_per_page' => - 1,
1811 'orderby' => 'title',
1812 'order' => 'asc',
1813 'post_type' => 'shop_coupon',
1814 'post_status' => 'publish',
1815 ) );
1816 if ( $coupons ) {
1817 ?>
1818 <div class="merchant-wc-coupon-selector merchant-<?php
1819 echo esc_attr( $settings['id'] ) ?>">
1820 <?php
1821 echo '<select name="merchant[' . esc_attr( $settings['id'] ) . ']">';
1822 echo '<option value="">' . esc_html__( 'Select a coupon', 'merchant' ) . '</option>';
1823
1824 foreach ( $coupons as $coupon ) {
1825 $coupon_code = strtolower( $coupon->post_title );
1826
1827 echo '<option value="' . esc_attr( $coupon_code ) . '"' . selected( esc_attr( $coupon_code ), $value, false ) . '>';
1828 echo esc_html( $coupon_code );
1829 echo '</option>';
1830 }
1831
1832 echo '</select>';
1833 echo '<a href="' . esc_url( admin_url( 'edit.php?post_type=shop_coupon' ) ) . '" target="_blank" style="margin-left: 10px;">' . esc_html__( 'Manage coupons',
1834 'merchant' ) . '</a>';
1835 ?>
1836 </div>
1837 <?php
1838 } else {
1839 echo '<div style="color: red;">';
1840 echo wp_kses_post(
1841 sprintf(
1842 /* Translators: 1. Coupon admin url 2. Link target attribute value */
1843 __( 'No coupons found! <a href="%1$s" target="%2$s">Create a new coupon</a>', 'merchant' ),
1844 admin_url( 'post-new.php?post_type=shop_coupon' ),
1845 '_blank'
1846 )
1847 );
1848 echo '</div>';
1849 echo '<input type="hidden" name="merchant[' . esc_attr( $settings['id'] ) . ']" value="" />';
1850 }
1851 }
1852
1853 /**
1854 * Field: Date Time.
1855 *
1856 * @param $settings array field settings.
1857 * @param $value string field value.
1858 * @param $module_id string module id.
1859 *
1860 * @return void
1861 */
1862 public static function date_time( $settings, $value, $module_id = '' ) {
1863 // All options are documented here: https://air-datepicker.com/docs
1864 $options = array(
1865 'dateFormat' => 'MM-dd-yyyy',
1866 'timepicker' => true,
1867 'timeFormat' => 'hh:mm AA',
1868 'minDate' => 'today',
1869 );
1870 if ( isset( $settings['options'] ) ) {
1871 $settings['options'] = wp_parse_args( $settings['options'], $options );
1872 } else {
1873 $settings['options'] = $options;
1874 }
1875 ?>
1876 <div class="merchant-datetime-field" data-options="<?php echo esc_attr( wp_json_encode( $settings['options'] ) ); ?>">
1877 <input type="text" name="merchant[<?php
1878 echo esc_attr( $settings['id'] ); ?>]" value="<?php
1879 echo esc_attr( $value ); ?>" placeholder="<?php
1880 echo isset( $settings['placeholder'] ) ? esc_attr( $settings['placeholder'] ) : ''; ?>"/>
1881 </div>
1882 <?php
1883 }
1884
1885 /**
1886 * Field: Flexible Content.
1887 *
1888 * @param array $settings
1889 * @param mixed $value
1890 *
1891 * @return void
1892 */
1893 public static function flexible_content( $settings, $value, $module_id = '' ) {
1894 $values = ( is_array( $value ) && ! empty( $value ) ) ? $value : array();
1895 $empty = empty( $values ) ? 'empty' : '';
1896
1897 $settings = wp_parse_args( $settings, array(
1898 'sorting' => false,
1899 'style' => 'default',
1900 'accordion' => false,
1901 ) );
1902
1903 $classes = array(
1904 'merchant-flexible-content-control',
1905 "{$settings['style']}-style",
1906 );
1907
1908 if ( $settings['sorting'] === false ) {
1909 $classes[] = 'disable-sorting';
1910 }
1911
1912 $has_accordion = (bool) ( $settings['accordion'] ?? false );
1913 if ( $has_accordion ) {
1914 $classes[] = 'has-accordion';
1915 }
1916
1917 $has_duplicate = (bool) ( $settings['duplicate'] ?? false );
1918 if ( $has_duplicate ) {
1919 $classes[] = 'has-duplicate';
1920 }
1921 ?>
1922 <div class="<?php
1923 echo esc_attr( implode( ' ', $classes ) ); ?>"
1924 data-id="<?php
1925 echo esc_attr( $settings['id'] ) ?>">
1926
1927 <div class="layouts" data-id="<?php
1928 echo esc_attr( $settings['id'] ) ?>">
1929
1930 <?php
1931 foreach ( $settings['layouts'] as $layout_type => $layout ) : ?>
1932
1933 <div class="layout" data-type="<?php echo esc_attr( $layout_type ) ?>">
1934 <div class="layout-header">
1935 <div class="layout-count">1</div>
1936 <div class="layout-title"<?php
1937 if ( isset( $layout['title-field'] ) && ! empty( $layout['title-field'] ) ) {
1938 echo ' data-title-field="' . esc_attr( $layout['title-field'] ) . '"';
1939 } ?>>
1940 <?php
1941 echo esc_html( $layout['title'] ) ?>
1942 </div>
1943 <div class="layout-toggle">
1944 <?php if ( $has_accordion ) : ?>
1945 <span class="customize-control-flexible-content-accordion dashicons dashicons-arrow-down"></span>
1946 <?php endif; ?>
1947 </div>
1948 </div>
1949 <div class="layout-body">
1950 <?php
1951 foreach ( $layout['fields'] as $sub_field ) :
1952 $classes = array( 'layout-field' );
1953
1954 if ( isset( $sub_field['classes'] ) ) {
1955 $classes = array_merge( $classes, $sub_field['classes'] );
1956 } ?>
1957 <div class="<?php
1958 echo esc_attr( implode( ' ', $classes ) ); ?>">
1959 <?php
1960 static::replace_field( $sub_field,
1961 '',
1962 array(
1963 "name=\"merchant[{$sub_field['id']}]",
1964 'merchant-module-page-setting-field-upload',
1965 'merchant-module-page-setting-field-select_ajax',
1966 ),
1967 array(
1968 "data-name=\"merchant[{$settings['id']}][0][{$sub_field['id']}]",
1969 'merchant-module-page-setting-field-upload template',
1970 'merchant-module-page-setting-field-select_ajax template',
1971 ),
1972 $module_id ); ?>
1973 </div>
1974 <?php
1975 endforeach; ?>
1976 <input type="hidden" data-name="merchant[<?php
1977 echo esc_attr( $settings['id'] ) ?>][0][layout]" value="<?php
1978 echo esc_attr( $layout_type ) ?>">
1979 </div>
1980
1981 <div class="layout-actions">
1982 <span class="customize-control-flexible-content-move dashicons dashicons-menu"></span>
1983 <a class="customize-control-flexible-content-delete" href="#">
1984 <span class="dashicons dashicons-no-alt"></span>
1985 </a>
1986 <?php if ( $has_duplicate ) : ?>
1987 <a
1988 href="#"
1989 class="customize-control-flexible-content-duplicate"
1990 data-id="<?php echo esc_attr( $settings['id'] ); ?>"
1991 data-layout="<?php echo esc_attr( $layout_type ); ?>"
1992 title="<?php echo esc_attr__( 'Duplicate', 'merchant' ); ?>">
1993 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35" width="16" height="16" fill="#50575e">
1994 <path d="M20.717,34.748H3.616A3.37,3.37,0,0,1,.25,31.381v-17.1a3.369,3.369,0,0,1,3.366-3.365h17.1a3.368,3.368,0,0,1,3.365,3.365v17.1A3.369,3.369,0,0,1,20.717,34.748ZM3.616,13.416a.866.866,0,0,0-.866.865v17.1a.867.867,0,0,0,.866.867h17.1a.867.867,0,0,0,.865-.867v-17.1a.865.865,0,0,0-.865-.865Z"/>
1995 <path d="M31.384,24.079H22.837a1.25,1.25,0,1,1,0-2.5h8.547a.867.867,0,0,0,.866-.866V3.618a.866.866,0,0,0-.866-.865h-17.1a.866.866,0,0,0-.866.865v8.548a1.25,1.25,0,0,1-2.5,0V3.618A3.369,3.369,0,0,1,14.279.253H31.384A3.369,3.369,0,0,1,34.75,3.618v17.1A3.37,3.37,0,0,1,31.384,24.079Z"/>
1996 </svg>
1997 </a>
1998 <?php endif; ?>
1999 </div>
2000 </div>
2001
2002 <?php
2003 endforeach; ?>
2004
2005 </div>
2006
2007 <div class="merchant-flexible-content <?php
2008 echo esc_attr( $empty ); ?> sortable">
2009
2010 <?php
2011 foreach ( $values as $option_key => $option ) : ?>
2012 <div class="layout" data-type="<?php echo esc_attr( $option['layout'] ) ?>">
2013 <div class="layout-header">
2014 <div class="layout-count"><?php
2015 echo absint( $option_key + 1 ) ?></div>
2016 <div class="layout-title"<?php
2017 if ( isset( $layout['title-field'] ) && ! empty( $layout['title-field'] ) ) {
2018 echo ' data-title-field="' . esc_attr( $layout['title-field'] ) . '"';
2019 } ?>>
2020 <?php
2021 echo isset( $settings['layouts'][ $option['layout'] ]['title'] ) ? esc_html( $settings['layouts'][ $option['layout'] ]['title'] ) : '' ?>
2022 </div>
2023 <div class="layout-toggle">
2024 <?php if ( $has_accordion ) : ?>
2025 <span class="customize-control-flexible-content-accordion dashicons dashicons-arrow-down"></span>
2026 <?php endif; ?>
2027 </div>
2028 </div>
2029 <div class="layout-body">
2030 <?php
2031 foreach ( $settings['layouts'][ $option['layout'] ]['fields'] as $sub_field ) :
2032 $classes = array( 'layout-field' );
2033 if ( isset( $sub_field['classes'] ) ) {
2034 $classes = array_merge( $classes, $sub_field['classes'] );
2035 } ?>
2036 <div class="<?php
2037 echo esc_attr( implode( ' ', $classes ) ) ?>">
2038 <?php
2039 $value = null;
2040 if ( isset( $option[ $sub_field['id'] ] ) ) {
2041 $value = $option[ $sub_field['id'] ];
2042 } elseif ( isset( $sub_field['default'] ) ) {
2043 $value = $sub_field['default'];
2044 }
2045 static::replace_field( $sub_field,
2046 $value,
2047 "name=\"merchant[{$sub_field['id']}]",
2048 "name=\"merchant[{$settings['id']}][{$option_key}][{$sub_field['id']}]",
2049 $module_id ); ?>
2050 </div>
2051 <?php
2052 endforeach; ?>
2053 <input type="hidden" name="merchant[<?php
2054 echo esc_attr( $settings['id'] ) ?>][<?php
2055 echo absint( $option_key ) ?>][layout]"
2056 value="<?php
2057 echo esc_attr( $option['layout'] ) ?>">
2058 </div>
2059
2060 <div class="layout-actions">
2061 <span class="customize-control-flexible-content-move dashicons dashicons-menu"></span>
2062 <a class="customize-control-flexible-content-delete" href="#">
2063 <span class="dashicons dashicons-no-alt"></span>
2064 </a>
2065 <?php if ( $has_duplicate ) : ?>
2066 <a
2067 href="#"
2068 class="customize-control-flexible-content-duplicate"
2069 data-id="<?php echo esc_attr( $settings['id'] ); ?>"
2070 data-layout="<?php echo esc_attr( $layout_type ); ?>"
2071 title="<?php echo esc_attr__( 'Duplicate', 'merchant' ); ?>">
2072 <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 35 35" width="16" height="16" fill="#50575e">
2073 <path d="M20.717,34.748H3.616A3.37,3.37,0,0,1,.25,31.381v-17.1a3.369,3.369,0,0,1,3.366-3.365h17.1a3.368,3.368,0,0,1,3.365,3.365v17.1A3.369,3.369,0,0,1,20.717,34.748ZM3.616,13.416a.866.866,0,0,0-.866.865v17.1a.867.867,0,0,0,.866.867h17.1a.867.867,0,0,0,.865-.867v-17.1a.865.865,0,0,0-.865-.865Z"/>
2074 <path d="M31.384,24.079H22.837a1.25,1.25,0,1,1,0-2.5h8.547a.867.867,0,0,0,.866-.866V3.618a.866.866,0,0,0-.866-.865h-17.1a.866.866,0,0,0-.866.865v8.548a1.25,1.25,0,0,1-2.5,0V3.618A3.369,3.369,0,0,1,14.279.253H31.384A3.369,3.369,0,0,1,34.75,3.618v17.1A3.37,3.37,0,0,1,31.384,24.079Z"/>
2075 </svg>
2076 </a>
2077 <?php endif; ?>
2078 </div>
2079 </div>
2080
2081 <?php
2082 endforeach; ?>
2083
2084 </div>
2085
2086 <div class="customize-control-flexible-content-add-wrapper">
2087 <div class="customize-control-flexible-content-add-list">
2088 <?php
2089 foreach ( $settings['layouts'] as $layout_type => $layout ) : ?>
2090 <a href="#"
2091 class="customize-control-flexible-content-add"
2092 data-id="<?php
2093 echo esc_attr( $settings['id'] ) ?>"
2094 data-layout="<?php
2095 echo esc_attr( $layout_type ) ?>">
2096 <?php
2097 echo esc_attr( $layout['title'] ) ?>
2098 </a>
2099 <?php
2100 endforeach; ?>
2101 </div>
2102 <button class="button customize-control-flexible-content-add-button" type="button"><?php
2103 echo esc_html( $settings['button_label'] ); ?></button>
2104 </div>
2105 </div>
2106 <?php
2107 }
2108
2109 /**
2110 * Field: Create Page.
2111 */
2112 public static function create_page( $settings, $value, $module_id = '' ) {
2113 $page_id = get_option( $settings['option_name'] );
2114
2115 echo '<div class="merchant-create-page-control">';
2116
2117 if ( $page_id && post_exists( get_the_title( $page_id ) ) && 'publish' === get_post_status( $page_id ) ) {
2118 echo wp_kses_post(
2119 sprintf( /* translators: 1: link to edit page */
2120 __( '<p class="merchant-module-page-setting-field-desc mrc-mt-0">Your page is created!</p><p class="merchant-module-page-setting-field-desc">Click <a href="%1$s" target="_blank">here</a> if you want to edit the page.</p><p class="merchant-module-page-setting-field-desc mrc-mb-0">To display the page in your theme header area, assign the page to the primary menu by clicking <a href="%2$s" target="_blank">here</a></p>',
2121 'merchant' ),
2122 get_admin_url() . 'post.php?post=' . $page_id . '&action=edit',
2123 get_admin_url() . 'nav-menus.php'
2124 )
2125 );
2126 } else {
2127 echo '<div class="merchant-create-page-control-create-message">';
2128 echo wp_kses_post(
2129 '<p class="merchant-module-page-setting-field-desc mrc-mt-0">'.
2130 sprintf( /* translators: 1: page name */
2131 __( 'It looks like you haven\'t created a <strong>%1$s</strong> page yet. Click the below button to create the page.',
2132 'merchant' ),
2133 $settings['page_title']
2134 ). '</p>'
2135 );
2136 echo '</div>';
2137 echo '<div class="merchant-create-page-control-success-message" style="display: none;">';
2138 echo wp_kses_post(
2139 sprintf( /* translators: 1: link to edit page */
2140 __( '<p class="merchant-module-page-setting-field-desc">Page created with success!</p><p class="merchant-module-page-setting-field-desc">Click <a href="%1$s" target="_blank">here</a> if you want to edit the page.</p><p class="merchant-module-page-setting-field-desc mrc-mb-0">To display the page in your theme header area, assign the page to the primary menu by clicking <a href="%2$s" target="_blank">here</a></p>',
2141 'merchant' ),
2142 get_admin_url() . 'post.php?post=&action=edit',
2143 get_admin_url() . 'nav-menus.php'
2144 )
2145 );
2146 echo '</div>';
2147 echo wp_kses_post(
2148 sprintf( /* translators: 1: page title, 2: page meta key, 3: page meta value, 4: option name, 5: nonce, 6: loading text, 7: success text */
2149 __( '<a href="#" class="merchant-create-page-control-button button-tertiary" data-page-title="%2$s" data-page-meta-key="%3$s" data-page-meta-value="%4$s" data-option-name="%5$s" data-nonce="%6$s" data-creating-text="%7$s" data-created-text="%8$s">%1$s</a>',
2150 'merchant' ),
2151 __( 'Create Page', 'merchant' ),
2152 $settings['page_title'],
2153 $settings['page_meta_key'],
2154 $settings['page_meta_value'],
2155 $settings['option_name'],
2156 wp_create_nonce( 'customize-create-page-control-nonce' ),
2157 __( 'Creating...', 'merchant' ),
2158 __( 'Created!', 'merchant' )
2159 )
2160 );
2161 }
2162
2163 echo '</div>';
2164 }
2165
2166 public static function dimensions( $settings, $value, $module_id = '' ) {
2167 $settings = wp_parse_args( $settings, array(
2168 'units' => array(
2169 'px' => 'px',
2170 'rem' => 'rem',
2171 'em' => 'em',
2172 'vw' => 'vw',
2173 'vh' => 'vh',
2174 '%' => '%',
2175 ),
2176 'dimensions' => array(
2177 'top',
2178 'right',
2179 'bottom',
2180 'left',
2181 ),
2182 ) );
2183 $default_value = array(
2184 'unit' => reset( $settings['units'] ),
2185 );
2186 foreach ( $settings['dimensions'] as $dimension ) {
2187 $default_value[ $dimension ] = 0;
2188 }
2189 $value = wp_parse_args( $value, $default_value );
2190 ?>
2191 <div class="merchant-module-page-settings-unit">
2192 <select name="merchant[<?php
2193 echo esc_attr( $settings['id'] ); ?>][unit]">
2194 <?php
2195 foreach ( $settings['units'] as $key => $option ) : ?>
2196 <option value="<?php
2197 echo esc_attr( $key ); ?>" <?php
2198 selected( $value['unit'], $key, true ); ?>><?php
2199 echo esc_html( $option ); ?></option>
2200 <?php
2201 endforeach; ?>
2202 </select>
2203 </div>
2204 <div class="merchant-module-page-settings-dimensions">
2205 <?php
2206 foreach ( $settings['dimensions'] as $dimension ) : ?>
2207 <div>
2208 <input id="merchant-<?php
2209 echo esc_attr( $settings['id'] ); ?>-<?php
2210 echo esc_attr( $dimension ) ?>"
2211 type="number"
2212 name="merchant[<?php
2213 echo esc_attr( $settings['id'] ); ?>][<?php
2214 echo esc_attr( $dimension ) ?>]"
2215 value="<?php
2216 echo esc_attr( $value[ $dimension ] ); ?>"/>
2217 <label for="merchant-<?php
2218 echo esc_attr( $settings['id'] ); ?>-<?php
2219 echo esc_attr( $dimension ) ?>">
2220 <?php
2221 echo esc_html( ucfirst( $dimension ) ); ?>
2222 </label>
2223 </div>
2224 <?php
2225 endforeach; ?>
2226 </div>
2227 <?php
2228 }
2229
2230 public static function responsive_dimensions( $settings, $value, $module_id = '' ) {
2231 $settings = wp_parse_args( $settings, array(
2232 'units' => array(
2233 'px' => 'px',
2234 'rem' => 'rem',
2235 'em' => 'em',
2236 'vw' => 'vw',
2237 'vh' => 'vh',
2238 '%' => '%',
2239 ),
2240 'dimensions' => array(
2241 'top',
2242 'right',
2243 'bottom',
2244 'left',
2245 ),
2246 'devices' => array(
2247 'desktop' => 'dashicons-desktop',
2248 'tablet' => 'dashicons-tablet',
2249 'mobile' => 'dashicons-smartphone',
2250 ),
2251 ) );
2252 $default_values = array();
2253 foreach ( $settings['devices'] as $device => $icon ) {
2254 $default_values[ $device ]['unit'] = reset( $settings['units'] );
2255
2256 foreach ( $settings['dimensions'] as $dimension ) {
2257 $default_values[ $device ][ $dimension ] = 0;
2258 }
2259 }
2260 $value = wp_parse_args( $value, $default_values );
2261 ?>
2262 <div class="merchant-module-page-settings-responsive">
2263 <ul class="merchant-module-page-settings-devices">
2264 <?php
2265 foreach ( $settings['devices'] as $device => $icon ) : ?>
2266 <li class="<?php
2267 echo esc_attr( $device ); ?>">
2268 <button type="button" class="preview-<?php
2269 echo esc_attr( $device ); ?> <?php
2270 echo $device === key( $settings['devices'] ) ? 'active' : '' ?>"
2271 data-device="<?php
2272 echo esc_attr( $device ); ?>">
2273 <i class="dashicons <?php
2274 echo esc_attr( $icon ); ?>"></i>
2275 </button>
2276 </li>
2277 <?php
2278 endforeach; ?>
2279 </ul>
2280 <?php
2281 foreach ( $settings['devices'] as $device => $icon ) : ?>
2282 <div class="merchant-module-page-settings-device-container <?php
2283 echo $device === key( $settings['devices'] ) ? 'active' : '' ?>" data-device="<?php
2284 echo esc_attr( $device ); ?>">
2285 <div class="merchant-module-page-settings-unit">
2286 <select name="merchant[<?php
2287 echo esc_attr( $settings['id'] ); ?>][<?php
2288 echo esc_attr( $device ) ?>][unit]">
2289 <?php
2290 foreach ( $settings['units'] as $key => $option ) : ?>
2291 <option value="<?php
2292 echo esc_attr( $key ); ?>" <?php
2293 selected( $value[ esc_attr( $device ) ]['unit'], $key, true ); ?>><?php
2294 echo esc_html( $option ); ?></option>
2295 <?php
2296 endforeach; ?>
2297 </select>
2298 </div>
2299 <div class="merchant-module-page-settings-dimensions">
2300 <?php
2301 foreach ( $settings['dimensions'] as $dimension ) : ?>
2302 <div>
2303 <input id="merchant-<?php
2304 echo esc_attr( $settings['id'] ); ?>-<?php
2305 echo esc_attr( $device ) ?>-<?php
2306 echo esc_attr( $dimension ) ?>"
2307 type="number"
2308 name="merchant[<?php
2309 echo esc_attr( $settings['id'] ); ?>][<?php
2310 echo esc_attr( $device ) ?>][<?php
2311 echo esc_attr( $dimension ) ?>]"
2312 value="<?php
2313 echo esc_attr( $value[ $device ][ $dimension ] ); ?>"/>
2314 <label for="merchant-<?php
2315 echo esc_attr( $settings['id'] ); ?>-<?php
2316 echo esc_attr( $device ) ?>-<?php
2317 echo esc_attr( $dimension ) ?>">
2318 <?php
2319 echo esc_html( ucfirst( $dimension ) ); ?>
2320 </label>
2321 </div>
2322 <?php
2323 endforeach; ?>
2324 </div>
2325 </div>
2326 <?php
2327 endforeach; ?>
2328 </div>
2329
2330 <?php
2331 }
2332
2333 /**
2334 * Field: Custom callback.
2335 */
2336 public static function custom_callback( $settings, $value, $module_id = '' ) {
2337 if ( ! empty( $settings['class_name'] ) && ! empty( $settings['callback_name'] ) ) {
2338 return call_user_func( array( $settings['class_name'], $settings['callback_name'] ), $settings, $value );
2339 }
2340
2341 if ( ! empty( $settings['callback_name'] ) ) {
2342 return call_user_func( $settings['callback_name'], $settings, $value );
2343 }
2344
2345 return false;
2346 }
2347
2348 /**
2349 * Get category choices for select2
2350 *
2351 * @return array
2352 */
2353 public static function get_category_select2_choices() {
2354 $choices = array();
2355 $cats = merchant_get_product_categories();
2356
2357 if ( is_array( $cats ) && ! empty( $cats ) ) {
2358 foreach ( $cats as $slug => $name ) {
2359 $choices[] = array(
2360 'id' => esc_attr( $slug ),
2361 'text' => esc_html( $name ),
2362 );
2363 }
2364 }
2365
2366 return $choices;
2367 }
2368
2369 /**
2370 * Get Tag choices for select2
2371 *
2372 * @return array
2373 */
2374 public static function get_tag_select2_choices() {
2375 $choices = array();
2376 $tags = merchant_get_product_tags();
2377
2378 if ( is_array( $tags ) && ! empty( $tags ) ) {
2379 foreach ( $tags as $slug => $name ) {
2380 $choices[] = array(
2381 'id' => esc_attr( $slug ),
2382 'text' => esc_html( $name ),
2383 );
2384 }
2385 }
2386
2387 return $choices;
2388 }
2389
2390 /**
2391 * Get User Roles choices for select2
2392 *
2393 * @return array
2394 */
2395 public static function get_user_roles_select2_choices() {
2396 $choices = array();
2397 $user_roles = get_editable_roles();
2398
2399 if ( ! empty( $user_roles ) ) {
2400 foreach ( $user_roles as $role_id => $role_data ) {
2401 $choices[] = array(
2402 'id' => $role_id,
2403 'text' => $role_data['name'],
2404 );
2405 }
2406 }
2407
2408 return $choices;
2409 }
2410
2411 /**
2412 * Get Customers choices for select2.
2413 *
2414 * @return array
2415 */
2416 public static function get_customers_select2_choices() {
2417 $cache_key = 'customers_select2_choices';
2418 $choices = get_transient( $cache_key );
2419
2420 if ( ! empty( $choices ) && is_array( $choices ) ) {
2421 return $choices;
2422 }
2423
2424 // Get users with the 'customer' role
2425 $customer_users = get_users(
2426 array(
2427 'role' => 'customer',
2428 'fields' => array( 'ID', 'display_name' ),
2429 )
2430 );
2431
2432 $choices = array();
2433 if ( ! empty( $customer_users ) ) {
2434 foreach ( $customer_users as $user ) {
2435 $choices[] = array(
2436 'id' => $user->ID,
2437 'text' => $user->display_name,
2438 );
2439 }
2440 }
2441
2442 // Cache the choices with no expiration. Will be cleared using `clear_customer_choices_cache`
2443 set_transient( $cache_key, $choices );
2444
2445 return $choices;
2446 }
2447
2448 /**
2449 * Clear customers cache when a customer is created/deleted/updated.
2450 *
2451 * @param $user_id
2452 * @param $user
2453 *
2454 * @return void
2455 */
2456 public function clear_customer_choices_cache( $user_id, $user ) {
2457 $user_roles = $user->roles ?? array();
2458 if ( in_array( 'customer', $user_roles, true ) ) {
2459 delete_transient( 'customers_select2_choices' );
2460 }
2461 }
2462 }
2463
2464 Merchant_Admin_Options::instance();
2465 }
2466