PluginProbe
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant / 2.3.2
Product Labels, Quick View, Buy Now, Pre-Orders, Frequently Bought Together & More for WooCommerce – Merchant v2.3.2
2.3.2 2.3.1 2.3.0 2.2.8 2.2.7 trunk 1.10.0 1.10.1 1.10.2 1.10.3 1.10.4 1.10.5 1.11.0 1.11.1 1.11.2 1.6 1.7 1.8 1.8.1 1.8.2 1.8.3 1.9.0 1.9.1 1.9.10 1.9.11 All 60 releases
← All changes | admin/classes/class-merchant-admin-options.php +264 -2276 1.9.112.3.2 View file →
@@ -1,7 +1,15 @@
1 1 <?php
2 2 /**
3 - * Merchant_Admin_Options Class.
3 + * Merchant Admin Options.
4 + *
5 + * Thin orchestrator that manages module settings. Delegates rendering
6 + * to {@see Merchant_Settings_Renderer}, saving to {@see Merchant_Settings_Saver},
7 + * asset enqueueing to {@see Merchant_Admin_Assets}, and Select2 data
8 + * to {@see Merchant_Select2_Choices}.
9 + *
10 + * @package Merchant
11 + * @since 1.0
4 12 */
5 13
6 14 if ( ! defined( 'ABSPATH' ) ) {
7 15 exit; // Exit if accessed directly
@@ -7,17 +15,36 @@
7 15 exit; // Exit if accessed directly
8 16 }
9 17
10 18 if ( ! class_exists( 'Merchant_Admin_Options' ) ) {
19 + /**
20 + * Merchant_Admin_Options
21 + *
22 + * Orchestrates the Merchant admin settings panel. Core responsibilities:
23 + * - CRUD operations for module settings (`get`, `set`, `delete`, `get_all`)
24 + * - Wiring admin hooks (assets, cache, cleanup, Pro activation)
25 + * - Backward-compatible facades that delegate to extracted classes
26 + *
27 + * This class is a singleton; use {@see Merchant_Admin_Options::instance()} to retrieve it.
28 + *
29 + * @since 1.0
30 + */
11 31 class Merchant_Admin_Options {
12 32
13 33 /**
14 34 * The single class instance.
35 + *
36 + * @since 1.0
37 + * @var Merchant_Admin_Options|null
15 38 */
16 39 private static $instance = null;
17 40
18 41 /**
19 - * Instance.
42 + * Get the singleton instance.
43 + *
44 + * @since 1.0
45 + *
46 + * @return Merchant_Admin_Options
20 47 */
21 48 public static function instance() {
22 49 if ( is_null( self::$instance ) ) {
23 50 self::$instance = new self();
@@ -27,220 +54,44 @@
27 54 }
28 55
29 56 /**
30 57 * Constructor.
58 + *
59 + * Registers admin hooks for script enqueueing, cache clearance,
60 + * legacy data cleanup, and Pro plugin activation.
61 + *
62 + * @since 1.0
31 63 */
32 64 public function __construct() {
33 - // Enqueue hooks.
34 - add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
65 + $assets = new Merchant_Admin_Assets();
66 + $choices = new Merchant_Select2_Choices();
35 67
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' ) );
68 + add_action( 'admin_enqueue_scripts', array( $assets, 'enqueue_scripts' ) );
69 + add_action( 'clean_user_cache', array( $choices, 'clear_customer_choices_cache' ), 10, 2 );
40 70
41 - add_action( 'clean_user_cache', array( $this, 'clear_customer_choices_cache' ), 10, 2 );
71 + add_action( 'admin_init', array( $this, 'delete_module_data' ) );
72 + add_action( 'admin_init', array( $this, 'activate_pro_plugin' ) );
42 73 }
43 74
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' );
75 + // ──────────────────────────────────────────────────────
76 + // CRUD — core orchestrator responsibility.
77 + // ──────────────────────────────────────────────────────
54 78
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 79 /**
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.
80 + * Get a single module setting value.
178 81 *
82 + * Retrieves the value of a specific setting for a given module
83 + * from the `merchant` option. Falls back to `$default_val` if
84 + * the setting does not exist.
85 + *
86 + * @since 1.0
87 + *
88 + * @param string $module The module ID (e.g. 'buy-x-get-y').
89 + * @param string $setting The setting key within the module.
90 + * @param mixed $default_val The default value if the setting is not found.
91 + *
92 + * @return mixed The setting value, filtered via `merchant_get_option`.
179 93 */
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 94 public static function get( $module, $setting, $default_val ) {
244 95 $options = get_option( 'merchant', array() );
245 96
246 97 $value = $default_val;
@@ -256,17 +107,25 @@
256 107 * @param mixed $value Option value.
257 108 * @param string $module Module ID.
258 109 * @param string $setting Setting ID.
259 110 * @param mixed $default_val Default value.
260 - *
261 - * @since 1.9.3
111 + *
112 + * @since 1.9.3
262 113 */
263 114 return apply_filters( 'merchant_get_option', $value, $module, $setting, $default_val );
264 115 }
265 116
266 - /**
267 - * Set option.
268 - */
117 + /**
118 + * Set a single module setting value.
119 + *
120 + * @since 1.0
121 + *
122 + * @param string $module The module ID.
123 + * @param string $setting The setting key.
124 + * @param mixed $value The value to store.
125 + *
126 + * @return void
127 + */
269 128 public static function set( $module, $setting, $value ) {
270 129 $options = get_option( 'merchant', array() );
271 130 $options[ $module ][ $setting ] = $value;
272 131 update_option( 'merchant', $options );
@@ -271,19 +130,32 @@
271 130 $options[ $module ][ $setting ] = $value;
272 131 update_option( 'merchant', $options );
273 132 }
274 133
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 - }
134 + /**
135 + * Delete a single module setting.
136 + *
137 + * @since 1.0
138 + *
139 + * @param string $module The module ID.
140 + * @param string $setting The setting key to remove.
141 + *
142 + * @return void
143 + */
144 + public static function delete( $module, $setting ) {
145 + $options = get_option( 'merchant', array() );
146 + unset( $options[ $module ][ $setting ] );
147 + update_option( 'merchant', $options );
148 + }
283 149
284 150 /**
285 - * Get all options.
151 + * Get all settings for a module.
152 + *
153 + * @since 1.0
154 + *
155 + * @param string $module The module ID.
156 + *
157 + * @return array All settings for the module.
286 158 */
287 159 public static function get_all( $module ) {
288 160 $options = get_option( 'merchant', array() );
289 161 $value = array();
@@ -294,2172 +166,288 @@
294 166
295 167 return $value;
296 168 }
297 169
170 + // ──────────────────────────────────────────────────────
171 + // Delegation facades — backward compatibility.
172 + // ──────────────────────────────────────────────────────
173 +
298 174 /**
299 - * Create options.
175 + * Create and render a module settings panel.
176 + *
177 + * @since 1.0
178 + * @see Merchant_Settings_Renderer::create()
179 + *
180 + * @param array $settings Module settings configuration.
181 + *
182 + * @return void
300 183 */
301 184 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
185 + Merchant_Settings_Renderer::create( $settings );
364 186 }
365 187
366 188 /**
367 - * Save options.
189 + * Render a single field.
190 + *
191 + * @since 1.0
192 + * @see Merchant_Settings_Renderer::field()
193 + *
194 + * @param array $settings The field configuration array.
195 + * @param mixed $value The current saved value.
196 + * @param string $module_id The module ID.
197 + *
198 + * @return void
368 199 */
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'] ] );
200 + public static function field( $settings, $value, $module_id = '' ) {
201 + Merchant_Settings_Renderer::field( $settings, $value, $module_id );
433 202 }
434 203
435 204 /**
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
205 + * Render a disabled (pro-gated) field.
668 206 *
669 - * @param array $settings
670 - * @param mixed $value
207 + * @since 1.0
208 + * @see Merchant_Settings_Renderer::disabled_field()
671 209 *
210 + * @param array $settings Field settings.
211 + * @param mixed $value Field value.
212 + * @param string $module_id Module ID.
213 + *
672 214 * @return void
673 215 */
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 - );
216 + public static function disabled_field( $settings, $value, $module_id = '' ) {
217 + Merchant_Settings_Renderer::disabled_field( $settings, $value, $module_id );
690 218 }
691 219
692 220 /**
693 - * Modified field.
221 + * Save module options from a form submission.
694 222 *
695 - * @param $settings
696 - * @param $value
697 - * @param $search
698 - * @param $replace
223 + * @since 1.0
224 + * @see Merchant_Settings_Saver::save_options()
699 225 *
226 + * @param array $settings Module settings configuration.
227 + *
700 228 * @return void
701 229 */
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' ) ) );
230 + public static function save_options( $settings ) {
231 + Merchant_Settings_Saver::save_options( $settings );
708 232 }
709 233
710 234 /**
711 - * Field: Text
235 + * Sanitize options.
236 + *
237 + * @since 1.9.3
238 + * @see Merchant_Settings_Saver::sanitize()
239 + *
240 + * @param array $field The field configuration.
241 + * @param mixed $value The raw submitted value.
242 + *
243 + * @return mixed The sanitized value.
712 244 */
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
245 + public static function sanitize( $field, $value ) {
246 + return Merchant_Settings_Saver::sanitize( $field, $value );
719 247 }
720 248
721 249 /**
722 - * Field: Text (readonly)
250 + * Get product category choices for Select2.
251 + *
252 + * @since 1.9.3
253 + * @see Merchant_Select2_Choices::get_category_select2_choices()
254 + *
255 + * @return array Formatted category choices.
723 256 */
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
257 + public static function get_category_select2_choices() {
258 + return Merchant_Select2_Choices::get_category_select2_choices();
729 259 }
730 260
731 261 /**
732 - * Field: Number
262 + * Get product tag choices for Select2.
263 + *
264 + * @since 1.9.3
265 + * @see Merchant_Select2_Choices::get_tag_select2_choices()
266 + *
267 + * @return array Formatted tag choices.
733 268 */
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
269 + public static function get_tag_select2_choices() {
270 + return Merchant_Select2_Choices::get_tag_select2_choices();
744 271 }
745 272
746 273 /**
747 - * Field: Textarea
274 + * Get product brand choices for Select2.
275 + *
276 + * @since 1.9.3
277 + * @see Merchant_Select2_Choices::get_brand_select2_choices()
278 + *
279 + * @return array Formatted brand choices.
748 280 */
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
281 + public static function get_brand_select2_choices() {
282 + return Merchant_Select2_Choices::get_brand_select2_choices();
756 283 }
757 284
758 285 /**
759 - * Field: Textarea
286 + * Get user role choices for Select2.
287 + *
288 + * @since 1.9.3
289 + * @see Merchant_Select2_Choices::get_user_roles_select2_choices()
290 + *
291 + * @return array Formatted role choices.
760 292 */
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
293 + public static function get_user_roles_select2_choices() {
294 + return Merchant_Select2_Choices::get_user_roles_select2_choices();
768 295 }
769 296
770 297 /**
771 - * Field: Textarea Code Snippet.
298 + * Get weekday choices, Monday first, keyed by day name.
299 + *
300 + * @since 2.3.2
301 + * @see Merchant_Select2_Choices::get_weekday_choices()
302 + *
303 + * @return array Day name => translated label.
772 304 */
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
305 + public static function get_weekday_choices() {
306 + return Merchant_Select2_Choices::get_weekday_choices();
780 307 }
781 308
782 309 /**
783 - * Field: Checkbox
310 + * Get shipping zone choices for Select2.
311 + *
312 + * @since 2.3.2
313 + * @see Merchant_Select2_Choices::get_shipping_zone_select2_choices()
314 + *
315 + * @return array Formatted zone choices.
784 316 */
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
317 + public static function get_shipping_zone_select2_choices() {
318 + return Merchant_Select2_Choices::get_shipping_zone_select2_choices();
801 319 }
802 320
803 321 /**
804 - * Field: Checkbox multiple
322 + * Get registered shipping method choices for Select2.
323 + *
324 + * @since 2.3.2
325 + * @see Merchant_Select2_Choices::get_shipping_method_select2_choices()
326 + *
327 + * @return array Formatted method choices.
805 328 */
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;
329 + public static function get_shipping_method_select2_choices() {
330 + return Merchant_Select2_Choices::get_shipping_method_select2_choices();
822 331 }
823 332
824 333 /**
825 - * Field: Switcher
334 + * Get enabled payment gateway choices for Select2.
335 + *
336 + * @since 2.3.2
337 + * @see Merchant_Select2_Choices::get_payment_gateway_select2_choices()
338 + *
339 + * @return array Formatted gateway choices.
826 340 */
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
341 + public static function get_payment_gateway_select2_choices() {
342 + return Merchant_Select2_Choices::get_payment_gateway_select2_choices();
848 343 }
849 344
850 345 /**
851 - * Field: Radio
346 + * Get customer user choices for Select2.
347 + *
348 + * @since 1.9.3
349 + * @see Merchant_Select2_Choices::get_customers_select2_choices()
350 + *
351 + * @return array Formatted customer choices.
852 352 */
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
353 + public static function get_customers_select2_choices() {
354 + return Merchant_Select2_Choices::get_customers_select2_choices();
872 355 }
873 356
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 - }
357 + // ──────────────────────────────────────────────────────
358 + // Admin hooks — small one-off actions.
359 + // ──────────────────────────────────────────────────────
909 360
910 361 /**
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
362 + * Delete stale module data from the database.
1065 363 *
1066 - * @param $settings
1067 - * @param $value
364 + * Cleans up data for removed modules (e.g., the deprecated
365 + * `code-snippets` module). Hooked to `admin_init`.
1068 366 *
367 + * @since 1.9.3
368 + *
1069 369 * @return void
1070 370 */
1071 - public static function select_ajax( $settings, $value, $module_id = '' ) {
1072 - $settings = wp_parse_args( $settings, array(
1073 - 'source' => 'post',
1074 - ) );
371 + public function delete_module_data() {
372 + $options = get_option( 'merchant', array() );
1075 373
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';
374 + if ( isset( $options['code-snippets'] ) ) {
375 + unset( $options['code-snippets'] );
376 + update_option( 'merchant', $options );
1082 377 }
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 378 }
1136 379
1137 380 /**
1138 - * Field: Info Block
381 + * Activate the Merchant Pro plugin.
1139 382 *
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
383 + * Handles the `merchant_activate_pro` admin action: verifies
384 + * nonce and capabilities, activates the Pro plugin, and
385 + * redirects back to the originating Merchant page.
1157 386 *
1158 - * @param $settings
1159 - * @param $value
387 + * @since 1.0
1160 388 *
1161 389 * @return void
1162 390 */
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 -
391 + public function activate_pro_plugin() {
392 + if ( ! isset( $_GET['action'] ) || 'merchant_activate_pro' !== $_GET['action'] ) {
1167 393 return;
1168 394 }
1169 395
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 396 if (
1314 - in_array( 'all', $types, true )
1315 - || ( in_array( 'variation', $types, true ) && in_array( 'variable', $types, true ) )
397 + ! isset( $_GET['nonce'] )
398 + || ! wp_verify_nonce(
399 + sanitize_text_field( wp_unslash( $_GET['nonce'] ) ),
400 + 'merchant_activate_pro'
401 + )
1316 402 ) {
1317 - $hierarchy = true;
403 + return;
1318 404 }
1319 405
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 );
406 + if ( ! current_user_can( 'activate_plugins' ) ) {
407 + return;
1354 408 }
1355 409
1356 - $query = new WP_Query( $query_args );
410 + $result = activate_plugin( 'merchant-pro/merchant-pro.php' );
1357 411
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 - ) );
412 + if ( is_wp_error( $result ) ) {
413 + wp_die( esc_html( $result->get_error_message() ) );
1412 414 }
1413 415
416 + wp_safe_redirect( $this->get_safe_merchant_redirect_url() );
1414 417 exit;
1415 418 }
1416 419
1417 420 /**
1418 - * Check if all variation attributes are set.
421 + * Get a safe redirect URL pointing to a Merchant admin page.
1419 422 *
1420 - * @param $variation WC_Product_Variation variation product object
423 + * Validates the HTTP referer is a Merchant page. Falls back
424 + * to the main Merchant dashboard if the referer is invalid
425 + * or points to a non-Merchant page.
1421 426 *
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.
427 + * @since 1.9.3
1859 428 *
1860 - * @return void
429 + * @return string Safe redirect URL.
1861 430 */
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 - }
431 + private function get_safe_merchant_redirect_url() {
432 + $fallback_url = admin_url( 'admin.php?page=merchant' );
433 + $referer = wp_get_referer();
434 + $redirect_to = wp_validate_redirect( $referer, $fallback_url );
1884 435
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';
436 + if ( $redirect_to === $fallback_url ) {
437 + return $fallback_url;
1910 438 }
1911 439
1912 - $has_accordion = (bool) ( $settings['accordion'] ?? false );
1913 - if ( $has_accordion ) {
1914 - $classes[] = 'has-accordion';
1915 - }
440 + $parsed_url = wp_parse_url( $redirect_to );
441 + $query_params = array();
442 + parse_str( $parsed_url['query'] ?? '', $query_params );
1916 443
1917 - $has_duplicate = (bool) ( $settings['duplicate'] ?? false );
1918 - if ( $has_duplicate ) {
1919 - $classes[] = 'has-duplicate';
444 + if ( empty( $query_params['page'] ) || strpos( $query_params['page'], 'merchant' ) !== 0 ) {
445 + return $fallback_url;
1920 446 }
1921 - ?>
1922 - <div class="<?php
1923 - echo esc_attr( implode( ' ', $classes ) ); ?>"
1924 - data-id="<?php
1925 - echo esc_attr( $settings['id'] ) ?>">
1926 447
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
448 + return $redirect_to;
2107 449 }
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 450 }
2463 451
2464 452 Merchant_Admin_Options::instance();
2465 453 }