PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / trunk
WPSSO Core – Complete Schema Markup and Meta Tags vtrunk
22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
wpsso / lib / com / form.php

form.php in WPSSO Core – Complete Schema Markup and Meta Tags trunk, at lib/com/form.php

3,259 lines 105.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /*
3 * License: GPLv3
4 * License URI: https://www.gnu.org/licenses/gpl.txt
5 * Copyright 2012-2026 Jean-Sebastien Morisset (https://surniaulula.com/)
6 */
7
8 if ( ! defined( 'ABSPATH' ) ) {
9
10 die( 'These aren\'t the droids you\'re looking for.' );
11 }
12
13 if ( ! class_exists( 'SucomUtil' ) ) { // Just in case.
14
15 require_once './util.php';
16 }
17
18 if ( ! class_exists( 'SucomUtilWP' ) ) { // Just in case.
19
20 require_once './util-wp.php';
21 }
22
23 if ( ! class_exists( 'SucomForm' ) ) {
24
25 class SucomForm {
26
27 private $p; // Plugin class object.
28
29 private $plugin_id = null; // Lowercase acronyn for main plugin.
30 private $ext_id = null; // Lowercase acronyn for main plugin or add-on.
31 private $opts_name = null;
32 private $admin_l10n = 'sucomAdminPageL10n';
33 private $text_domain = false; // Text domain for plugin or add-on.
34 private $def_text_domain = false; // Default text domain (fallback).
35 private $show_hide_js_added = false;
36 private $json_array_added = array();
37
38 public $options = array();
39 public $defaults = array();
40
41 public function __construct( &$plugin, $opts_name, &$opts, &$defs, $ext_id = '' ) {
42
43 $this->p =& $plugin;
44
45 if ( $this->p->debug->enabled ) {
46
47 $this->p->debug->mark();
48
49 $this->p->debug->log( 'form options name is ' . $opts_name );
50 }
51
52 $this->plugin_id = $this->p->id;
53 $this->opts_name =& $opts_name;
54 $this->options =& $opts;
55 $this->defaults =& $defs;
56 $this->ext_id = empty( $ext_id ) ? $this->plugin_id : $ext_id; // Lowercase acronyn for plugin or add-on.
57
58 $this->set_admin_l10n();
59 $this->set_text_domain( $this->ext_id );
60 $this->set_default_text_domain( $this->plugin_id );
61 }
62
63 public function get_options_name() {
64
65 return $this->opts_name;
66 }
67
68 public function get_options( $opt_key = false, $def_val = null ) {
69
70 if ( false !== $opt_key ) {
71
72 if ( $this->in_options( $opt_key ) ) {
73
74 return $this->options[ $opt_key ];
75
76 }
77
78 return $def_val;
79 }
80
81 return $this->options;
82 }
83
84 public function get_defaults( $opt_key = false, $def_val = null ) {
85
86 if ( false !== $opt_key ) {
87
88 if ( $this->in_defaults( $opt_key ) ) {
89
90 return $this->defaults[ $opt_key ];
91
92 }
93
94 return $def_val;
95 }
96
97 return $this->defaults;
98 }
99
100 public function in_options( $opt_key ) {
101
102 if ( isset( $this->options[ $opt_key ] ) ) {
103
104 return true;
105
106 } elseif ( 0 === strpos( $opt_key, '/' ) ) { // Regular expression.
107
108 if ( ! is_array( $this->options ) ) { // Just in case.
109
110 return false;
111 }
112
113 $opts = SucomUtil::preg_grep_keys( $opt_key, $this->options );
114
115 return empty( $opts ) ? false : true;
116 }
117
118 return false;
119 }
120
121 public function in_defaults( $opt_key ) {
122
123 if ( isset( $this->defaults[ $opt_key ] ) ) {
124
125 return true;
126
127 } elseif ( false !== strpos( $opt_key, '#' ) ) { // Localized option name.
128
129 $opt_key_locale = SucomUtilOptions::get_key_locale( $opt_key, $this->defaults, 'default' );
130
131 if ( isset( $this->defaults[ $opt_key_locale ] ) ) {
132
133 $this->defaults[ $opt_key ] = $this->defaults[ $opt_key_locale ];
134
135 return true;
136 }
137 }
138
139 return false;
140 }
141
142 /*
143 * $ext_id is the lowercase acronyn for the plugin or add-on.
144 */
145 public function get_ext_id() {
146
147 return $this->ext_id;
148 }
149
150 public function get_text_domain() {
151
152 return $this->text_domain;
153 }
154
155 public function get_default_text_domain() {
156
157 return $this->def_text_domain;
158 }
159
160 public function set_admin_l10n() {
161
162 $this->admin_l10n = $this->get_plugin_admin_l10n();
163 }
164
165 /*
166 * $ext_id is the lowercase acronyn for the plugin or add-on.
167 */
168 public function set_text_domain( $ext_id ) {
169
170 $this->text_domain = $this->get_plugin_text_domain( $ext_id );
171 }
172
173 /*
174 * Get the text domain for the main plugin.
175 *
176 * $plugin_id is the lowercase acronyn for the main plugin.
177 */
178 public function set_default_text_domain( $plugin_id ) {
179
180 $this->def_text_domain = $this->get_plugin_text_domain( $plugin_id );
181 }
182
183 /*
184 * $ext_id is the lowercase acronyn for the plugin or add-on.
185 */
186 public function get_plugin_text_domain( $ext_id ) {
187
188 if ( isset( $this->p->cf[ 'plugin' ][ $ext_id ][ 'text_domain' ] ) ) { // Return the main plugin or add-on text domain.
189
190 return $this->p->cf[ 'plugin' ][ $ext_id ][ 'text_domain' ];
191
192 } elseif ( isset( $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'text_domain' ] ) ) { // Fallback to the main plugin text domain.
193
194 return $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'text_domain' ];
195 }
196
197 return $this->def_text_domain; // Return false or the (previously set) main plugin text domain.
198 }
199
200 public function get_plugin_admin_l10n() {
201
202 if ( isset( $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'admin_l10n' ] ) ) {
203
204 return $this->p->cf[ 'plugin' ][ $this->plugin_id ][ 'admin_l10n' ];
205 }
206
207 return $this->admin_l10n;
208 }
209
210 public function get_option_value_transl( $value, $context = 'option value' ) {
211
212 if ( $this->text_domain ) { // Just in case.
213
214 $value_transl = _x( $value, $context, $this->text_domain ); // Use text domain of main plugin or add-on.
215
216 if ( $value === $value_transl ) { // No translation.
217
218 if ( $this->text_domain !== $this->def_text_domain ) { // Fallback to default text domain of main plugin.
219
220 $value_transl = _x( $value, $context, $this->def_text_domain );
221 }
222 }
223
224 return $value_transl;
225
226 } elseif ( $this->def_text_domain ) { // Fallback to default text domain of main plugin.
227
228 return _x( $value, $context, $this->def_text_domain );
229 }
230
231 return $value;
232 }
233
234 public function get_tr_hide( $in_view, $opt_keys = array() ) {
235
236 $css_class = $this->get_css_class_hide( $in_view, $opt_keys );
237
238 return empty( $css_class ) ? '' : '<tr class="' . $css_class . '">';
239 }
240
241 public function get_tr_hide_img_dim( $in_view, $opt_name ) {
242
243 $css_class = $this->get_css_class_hide_img_dim( $in_view, $opt_name );
244
245 return empty( $css_class ) ? '' : '<tr class="' . $css_class . '">';
246 }
247
248 public function get_tr_hide_prefix( $in_view, $op_prefix ) {
249
250 $css_class = $this->get_css_class_hide_prefix( $in_view, $op_prefix );
251
252 return empty( $css_class ) ? '' : '<tr class="' . $css_class . '">';
253 }
254
255 public function get_tr_hide_vid_dim( $in_view, $opt_name ) {
256
257 $css_class = $this->get_css_class_hide_vid_dim( $in_view, $opt_name );
258
259 return empty( $css_class ) ? '' : '<tr class="' . $css_class . '">';
260 }
261
262 public function get_tr_on_change( $select_id, $select_values ) {
263
264 $css_class = $this->get_css_class_on_change( $select_id, $select_values );
265
266 return empty( $css_class ) ? '' : '<tr class="' . $css_class . '">';
267 }
268
269 public function get_th_html( $label = '', $css_class = '', $css_id = '', $atts = array() ) {
270
271 $input_class = SucomUtil::sanitize_css_class( $css_class );
272 $input_id = SucomUtil::sanitize_css_id( $css_id );
273 $tooltip_text = '';
274
275 if ( ! empty( $css_id ) ) {
276
277 if ( isset( $this->p->msgs ) ) { // Just in case.
278
279 $tooltip_text = $this->p->msgs->get( 'tooltip-' . $css_id, $atts ); // Text is esc_attr().
280 }
281 }
282
283 if ( isset( $atts[ 'is_locale' ] ) ) {
284
285 $label .= ' <span class="option_locale">[' . SucomUtilWP::get_locale() . ']</span>';
286 }
287
288 $html = '<th';
289 $html .= empty( $atts[ 'th_colspan' ] ) ? '' : ' colspan="' . $atts[ 'th_colspan' ] . '"';
290 $html .= empty( $atts[ 'th_rowspan' ] ) ? '' : ' rowspan="' . $atts[ 'th_rowspan' ] . '"';
291 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
292 $html .= empty( $input_id ) ? '' : ' id="th_' . $input_id . '"'; // Already sanitized.
293 $html .= '>' . $label . $tooltip_text . '</th>';
294
295 return $html;
296 }
297
298 public function get_css_class_hide_img_dim( $in_view, $opt_name ) {
299
300 foreach ( array( 'width', 'height', 'crop', 'crop_x', 'crop_y' ) as $opt_name_suffix ) {
301
302 $opt_keys[] = $opt_name . '_' . $opt_name_suffix;
303 }
304
305 return $this->get_css_class_hide( $in_view, $opt_keys );
306 }
307
308 public function get_css_class_hide_prefix( $in_view, $opt_prefix ) {
309
310 $opt_keys = SucomUtilOptions::get_opts_begin( $this->options, $opt_prefix );
311
312 return $this->get_css_class_hide( $in_view, $opt_keys );
313 }
314
315 public function get_css_class_hide_vid_dim( $in_view, $opt_name ) {
316
317 foreach ( array( 'width', 'height' ) as $opt_name_suffix ) {
318
319 $opt_keys[] = $opt_name . '_' . $opt_name_suffix;
320 }
321
322 return $this->get_css_class_hide( $in_view, $opt_keys );
323 }
324
325 public function get_css_class_hide( $in_view, $opt_keys = array() ) {
326
327 $css_class = 'hide_in_' . $in_view;
328
329 if ( empty( $opt_keys ) ) {
330
331 return $css_class;
332
333 } elseif ( ! is_array( $opt_keys ) ) {
334
335 $opt_keys = array( $opt_keys );
336
337 } elseif ( SucomUtil::is_assoc( $opt_keys ) ) {
338
339 $opt_keys = array_keys( $opt_keys );
340 }
341
342 $checked_keys = array();
343
344 foreach ( $opt_keys as $opt_key ) {
345
346 $opt_key = preg_replace( '/[#:].*$/', '', $opt_key ); // Just in case.
347
348 if ( empty( $opt_key ) || ! empty( $checked_keys[ $opt_key ] ) ) {
349
350 continue;
351 }
352
353 $checked_keys[ $opt_key ] = true;
354
355 /*
356 * Example:
357 *
358 * $opt_key_locale = 'site_name#fr_FR'
359 * $opt_key = 'site_name'
360 */
361 $opt_key_locale = SucomUtilOptions::get_key_locale( $opt_key, $this->options );
362
363 if ( isset( $this->defaults[ $opt_key_locale ] ) ) {
364
365 if ( isset( $this->options[ $opt_key_locale ] ) ) {
366
367 /*
368 * Allow comparing strings and integers.
369 */
370 if ( $this->options[ $opt_key_locale ] != $this->defaults[ $opt_key_locale ] ) {
371
372 return ''; // Show option.
373 }
374 }
375 }
376
377 if ( $opt_key_locale !== $opt_key ) {
378
379 if ( isset( $this->defaults[ $opt_key ] ) ) {
380
381 if ( isset( $this->options[ $opt_key_locale ] ) ) {
382
383 /*
384 * Allow comparing strings and integers.
385 */
386 if ( '' !== $this->options[ $opt_key_locale ] &&
387 $this->options[ $opt_key_locale ] != $this->defaults[ $opt_key ] ) {
388
389 return ''; // Show option.
390 }
391 }
392
393 if ( isset( $this->options[ $opt_key ] ) ) {
394
395 /*
396 * Allow comparing strings and integers.
397 */
398 if ( $this->options[ $opt_key ] != $this->defaults[ $opt_key ] ) {
399
400 return ''; // Show option.
401 }
402 }
403 }
404 }
405 }
406
407 return $css_class; // Hide option.
408 }
409
410 public function get_css_class_on_change( $select_id, $select_values ) {
411
412 if ( ! is_array( $select_values ) ) {
413
414 $select_values = array( $select_values );
415 }
416
417 $select_id = SucomUtil::sanitize_css_id( $select_id );
418
419 $css_class = 'hide_' . $select_id;
420
421 foreach ( $select_values as $select_value ) {
422
423 $select_value = SucomUtil::sanitize_css_id( $select_value );
424
425 $css_class .= ' hide_' . $select_id . '_' . $select_value;
426 }
427
428 return $css_class;
429 }
430
431 public function get_md_form_rows( array $table_rows, array $form_rows, array $head = array(), array $mod = array() ) {
432
433 foreach ( $form_rows as $key => $val ) {
434
435 $table_rows[ $key ] = '';
436
437 if ( empty( $val ) ) { // Placeholder.
438
439 continue;
440 }
441
442 if ( empty( $val[ 'label' ] ) ) { // Just in case.
443
444 $val[ 'label' ] = '';
445 }
446
447 if ( isset( $val[ 'tr_class' ] ) ) {
448
449 $tr_html = '<tr class="' . $val[ 'tr_class' ] . '">' . "\n";
450
451 } else $tr_html = '';
452
453 /*
454 * Table cell HTML.
455 */
456 if ( isset( $val[ 'table_row' ] ) ) {
457
458 if ( ! empty( $val[ 'table_row' ] ) ) {
459
460 $table_rows[ $key ] .= $tr_html . $val[ 'table_row' ] . "\n";
461 }
462
463 continue;
464 }
465
466 $td_class = empty( $val[ 'td_class' ] ) ? '' : ' class="' . $val[ 'td_class' ] . '"';
467
468 if ( ! empty( $val[ 'header' ] ) ) {
469
470 $col_span = ' colspan="' . ( isset( $val[ 'col_span' ] ) ? $val[ 'col_span' ] : 2 ) . '"';
471
472 $table_rows[ $key ] .= $tr_html . '<td' . $col_span . $td_class . '>';
473 $table_rows[ $key ] .= '<' . $val[ 'header' ];
474
475 if ( ! empty( $val[ 'header_class' ] ) ) {
476
477 $table_rows[ $key ] .= ' class="' . $val[ 'header_class' ] . '"';
478 }
479
480 $table_rows[ $key ] .= '>' . $val[ 'label' ] . '</' . $val[ 'header' ] . '>';
481 $table_rows[ $key ] .= '</td>' . "\n";
482
483 } else {
484
485 $col_span = empty( $val[ 'col_span' ] ) ? '' : ' colspan="' . $val[ 'col_span' ] .'"';
486
487 $labels = empty( $val[ 'label' ] ) ? array( '' ) : $val[ 'label' ]; // Add at least one empty label.
488 $labels = is_array( $labels ) ? $labels : array( $labels );
489
490 foreach ( $labels as $th_num => $th_label ) {
491
492 $table_rows[ $key ] .= $tr_html . $this->get_th_html( $th_label,
493 ( empty( $val[ 'th_class' ] ) ? '' : $val[ 'th_class' ] ),
494 ( empty( $val[ 'tooltip' ] ) ? '' : $val[ 'tooltip' ] ) ) . "\n";
495 }
496
497 $contents = empty( $val[ 'content' ] ) ? array() : $val[ 'content' ]; // Skip if no content.
498 $contents = is_array( $contents ) ? $contents : array( $contents );
499
500 foreach ( $contents as $td_num => $td_content ) {
501
502 $table_rows[ $key ] .= '<td' . $col_span . $td_class . '>';
503 $table_rows[ $key ] .= $td_content;
504 $table_rows[ $key ] .= '</td>' . "\n";
505 }
506 }
507 }
508
509 return $table_rows;
510 }
511
512 /*
513 * Hidden input field.
514 */
515 public function get_hidden( $name, $value = null ) {
516
517 if ( empty( $name ) ) {
518
519 return; // Just in case.
520 }
521
522 if ( null === $value ) {
523
524 $value = $this->in_options( $name ) ? $this->options[ $name ] : '';
525 }
526
527 return '<input type="hidden" name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '" value="' . esc_attr( $value ) . '" />';
528 }
529
530 /*
531 * Checkbox input field.
532 */
533 public function get_checkbox( $name, $css_class = '', $css_id = '', $is_disabled = false, $force = null, $group = null ) {
534
535 if ( empty( $name ) ) {
536
537 return; // Just in case.
538
539 } elseif ( $force !== null ) {
540
541 $input_checked = checked( $force, 1, false );
542
543 } elseif ( $this->in_options( $name ) ) {
544
545 $input_checked = checked( $this->options[ $name ], 1, false );
546
547 } elseif ( $this->in_defaults( $name ) ) {
548
549 $input_checked = checked( $this->defaults[ $name ], 1, false );
550
551 } else $input_checked = '';
552
553 $default_value = $this->in_defaults( $name ) && ! empty( $this->defaults[ $name ] ) ? 1 : 0;
554 $default_transl = $this->get_option_value_transl( $default_value ? 'enabled' : 'disabled' );
555 $title_transl = sprintf( $this->get_option_value_transl( 'Default is %s' ), $default_transl );
556 $input_class = $css_class . ( $this->get_options( $name . ':disabled' ) ? ' disabled' : '' );
557 $input_class .= ( $input_checked && $default_value ) || ( ! $input_checked && ! $default_value ) ? ' default' : '';
558 $input_class = SucomUtil::sanitize_css_class( $input_class );
559 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
560
561 $html = $is_disabled ? '' : $this->get_hidden( 'is_checkbox_' . $name, 1 );
562 $html .= '<label class="sucom-checkbox"';
563 $html .= $input_id ? ' for="checkbox_' . $input_id . '"' : '';
564 $html .= ' title="' . $title_transl . '">';
565 $html .= '<input type="checkbox"';
566 $html .= $is_disabled ? '' : ' name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '" value="1"';
567 $html .= $is_disabled ? ' disabled="disabled"' : '';
568 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
569 $html .= $input_id ? ' id="checkbox_' . $input_id . '"' : ''; // Already sanitized.
570 $html .= $group ? ' data-group="' . esc_attr( $group ) . '"' : '';
571 $html .= ' data-default-value="' . esc_attr( $default_value ) . '"';
572 $html .= ' ' . $input_checked . '/>';
573 $html .= '<span class="sucom-checkbox-button"></span>';
574 $html .= '</label><!-- .sucom-checkbox -->';
575
576 return $html;
577 }
578
579 /*
580 * Creates a vertical list (by default) of checkboxes.
581 *
582 * The $name_prefix is combined with the $values array names to create the checbox option name.
583 */
584 public function get_checklist( $name_prefix, $values = array(), $css_class = 'column-list', $css_id = '', $is_assoc = null, $is_disabled = false,
585 $event_names = array() ) {
586
587 if ( empty( $name_prefix ) || ! is_array( $values ) ) {
588
589 return;
590 }
591
592 if ( null === $is_assoc ) {
593
594 $is_assoc = SucomUtil::is_assoc( $values );
595 }
596
597 if ( is_string( $event_names ) ) {
598
599 $event_names = array( $event_names );
600
601 } elseif ( ! is_array( $event_names ) ) { // Ignore true, false, null, etc.
602
603 $event_names = array();
604 }
605
606 unset( $values[ 'none' ] ); // Just in case - remove the 'none' value for select arrays.
607
608 $doing_ajax = SucomUtilWP::doing_ajax();
609 $container_class = SucomUtil::sanitize_css_class( $css_class );
610 $container_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name_prefix : $css_id );
611
612 /*
613 * Use the "column-list" class to align the checbox input vertically.
614 */
615 $html = '<div class="' . $container_class . '" id="checklist_' . $container_id . '">' . "\n";
616
617 foreach ( $values as $name_suffix => $label ) {
618
619 if ( is_array( $label ) ) { // Just in case.
620
621 $label = implode( $glue = ', ', $label );
622 }
623
624 /*
625 * If the array is not associative (so a regular numbered array), use the label as the name suffix.
626 */
627 $input_name = $is_assoc ? $name_prefix . '_' . $name_suffix : $name_prefix . '_' . $label;
628 $input_name = SucomUtil::sanitize_input_name( $input_name );
629 $input_id = SucomUtil::sanitize_css_id( $input_name );
630 $label_transl = $this->get_option_value_transl( $label );
631
632 $html .= '<span class="sucom-input-item">';
633 $html .= $this->get_checkbox( $input_name, $input_class = '', $input_id, $is_disabled );
634 $html .= '<span class="sucom-checkbox-label">' . $label_transl . '</span>';
635 $html .= '</span><!-- .sucom-input-item -->';
636
637 foreach ( $event_names as $event_num => $event_name ) {
638
639 $html .= '<!-- event name: ' . $event_name . ' -->' . "\n";
640
641 switch ( $event_name ) {
642
643 case 'on_change_unhide_rows':
644
645 $input_checked = '';
646
647 if ( $this->in_options( $input_name ) ) {
648
649 $input_checked = checked( $this->options[ $input_name ], 1, false );
650
651 } elseif ( $this->in_defaults( $input_name ) ) {
652
653 $input_checked = checked( $this->defaults[ $input_name ], 1, false );
654 }
655
656 $def_hide_class = 'hide_' . esc_js( $input_name );
657 $def_show_class = 'hide_' . esc_js( $input_name . '_' . ( $input_checked ? 1 : 0 ) );
658
659 $html .= '<script>';
660 $html .= 'jQuery( \'#checkbox_' . $input_id . '\' ).on( \'change\', function(){';
661 $html .= 'value = this.checked ? 1 : 0;';
662 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'hide_' . esc_js( $input_name ) . '_\' + value );';
663 $html .= '});';
664
665 if ( $doing_ajax ) {
666
667 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'' . $def_show_class . '\' );';
668
669 } else {
670
671 $html .= 'jQuery( window ).on( \'load\', function(){';
672 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'' . $def_show_class . '\' );';
673 $html .= '});';
674 }
675
676 $html .= '</script>' . "\n";
677
678 break;
679 }
680 }
681 }
682
683 $html .= '</div>' . "\n";
684
685 return $html;
686 }
687
688
689 public function get_checklist_countries( $name_prefix, $css_class = 'column-list', $css_id = '', $is_disabled = false ) {
690
691 $values = SucomUtil::get_alpha2_countries();
692
693 return $this->get_checklist( $name_prefix, $values, $css_class, $css_id, $is_assoc = true, $is_disabled );
694 }
695
696 public function get_checklist_post_types( $name_prefix, $css_class = 'column-list', $css_id = '', $is_disabled = false ) {
697
698 $label_prefix = $this->get_option_value_transl( 'Post Type' );
699
700 $values = SucomUtilWP::get_post_type_labels( $val_prefix = '', $label_prefix );
701
702 return $this->get_checklist( $name_prefix, $values, $css_class, $css_id, $is_assoc = true, $is_disabled );
703 }
704
705 public function get_checklist_post_tax_user( $name_prefix, $css_class = 'column-list', $css_id = '', $is_disabled = false ) {
706
707 $values = $this->get_checklist_post_tax_user_values();
708
709 return $this->get_checklist( $name_prefix, $values, $css_class, $css_id, $is_assoc = true, $is_disabled );
710 }
711
712 public function get_columns_post_tax_user( $name_prefix = 'plugin', $col_headers = array(), $table_class = 'plugin_list_table_cols', $is_disabled = false ) {
713
714 $list_cols = '<table class="' . $table_class . '">' . "\n";
715 $list_cols .= '<tr>';
716
717 foreach ( $col_headers as $col_key => $col_header ) {
718
719 $list_cols .= '<th>' . $col_header . '</th>';
720 }
721
722 $list_cols .= '<td class="underline"></td>';
723 $list_cols .= '</tr>' . "\n";
724
725 $values = $this->get_checklist_post_tax_user_values();
726
727 foreach ( $values as $name_suffix => $label_transl ) {
728
729 $list_cols .= '<tr>';
730
731 foreach ( $col_headers as $col_key => $col_header ) {
732
733 $opt_key = $name_prefix . '_' . $col_key . '_col_' . $name_suffix;
734
735 if ( $this->in_defaults( $opt_key ) ) { // Just in case.
736
737 $list_cols .= '<td class="checkbox' . ( $is_disabled ? ' blank' : '' ) . '">' .
738 $this->get_checkbox( $opt_key, $css_class = '', $css_id = '', $is_disabled ) . '</td>';
739
740 } else {
741
742 $list_cols .= '<td class="checkbox"></td>';
743 }
744 }
745
746 $list_cols .= '<td' . ( $is_disabled ? ' class="blank"' : '' ) . '><p>' . $label_transl . '</p></td>';
747 $list_cols .= '</tr>' . "\n";
748 }
749
750 $list_cols .= '</table>' . "\n";
751
752 return $list_cols;
753 }
754
755 private function get_checklist_post_tax_user_values() {
756
757 $label_prefix = $this->get_option_value_transl( 'Post Type' );
758
759 $values = SucomUtilWP::get_post_type_labels( $val_prefix = '', $label_prefix );
760
761 $label_prefix = $this->get_option_value_transl( 'Taxonomy' );
762
763 $values += SucomUtilWP::get_taxonomy_labels( $val_prefix = 'tax_', $label_prefix );
764
765 $values[ 'user_page' ] = $this->get_option_value_transl( 'User Profiles' );
766
767 asort( $values ); // Sort by label.
768
769 return $values;
770 }
771
772 public function get_amount_currency( $amount_name, $currency_name, $css_class = 'price', $css_id = '', $max_len = 0, $holder = '' ) {
773
774 $currencies = SucomUtil::get_currencies_abbrev();
775
776 return $this->get_input( $amount_name, $css_class, $css_id, $max_len, $holder ) . ' ' .
777 $this->get_select( $currency_name, $currencies, $css_class = 'currency', $css_id = '',
778 $is_assoc = true, $is_disabled = false, $selected = false, $event_names = array( 'on_focus_load_json' ),
779 $event_args = array( 'json_var' => 'currencies' ) );
780 }
781
782 public function get_date_time_timezone( $name_prefix, $media_info = array(), $is_disabled = false, $step_mins = 15, $add_none = true ) {
783
784 $holder_date = '';
785 $selected_time = false;
786 $selected_timezone = false;
787
788 if ( ! empty( $media_info ) && is_array( $media_info ) ) { // Just in case.
789
790 if ( $media_info[ $name_prefix . '_date' ] && $media_info[ $name_prefix . '_time' ] && $media_info[ $name_prefix . '_timezone' ] ) {
791
792 $holder_date = $media_info[ $name_prefix . '_date' ];
793
794 if ( ! $this->in_options( $name_prefix . '_time' ) )
795 $selected_time = $media_info[ $name_prefix . '_time' ];
796
797 if ( ! $this->in_options( $name_prefix . '_timezone' ) )
798 $selected_timezone = $media_info[ $name_prefix . '_timezone' ];
799 }
800 }
801
802 $html = $this->get_input_date( $name_prefix . '_date', $css_class = '', $css_id = '', $holder_date, $is_disabled ) . ' ';
803 $html .= $this->get_option_value_transl( 'at' ) . ' ';
804 $html .= $this->get_select_time( $name_prefix . '_time', $css_class = '', $css_id = '', $is_disabled, $selected_time, $step_mins, $add_none ) . ' ';
805 $html .= $this->get_option_value_transl( 'tz' ) . ' ';
806 $html .= $this->get_select_timezone( $name_prefix . '_timezone', $css_class = '', $css_id = '', $is_disabled, $selected_timezone );
807
808 return $html;
809 }
810
811 /*
812 * Deprecated on 2024/08/09.
813 */
814 public function get_date_time_tz( $name_prefix, $is_disabled = false, $step_mins = 15, $add_none = true ) {
815
816 return $this->get_date_time_timezone( $name_prefix, $media_info = array(), $is_disabled, $step_mins, $add_none );
817 }
818
819 /*
820 * Text input field.
821 */
822 public function get_input( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false, $tabidx = null, $el_attr = '' ) {
823
824 if ( empty( $name ) ) {
825
826 return; // Just in case.
827
828 } elseif ( $is_disabled ) {
829
830 return $this->get_no_input( $name, $css_class, $css_id, $holder );
831 }
832
833 $holder = $this->get_placeholder_sanitized( $name, $holder );
834 $value = $this->in_options( $name ) ? $this->options[ $name ] : '';
835 $input_class = $css_class . ( $this->get_options( $name . ':disabled' ) ? ' disabled' : '' );
836 $input_class = SucomUtil::sanitize_css_class( $input_class );
837 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
838
839 if ( ! is_array( $len ) ) { // A non-array value defaults to a max length.
840
841 $len = empty( $len ) ? array() : array( 'max' => $len );
842 }
843
844 $html = '<input type="text" name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '"';
845 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
846 $html .= empty( $input_id ) ? '' : ' id="text_' . $input_id . '"'; // Already sanitized.
847 $html .= empty( $el_attr ) ? '' : ' ' . trim( $el_attr );
848 $html .= is_numeric( $tabidx ) ? '' : ' tabindex="' . esc_attr( $tabidx ) . '"';
849
850 foreach ( $len as $key => $val ) {
851
852 $html .= empty( $len[ $key ] ) ? '' : ' ' . $key . 'Length="' . esc_attr( $len[ $key ] ) . '"';
853 }
854
855 $html .= $this->get_placeholder_attrs( $type = 'input', $holder, $name );
856 $html .= ' value="' . esc_attr( $value ) . '" />' . "\n";
857 $html .= empty( $len ) ? '' : '<div id="text_' . $input_id . '-text-len-wrapper"></div>' . "\n";
858
859 if ( ! empty( $len ) ) {
860
861 $html .= $this->get_script_text_len( 'text_' . $input_id );
862 }
863
864 return $html;
865 }
866
867 public function get_input_dep( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false, $dep_id = '' ) {
868
869 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
870
871 $html = $this->get_input( $name, $css_class, $input_id, $len, $holder, $is_disabled );
872
873 if ( $dep_id ) { // Just in case.
874
875 $html .= $this->get_script_placeholder_dep( 'input#text_' . $input_id, 'input#text_' . $dep_id );
876 }
877
878 return $html;
879 }
880
881 public function get_input_color( $name = '', $css_class = '', $css_id = '', $is_disabled = false ) {
882
883 $input_class = 'colorpicker ' . $css_class . ( $this->get_options( $name . ':disabled' ) ? ' disabled' : '' );
884 $input_class = SucomUtil::sanitize_css_class( $input_class );
885 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
886
887 if ( empty( $name ) ) {
888
889 $is_disabled = true;
890 $input_value = '';
891
892 } else {
893
894 $input_value = $this->in_options( $name ) ? $this->options[ $name ] : '';
895 }
896
897 $html = '<input type="text"';
898 $html .= $is_disabled ? ' disabled="disabled"' : ' name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '"';
899 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
900 $html .= $input_id ? ' id="text_' . $input_id . '"' : ''; // Already sanitized.
901 $html .= ' placeholder="#000000" value="' . esc_attr( $input_value ) . '"';
902 $html .= ' data-default-color="' . esc_attr( $input_value ) . '"';
903 $html .= '/>';
904
905 return $html;
906 }
907
908 public function get_input_date( $name = '', $css_class = '', $css_id = '', $holder = '', $is_disabled = false, $min_date = '', $max_date = '' ) {
909
910 $holder = $holder ? $holder : ( $this->in_defaults( $name ) ? $this->defaults[ $name ] : 'yyyy-mm-dd' );
911 $el_attr = $min_date ? ' min="' . esc_attr( $min_date ) . '"' : '';
912 $el_attr .= $max_date ? ' max="' . esc_attr( $max_date ) . '"' : '';
913
914 return $this->get_input( $name, 'datepicker ' . $css_class, $css_id, $len = 0, $holder, $is_disabled, $tabidx = null, $el_attr );
915 }
916
917 public function get_input_time_dhms( $name_prefix ) {
918
919 static $days_sep = null;
920 static $hours_sep = null;
921 static $mins_sep = null;
922 static $secs_sep = null;
923
924 if ( null === $days_sep ) { // Translate only once.
925
926 $days_sep = ' ' . _x( 'days', 'option comment', 'wpsso' ) . ', ';
927 $hours_sep = ' ' . _x( 'hours', 'option comment', 'wpsso' ) . ', ';
928 $mins_sep = ' ' . _x( 'mins', 'option comment', 'wpsso' ) . ', ';
929 $secs_sep = ' ' . _x( 'secs', 'option comment', 'wpsso' );
930 }
931
932 return $this->get_input( $name_prefix . '_days', $css_class = 'xshort', $css_id = '', $max_len = 0, $holder = 0 ) . $days_sep .
933 $this->get_input( $name_prefix . '_hours', $css_class = 'xshort', $css_id = '', $max_len = 0, $holder = 0 ) . $hours_sep .
934 $this->get_input( $name_prefix . '_mins', $css_class = 'xshort', $css_id = '', $max_len = 0, $holder = 0 ) . $mins_sep .
935 $this->get_input( $name_prefix . '_secs', $css_class = 'xshort', $css_id = '', $max_len = 0, $holder = 0 ) . $secs_sep;
936 }
937
938 public function get_input_image_crop_area( $name, $add_none = false, $is_disabled = false ) {
939
940 $css_class = 'crop-area';
941 $css_id = '';
942 $is_assoc = true;
943 $html = '';
944
945 foreach ( array( 'crop_x', 'crop_y' ) as $key ) {
946
947 $values = $this->p->cf[ 'form' ][ 'position_' . $key ];
948
949 if ( $add_none ) {
950
951 $html .= $this->get_select_none( $name . '_' . $key, $values, $css_class, $css_id, $is_assoc, $is_disabled );
952
953 } else $html .= $this->get_select( $name . '_' . $key, $values, $css_class, $css_id, $is_assoc, $is_disabled );
954 }
955
956 return $html;
957 }
958
959 public function get_input_image_dimensions( $name_prefix, $is_disabled = false ) {
960
961 $html = $this->get_input( $name_prefix . '_width', $css_class = 'size width', $css_id = '', $len = 0, $holder = '', $is_disabled );
962 $html .= 'x' . "\n";
963 $html .= $this->get_input( $name_prefix . '_height', $css_class = 'size height', $css_id = '', $len = 0, $holder = '', $is_disabled ) . 'px' . ' ';
964 $html .= _x( 'crop', 'option comment', $this->text_domain );
965 $html .= $this->get_checkbox( $name_prefix . '_crop', '', '', $is_disabled );
966 $html .= '<div class="image_crop_area">';
967 $html .= _x( 'from', 'option comment', $this->text_domain ) . "\n";
968 $html .= $this->get_input_image_crop_area( $name_prefix, $add_none = false, $is_disabled );
969 $html .= '</div>';
970
971 return $html;
972 }
973
974 public function get_input_image_upload( $name_prefix, $holder = '', $is_disabled = false, $input_name_id_attr = '' ) {
975
976 // translators: Please ignore - translation uses a different text domain.
977 $img_libs = array( 'wp' => __( 'Media Library' ) );
978 $selected_lib = false;
979
980 list( $name_prefix, $name_suffix ) = $this->split_name_locale( $name_prefix );
981
982 $input_name_id_locale = $name_prefix . '_id' . $name_suffix;
983 $input_name_lib_locale = $name_prefix . '_id_lib' . $name_suffix;
984 $input_name_url_locale = $name_prefix . '_url' . $name_suffix;
985
986 $def_id_value = $this->get_defaults_locale( $input_name_id_locale );
987 $def_lib_value = $this->get_defaults_locale( $input_name_lib_locale );
988
989 $holder = $holder && $def_id_value ? $def_id_value : $holder;
990
991 $img_id_value = $this->get_options_locale( $input_name_id_locale );
992 $img_lib_value = $this->get_options_locale( $input_name_lib_locale, $def_lib_value );
993 $img_url_value = $this->get_options_locale( $input_name_url_locale );
994
995 $id_disabled_css_class = $this->get_options( $input_name_id_locale . ':disabled' ) ? ' disabled' : '';
996 $upload_css_class = 'sucom_image_upload_button button' . $id_disabled_css_class;
997 $img_id_css_class = 'sucom_image_upload_id' . $id_disabled_css_class;
998 $img_lib_css_class = 'sucom_image_upload_lib' . $id_disabled_css_class;
999
1000 $preview_css_id = SucomUtil::sanitize_css_id( 'preview_' . $input_name_id_locale );
1001 $upload_css_id = SucomUtil::sanitize_css_id( 'upload_' . $input_name_id_locale );
1002 $img_id_css_id = SucomUtil::sanitize_css_id( $input_name_id_locale );
1003 $img_lib_css_id = SucomUtil::sanitize_css_id( $input_name_lib_locale );
1004 $img_url_css_id = SucomUtil::sanitize_css_id( $input_name_url_locale );
1005
1006 $input_name_id_attr .= ' data-preview-css-id="' . $preview_css_id . '"' .
1007 ' data-img-lib-css-id="select_' . $img_lib_css_id . '"' .
1008 ' data-img-url-css-id="text_' . $img_url_css_id . '"';
1009
1010 $input_name_lib_attr = ' data-img-id-css-id="text_' . $img_id_css_id . '"' .
1011 ' data-upload-css-id="button_' . $upload_css_id . '"';
1012
1013 $upload_button_data = array(
1014 'img-id-css-id' => 'text_' . $img_id_css_id,
1015 'img-lib-css-id' => 'select_' . $img_lib_css_id,
1016 );
1017
1018 if ( 'wp' === $img_lib_value ) {
1019
1020 if ( $img_id_value ) {
1021
1022 $upload_button_data[ 'wp-img-id' ] = $img_id_value;
1023
1024 } elseif ( $holder ) {
1025
1026 $upload_button_data[ 'wp-img-id' ] = $holder;
1027 }
1028 }
1029
1030 $img_libs_count = count( $img_libs );
1031 $upload_disabled = function_exists( 'wp_enqueue_media' ) ? $is_disabled : true; // Just in case.
1032 $img_id_disabled = $is_disabled;
1033 $img_lib_disabled = $img_libs_count > 1 ? $is_disabled : true;
1034
1035 /*
1036 * Prevent conflicts by removing the image URL if we have an image ID.
1037 *
1038 * Disable the image ID option if we have an image URL.
1039 */
1040 if ( ! empty( $img_id_value ) ) {
1041
1042 unset( $this->options[ $input_name_url_locale ] );
1043 unset( $this->options[ $input_name_url_locale . ':disabled' ] );
1044 unset( $this->options[ $input_name_url_locale . ':width' ] );
1045 unset( $this->options[ $input_name_url_locale . ':height' ] );
1046
1047 } elseif ( ! empty( $img_url_value ) ) {
1048
1049 unset( $this->options[ $input_name_id_locale ] );
1050 unset( $this->options[ $input_name_lib_locale ] );
1051
1052 $holder = ''; // Just in case.
1053 $upload_disabled = true;
1054 $img_id_disabled = true;
1055 }
1056
1057 if ( ! empty( $img_libs[ 'wp' ] ) ) {
1058
1059 // translators: Please ignore - translation uses a different text domain.
1060 $upload_label = __( 'Select Image' );
1061 $upload_button = $this->get_button( $upload_label, $upload_css_class, $upload_css_id,
1062 $url = '', $newtab = false, $upload_disabled, $upload_button_data );
1063
1064 if ( 1 === $img_libs_count ) {
1065
1066 $img_lib_css_class .= ' hidden';
1067 }
1068 }
1069
1070 $select_lib = $this->get_select( $input_name_lib_locale, $img_libs, $img_lib_css_class, $img_lib_css_id,
1071 $is_assoc = true, $img_lib_disabled, $selected_lib, $event_names = array(), $event_args = array(),
1072 $input_name_lib_attr );
1073
1074 $input_id = $this->get_input( $input_name_id_locale, $img_id_css_class, $img_id_css_id,
1075 $len = 0, $holder, $img_id_disabled, $tabidx = null, $input_name_id_attr );
1076
1077 $html = '<div class="sucom_image_upload">';
1078 $html .= $select_lib . ' ';
1079 $html .= $input_id . ' ';
1080 $html .= $upload_button . ' ';
1081 $html .= '</div>';
1082 $html .= '<div class="sucom_image_upload_preview" id="' . $preview_css_id . '"></div>';
1083
1084 return $html;
1085 }
1086
1087 public function get_input_image_url( $name_prefix, $url = '', $is_disabled = false ) {
1088
1089 return $this->get_input_media_url( $name_prefix, $primary_suffix = 'id', $url, $is_disabled );
1090 }
1091
1092 public function get_input_video_dimensions( $name_prefix, $media_info = array(), $is_disabled = false ) {
1093
1094 $holder_width = '';
1095 $holder_height = '';
1096
1097 if ( ! empty( $media_info ) && is_array( $media_info ) ) { // Just in case.
1098
1099 if ( $media_info[ $name_prefix . '_width' ] && $media_info[ $name_prefix . '_height' ] ) {
1100
1101 $holder_width = $media_info[ $name_prefix . '_width' ];
1102 $holder_height = $media_info[ $name_prefix . '_height' ];
1103 }
1104 }
1105
1106 $html = $this->get_input( $name_prefix . '_width', $css_class = 'size width', $css_id = '', $len = 0, $holder_width, $is_disabled ) . 'x&nbsp;';
1107 $html .= $this->get_input( $name_prefix . '_height', $css_class = 'size height', $css_id = '', $len = 0, $holder_height, $is_disabled ) . 'px';
1108
1109 return $html;
1110 }
1111
1112 public function get_input_video_url( $name_prefix, $url = '', $is_disabled = false ) {
1113
1114 return $this->get_input_media_url( $name_prefix, $primary_suffix = 'embed', $url, $is_disabled );
1115 }
1116
1117 /*
1118 * Select drop-down field.
1119 *
1120 * $is_disabled can be false or an option value for the disabled select.
1121 */
1122 public function get_select( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null, $is_disabled = false, $selected = false,
1123 $event_names = array(), $event_args = array(), $el_attr = '' ) {
1124
1125 if ( empty( $name ) ) return ''; // Just in case.
1126
1127 $filter_name = SucomUtil::sanitize_hookname( $this->plugin_id . '_form_select_' . $name );
1128
1129 $values = apply_filters( $filter_name, $values );
1130
1131 if ( ! is_array( $values ) ) return ''; // Just in case.
1132
1133 if ( 'sorted' === $is_assoc ) {
1134
1135 $event_args[ 'is_sorted' ] = true;
1136
1137 $is_assoc = null;
1138 }
1139
1140 if ( null === $is_assoc ) $is_assoc = SucomUtil::is_assoc( $values );
1141
1142 /*
1143 * Maybe add a custom selected string to the values.
1144 */
1145 if ( ! is_bool( $selected ) ) {
1146
1147 if ( ! isset( $values[ $selected ] ) ) {
1148
1149 if ( $is_assoc ) {
1150
1151 $values[ $selected ] = $selected;
1152
1153 } else { $values[] = $selected; }
1154 }
1155
1156 }
1157
1158 /*
1159 * Maybe add a custom default string to the values.
1160 */
1161 if ( $this->in_defaults( $name ) ) {
1162
1163 if ( ! isset( $values[ $this->defaults[ $name ] ] ) ) {
1164
1165 if ( $is_assoc ) { $values[ $this->defaults[ $name ] ] = $this->defaults[ $name ]; }
1166 else { $values[] = $this->defaults[ $name ]; }
1167 }
1168 }
1169
1170 if ( is_string( $event_names ) ) {
1171
1172 $event_names = array( $event_names );
1173
1174 } elseif ( ! is_array( $event_names ) ) { // Just in case - ignore true, false, null, etc.
1175
1176 $event_names = array();
1177 }
1178
1179 if ( is_string( $event_args ) ) { // Backwards compatibility.
1180
1181 $event_args = array( 'json_var' => $event_args );
1182
1183 } elseif ( ! is_array( $event_args ) ) { // Just in case - ignore true, false, null, etc.
1184
1185 $event_args = array();
1186 }
1187
1188 $event_json_var = false;
1189
1190 if ( in_array( 'on_focus_load_json', $event_names ) ) {
1191
1192 $event_json_var = $this->plugin_id . '_select';
1193
1194 if ( ! empty( $event_args[ 'json_var' ] ) ) {
1195
1196 $event_json_var .= '_' . $event_args[ 'json_var' ];
1197 }
1198
1199 $event_json_var .= '_' . md5( serialize( $values ) );
1200
1201 $event_json_var = SucomUtil::sanitize_hookname( $event_json_var );
1202 }
1203
1204 $html = '';
1205 $row_id = empty( $css_id ) ? 'tr_' . $name : 'tr_' . $css_id;
1206 $input_class = $css_class . ( $this->get_options( $name . ':disabled' ) ? ' disabled' : '' );
1207 $input_class = SucomUtil::sanitize_css_class( $input_class );
1208 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
1209 $in_options = $this->in_options( $name ); // Optimize and call only once - returns true or false.
1210 $in_defaults = $this->in_defaults( $name ); // Optimize and call only once - returns true or false.
1211 $selected_value = '';
1212 $select_opt_count = 0; // Used to check for first option.
1213 $select_opt_added = 0;
1214 $select_opt_arr = array();
1215 $select_json_arr = array();
1216 $default_value = '';
1217 $default_text = '';
1218
1219 /*
1220 * Check for two-dimentional arrays and maybe use option groups.
1221 */
1222 $values = self::maybe_transl_sort_values( $name, $values, $is_assoc, $event_args );
1223
1224 foreach ( $values as $optgroup_transl => $group_array ) {
1225
1226 if ( is_array( $group_array ) ) { // Two dimensional array.
1227
1228 if ( $event_json_var ) {
1229
1230 if ( empty( $this->json_array_added[ $event_json_var ] ) ) {
1231
1232 $select_json_arr[ $optgroup_transl . ':optgroup-begin' ] = $optgroup_transl;
1233 }
1234
1235 } else $select_opt_arr[] = '<optgroup label="' . esc_attr( $optgroup_transl ) . '">';
1236
1237 $group_values = $group_array;
1238
1239 } else $group_values = array( $optgroup_transl => $group_array );
1240
1241 foreach ( $group_values as $option_value => $label_transl ) {
1242
1243 $select_opt_count++; // Used to check for first option.
1244
1245 if ( is_array( $label_transl ) ) { // Just in case.
1246
1247 $label_transl = implode( $glue = ', ', $label_transl );
1248 }
1249
1250 /*
1251 * Save the option value and translated label for the json array before adding "(default)" suffix.
1252 */
1253 if ( $event_json_var ) {
1254
1255 if ( empty( $this->json_array_added[ $event_json_var ] ) ) {
1256
1257 $select_json_arr[ $option_value ] = $label_transl;
1258 }
1259 }
1260
1261 /*
1262 * Save the default value and its text so we can add them (as jquery data) to the select.
1263 */
1264 if ( $in_defaults && (string) $option_value === (string) $this->defaults[ $name ] ) {
1265
1266 $default_value = $option_value;
1267 $default_text = $this->get_option_value_transl( '(default)' );
1268 $label_transl .= ' ' . $default_text;
1269 }
1270
1271 /*
1272 * Maybe get a selected="selected" string for this option.
1273 */
1274 if ( ! is_bool( $selected ) ) {
1275
1276 $is_selected_html = selected( $selected, $option_value, false );
1277
1278 } elseif ( $in_options ) {
1279
1280 $is_selected_html = selected( $this->options[ $name ], $option_value, false );
1281
1282 } elseif ( $in_defaults ) {
1283
1284 $is_selected_html = selected( $this->defaults[ $name ], $option_value, false );
1285
1286 } else $is_selected_html = '';
1287
1288 /*
1289 * If the selected value is the default, add the default class.
1290 */
1291 if ( $is_selected_html && $in_defaults && $option_value === $this->defaults[ $name ] ) {
1292
1293 $input_class .= ' default';
1294 }
1295
1296 /*
1297 * Save either the first or selected value for the 'on_change_unhide_rows' event.
1298 */
1299 if ( $is_selected_html || $select_opt_count === 1 ) {
1300
1301 $selected_value = $option_value;
1302 }
1303
1304 /*
1305 * Only include the first and selected option(s).
1306 */
1307 if ( ( ! $is_disabled && ! $event_json_var ) || $is_selected_html || $select_opt_count === 1 ) {
1308
1309 if ( ! isset( $select_opt_arr[ $option_value ] ) ) {
1310
1311 $select_opt_arr[ $option_value ] = '<option value="' . esc_attr( $option_value ) . '"' .
1312 $is_selected_html . '>' . $label_transl . '</option>';
1313
1314 $select_opt_added++;
1315 }
1316 }
1317 }
1318
1319 if ( is_array( $group_array ) ) {
1320
1321 if ( $event_json_var ) {
1322
1323 if ( empty( $this->json_array_added[ $event_json_var ] ) ) {
1324
1325 $select_json_arr[ $optgroup_transl . ':optgroup-end' ] = $optgroup_transl;
1326 }
1327
1328 } else $select_opt_arr[] = '</optgroup>';
1329 }
1330 }
1331
1332 $html .= "\n";
1333 $html .= '<select ';
1334 $html .= $is_disabled ? '' : ' name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '"';
1335 $html .= $is_disabled ? ' disabled="disabled"' : '';
1336 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
1337 $html .= $input_id ? ' id="select_' . $input_id . '"' : ''; // Already sanitized.
1338 $html .= ' data-default-value="' . esc_attr( $default_value ) . '"';
1339 $html .= ' data-default-text="' . esc_attr( $default_text ) . '"';
1340 $html .= $el_attr ? ' ' . trim( $el_attr ) : '';
1341 $html .= '>' . "\n";
1342 $html .= implode( $glue = "\n", $select_opt_arr );
1343 $html .= '<!-- ' . $select_opt_added . ' select options added -->' . "\n";
1344 $html .= '</select>' . "\n";
1345
1346 foreach ( $event_names as $event_num => $event_name ) {
1347
1348 $html .= '<!-- event name: ' . $event_name . ' -->' . "\n";
1349
1350 switch ( $event_name ) {
1351
1352 case 'on_focus_show':
1353
1354 $show_id = null;
1355
1356 if ( ! empty( $event_args[ 'show_id' ] ) ) {
1357
1358 $show_id = $event_args[ 'show_id' ];
1359
1360 } elseif ( $event_args && is_string( $event_args ) ) { // Deprecated.
1361
1362 $show_id = $event_args;
1363 }
1364
1365 if ( $show_id ) {
1366
1367 $html .= '<script>';
1368 $html .= 'jQuery( \'#select_' . $input_id . '\' ).on( \'focus\', function(){';
1369 $html .= 'jQuery( \'' . $show_id . '\' ).show();';
1370 $html .= '});';
1371 $html .= '</script>' . "\n";
1372 }
1373
1374 break;
1375
1376 case 'on_focus_load_json':
1377
1378 $html .= $this->get_script_load_json( $event_json_var, $event_args, $select_json_arr, 'select_' . $input_id );
1379
1380 break;
1381
1382 case 'on_focus_get_ajax':
1383
1384 break;
1385
1386 case 'on_change_redirect':
1387
1388 $redirect_url = add_query_arg( array( $name => '%%' . $name . '%%' ),
1389 SucomUtil::get_prot() . '://' . $_SERVER[ 'SERVER_NAME' ] . $_SERVER[ 'REQUEST_URI' ] );
1390
1391 $redirect_url_encoded = SucomUtil::esc_url_encode( $redirect_url );
1392
1393 $html .= '<script>';
1394 $html .= 'jQuery( \'#select_' . $input_id . '\' ).on( \'change\', function(){';
1395 $html .= 'sucomSelectChangeRedirect( \'' . esc_js( $name ) . '\', this.value, \'' . $redirect_url_encoded . '\' );';
1396 $html .= '});';
1397 $html .= '</script>' . "\n";
1398
1399 break;
1400
1401 case 'on_show_unhide_rows':
1402
1403 $html .= $this->get_script_trigger_show_hide();
1404
1405 // No break.
1406
1407 case 'on_change_unhide_rows':
1408
1409 $def_hide_class = 'hide_' . esc_js( $name );
1410 $def_show_class = 'hide_' . esc_js( $name . '_' . SucomUtil::sanitize_css_id( $selected_value ) );
1411
1412 $html .= '<script>';
1413 $html .= 'jQuery( \'#select_' . $input_id . '\' ).on( \'change\', function(){';
1414 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'hide_' . esc_js( $name ) . '_\' + this.value );';
1415 $html .= '});';
1416 $html .= '</script>' . "\n";
1417
1418 $html .= '<!-- selected value: ' . $selected_value . ' -->' . "\n";
1419
1420 /*
1421 * If we have an option selected, unhide those rows.
1422 *
1423 * Test for a non-empty string to allow for a value of 0.
1424 */
1425 if ( '' !== $selected_value ) {
1426
1427 $html .= '<script>';
1428
1429 if ( 'on_show_unhide_rows' === $event_name ) {
1430
1431 $html .= 'jQuery( \'tr#' . esc_js( $row_id ) . '\' ).on( \'show\', function(){';
1432 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'' . $def_show_class . '\' );';
1433 $html .= '});';
1434
1435 } else {
1436
1437 $doing_ajax = SucomUtilWP::doing_ajax();
1438
1439 if ( $doing_ajax ) {
1440
1441 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'' . $def_show_class . '\' );';
1442
1443 } else {
1444
1445 $html .= 'jQuery( window ).on( \'load\', function(){';
1446 $html .= 'sucomChangeHideUnhideRows( \'' . $def_hide_class . '\', \'' . $def_show_class . '\' );';
1447 $html .= '});';
1448 }
1449 }
1450
1451 $html .= '</script>' . "\n";
1452 }
1453
1454 break;
1455 }
1456 }
1457
1458 return $html;
1459 }
1460
1461 public function get_select_country( $name, $css_class = '', $css_id = '', $is_disabled = false, $selected = false ) {
1462
1463 /*
1464 * Set 'none' as the default if no default is defined.
1465 */
1466 if ( ! empty( $name ) ) { // Just in case.
1467
1468 if ( ! $this->in_defaults( $name ) ) {
1469
1470 $this->defaults[ $name ] = 'none'; // Required for sanity check.
1471 }
1472 }
1473
1474 /*
1475 * Sanity check for older input field values.
1476 */
1477 if ( false === $selected ) {
1478
1479 if ( empty( $this->options[ $name ] ) || ( 'none' !== $this->options[ $name ] && 2 !== strlen( $this->options[ $name ] ) ) ) {
1480
1481 $selected = $this->defaults[ $name ];
1482 }
1483 }
1484
1485 return $this->get_select_none( $name, SucomUtil::get_alpha2_countries(), $css_class, $css_id,
1486 $is_assoc = true, $is_disabled, $selected, $event_names = array( 'on_focus_load_json' ),
1487 $event_args = array( 'json_var' => 'alpha2_countries' ));
1488 }
1489
1490 public function get_select_education_level( $name, $css_class = '', $css_id = '', $is_disabled = false, $selected = false ) {
1491
1492 if ( ! class_exists( 'SucomEducationLevels' ) ) {
1493
1494 require_once dirname( __FILE__ ) . '/education-levels.php';
1495 }
1496
1497 return $this->get_select_none( $name, SucomEducationLevels::get(), $css_class, $css_id,
1498 $is_assoc = 'sorted', $is_disabled, $selected, $event_names = array( 'on_focus_load_json' ),
1499 $event_args = array( 'json_var' => 'education_levels' ) );
1500 }
1501
1502 /*
1503 * Add 'none' as the first array element. Always converts the array to associative.
1504 */
1505 public function get_select_none( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null, $is_disabled = false,
1506 $selected = false, $event_names = array(), $event_args = array() ) {
1507
1508 /*
1509 * Set 'none' as the default if no default is defined.
1510 */
1511 if ( ! empty( $name ) ) {
1512
1513 if ( ! $this->in_defaults( $name ) ) {
1514
1515 $this->defaults[ $name ] = 'none';
1516 }
1517 }
1518
1519 if ( null === $is_assoc ) {
1520
1521 $is_assoc = SucomUtil::is_assoc( $values );
1522 }
1523
1524 if ( ! $is_assoc ) {
1525
1526 $new_values = array();
1527
1528 foreach ( $values as $option_value => $label ) {
1529
1530 if ( is_array( $label ) ) { // Just in case.
1531
1532 $label = implode( $glue = ', ', $label );
1533 }
1534
1535 $new_values[ (string) $label ] = $label;
1536 }
1537
1538 $values = $new_values;
1539
1540 unset( $new_values );
1541 }
1542
1543 unset( $values[ 'none' ] ); // Just in case.
1544
1545 $values = array( 'none' => '[None]' ) + $values;
1546
1547 if ( empty( $is_assoc ) ) $is_assoc = true; // Allow for 'sorted' value.
1548
1549 return $this->get_select( $name, $values, $css_class, $css_id, $is_assoc, $is_disabled, $selected, $event_names, $event_args );
1550 }
1551
1552 /*
1553 * The "time-hh-mm" class is always prefixed to the $css_class value.
1554 *
1555 * By default, the 'none' array element is not added.
1556 */
1557 public function get_select_time( $name, $css_class = '', $css_id = '', $is_disabled = false, $selected = false, $step_mins = 15, $add_none = false ) {
1558
1559 $time_mins = SucomUtil::get_hours( 60 * $step_mins );
1560 $css_class = trim( 'time-hh-mm ' . $css_class );
1561 $event_names = array( 'on_focus_load_json' );
1562 $event_args = array( 'json_var' => 'hour_mins_step_' . $step_mins );
1563
1564 /*
1565 * Set 'none' as the default if no default is defined.
1566 */
1567 if ( $add_none ) {
1568
1569 $event_args[ 'json_var' ] .= '_add_none';
1570
1571 if ( ! empty( $name ) ) {
1572
1573 if ( ! $this->in_defaults( $name ) ) {
1574
1575 $this->defaults[ $name ] = 'none';
1576 }
1577 }
1578
1579 return $this->get_select_none( $name, $time_mins, $css_class, $css_id, $is_assoc = true,
1580 $is_disabled, $selected, $event_names, $event_args );
1581 }
1582
1583 return $this->get_select( $name, $time_mins, $css_class, $css_id, $is_assoc = true,
1584 $is_disabled, $selected, $event_names, $event_args );
1585 }
1586
1587 public function get_select_time_none( $name, $css_class = '', $css_id = '', $is_disabled = false, $selected = false, $step_mins = 15 ) {
1588
1589 /*
1590 * Set 'none' as the default if no default is defined.
1591 */
1592 if ( ! empty( $name ) ) {
1593
1594 if ( ! $this->in_defaults( $name ) ) {
1595
1596 $this->defaults[ $name ] = 'none';
1597 }
1598 }
1599
1600 return $this->get_select_time( $name, $css_class, $css_id, $is_disabled, $selected, $step_mins, $add_none = true );
1601 }
1602
1603 /*
1604 * The "timezone" class is always prefixed to the $css_class value.
1605 */
1606 public function get_select_timezone( $name, $css_class = '', $css_id = '', $is_disabled = false, $selected = false ) {
1607
1608 $css_class = trim( 'timezone ' . $css_class );
1609
1610 /*
1611 * Returns an associative array of timezone strings (ie. 'Africa/Abidjan'), 'UTC', and offsets (ie. '-07:00').
1612 */
1613 $timezones = SucomUtil::get_timezones();
1614
1615 if ( ! empty( $name ) ) {
1616
1617 if ( ! $this->in_defaults( $name ) ) {
1618
1619 $this->defaults[ $name ] = SucomUtil::get_default_timezone();
1620 }
1621 }
1622
1623 return $this->get_select( $name, $timezones, $css_class, $css_id, $is_assoc = true, $is_disabled, $selected,
1624 $event_names = array( 'on_focus_load_json' ), $event_args = array( 'json_var' => 'timezones' ) );
1625 }
1626
1627 public function get_submit( $value, $css_class = 'button-primary', $css_id = '' ) {
1628
1629 $input_class = SucomUtil::sanitize_css_class( $css_class );
1630 $input_id = SucomUtil::sanitize_css_id( $css_id );
1631
1632 $html = '<input type="submit"';
1633 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
1634 $html .= empty( $input_id ) ? '' : ' id="submit_' . $input_id . '"'; // Already sanitized.
1635 $html .= ' value="' . esc_attr( $value ) . '"/>';
1636
1637 return $html;
1638 }
1639
1640 public function get_video_dimensions_text( $name_prefix, $media_info = array() ) {
1641
1642 if ( ! empty( $this->options[ $name_prefix . '_width' ] ) && ! empty( $this->options[ $name_prefix . '_height' ] ) ) {
1643
1644 return $this->options[ $name_prefix . '_width' ] . 'x' . $this->options[ $name_prefix . '_height' ] . 'px';
1645
1646 }
1647
1648 if ( ! empty( $media_info ) && is_array( $media_info ) ) {
1649
1650 if ( $media_info[ $name_prefix . '_width' ] && $media_info[ $name_prefix . '_height' ] ) {
1651
1652 $holder_width = $media_info[ $name_prefix . '_width' ];
1653 $holder_height = $media_info[ $name_prefix . '_height' ];
1654
1655 return $holder_width . 'x' . $holder_height . 'px';
1656 }
1657 }
1658
1659 return '';
1660 }
1661
1662 public function get_textarea( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false ) {
1663
1664 if ( empty( $name ) ) {
1665
1666 return; // Just in case.
1667 }
1668
1669 $input_class = $css_class . ( $this->get_options( $name . ':disabled' ) ? ' disabled' : '' );
1670 $input_class = SucomUtil::sanitize_css_class( $input_class );
1671 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
1672 $input_rows = '';
1673 $value = $this->in_options( $name ) ? $this->options[ $name ] : '';
1674 $holder = $this->get_placeholder_sanitized( $name, $holder );
1675
1676 if ( ! is_array( $len ) ) {
1677
1678 $len = array( 'max' => $len );
1679 }
1680
1681 if ( ! empty( $len[ 'rows' ] ) ) {
1682
1683 $input_rows = $len[ 'rows' ];
1684
1685 } elseif ( ! empty( $len[ 'max' ] ) ) {
1686
1687 $input_rows = round( $len[ 'max' ] / 100 ) + 1;
1688 }
1689
1690 $html = '<textarea ';
1691 $html .= $is_disabled ? ' disabled="disabled"' : ' name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '"';
1692 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
1693 $html .= $input_id ? ' id="textarea_' . $input_id . '"' : ''; // Already sanitized.
1694 $html .= $input_rows ? ' rows="' . $input_rows . '"' : '';
1695 $html .= empty( $len[ 'max' ] ) || $is_disabled ? '' : ' maxLength="' . esc_attr( $len[ 'max' ] ) . '"';
1696 $html .= empty( $len[ 'warn' ] ) || $is_disabled ? '' : ' warnLength="' . esc_attr( $len[ 'warn' ] ) . '"';
1697 $html .= $this->get_placeholder_attrs( $type = 'textarea', $holder ) . '>' . esc_attr( $value ) . '</textarea>' . "\n";
1698 $html .= empty( $len[ 'max' ] ) || $is_disabled ? '' : '<div id="textarea_' . $input_id . '-text-len-wrapper"></div>' . "\n";
1699
1700 if ( ! empty( $len[ 'max' ] ) ) {
1701
1702 $html .= $this->get_script_text_len( 'textarea_' . $input_id );
1703 }
1704
1705 return $html;
1706 }
1707
1708 public function get_textarea_dep( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false, $dep_id = '' ) {
1709
1710 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name : $css_id );
1711
1712 $html = $this->get_textarea( $name, $css_class, $input_id, $len, $holder, $is_disabled );
1713
1714 if ( $dep_id ) { // Just in case.
1715
1716 $html .= $this->get_script_placeholder_dep( 'textarea#textarea_' . $input_id, 'textarea#textarea_' . $dep_id );
1717 }
1718
1719 return $html;
1720 }
1721
1722 public function get_button( $value, $css_class = '', $css_id = '', $url = '', $newtab = false, $is_disabled = false, $el_data = array() ) {
1723
1724 $input_class = SucomUtil::sanitize_css_class( $css_class );
1725 $input_id = SucomUtil::sanitize_css_id( $css_id );
1726
1727 if ( true === $newtab ) {
1728
1729 $on_click = ' onClick="window.open(\'' . SucomUtil::esc_url_encode( $url ) . '\', \'_blank\');"';
1730
1731 } else {
1732
1733 $on_click = ' onClick="window.location.href = \'' . SucomUtil::esc_url_encode( $url ) . '\';"';
1734 }
1735
1736 $el_attr = '';
1737
1738 if ( is_array( $el_data ) ) {
1739
1740 foreach ( $el_data as $data_key => $data_value ) {
1741
1742 $el_attr .= ' data-' . $data_key . '="' . esc_attr( $data_value ) . '"';
1743 }
1744
1745 } else $el_attr = $el_data;
1746
1747 $html = '<input type="button" ';
1748 $html .= $is_disabled ? ' disabled="disabled"' : '';
1749 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
1750 $html .= empty( $input_id ) ? '' : ' id="button_' . $input_id . '"'; // Already sanitized.
1751 $html .= empty( $url ) || $is_disabled ? '' : $on_click;
1752 $html .= empty( $el_attr ) ? '' : ' ' . trim( $el_attr );
1753 $html .= ' value="' . esc_attr( wp_kses( $value, array() ) ) . '"/>'; // KSES (Kses Strips Evil Scripts).
1754
1755 return $html;
1756 }
1757
1758 /*
1759 * MULTIPLE FIELDS METHODS:
1760 *
1761 * get_input_multi()
1762 * get_mixed_multi()
1763 * get_select_multi()
1764 * get_textarea_multi()
1765 */
1766 public function get_input_multi( $name, $css_class = '', $css_id = '', $show_max = 10, $show_first = 1, $is_disabled = false ) {
1767
1768 if ( empty( $name ) ) {
1769
1770 return; // Just in case.
1771 }
1772
1773 $html = '';
1774 $display = true;
1775 $one_more = false;
1776 $show_first = $show_first > $show_max ? $show_max : $show_first;
1777 $start_num = 0;
1778 $end_num = $show_max > 0 ? $show_max - 1 : 0;
1779
1780 foreach ( range( $start_num, $end_num, 1 ) as $key_num ) {
1781
1782 $display = $one_more || $key_num < $show_first ? true : false;
1783 $prev_num = $key_num > 0 ? $key_num - 1 : 0;
1784 $next_num = $key_num + 1;
1785 $disp_num = $key_num + 1;
1786
1787 $input_name = $name . '_' . $key_num;
1788 $input_class = $css_class . ( $this->get_options( $input_name . ':disabled' ) ? ' disabled' : '' );
1789 $input_class = SucomUtil::sanitize_css_class( $input_class );
1790 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $input_name : $css_id . '_' . $key_num );
1791 $input_id_prev = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $prev_num : $css_id . '_' . $prev_num );
1792 $input_id_next = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $next_num : $css_id . '_' . $next_num );
1793 $input_value = $this->in_options( $input_name ) ? $this->options[ $input_name ] : '';
1794
1795 if ( $is_disabled && $key_num >= $show_first && empty( $display ) ) {
1796
1797 continue;
1798 }
1799
1800 if ( $start_num === $key_num ) {
1801
1802 $el_attr = 'onFocus="jQuery(\'div#multi_' . $input_id_next . '\').show();"';
1803
1804 } else {
1805
1806 $el_attr = 'onFocus="if ( jQuery(\'input#text_' . $input_id_prev . '\').val().length )' .
1807 ' { jQuery(\'div#multi_' . $input_id_next . '\').show(); } else' .
1808 ' if ( ! jQuery(\'input#textarea_' . $input_id . '\').val().length )' .
1809 ' { jQuery(\'input#text_' . $input_id_prev . '\').focus(); }"';
1810 }
1811
1812 $html .= '<div';
1813 $html .= ' class="multi_container input_multi"';
1814 $html .= ' id="multi_' . $input_id . '"';
1815 $html .= $display || '' !== $input_value ? '' : ' style="display:none;"';
1816 $html .= '>' . "\n";
1817 $html .= '<div class="multi_number">' . $disp_num . '.</div>' . "\n";
1818 $html .= '<div class="multi_input">' . "\n";
1819 $html .= '<div class="multi_input_el">' . "\n"; // Container for each input field.
1820 $html .= '<input type="text"';
1821 $html .= $is_disabled ? '' : ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"';
1822 $html .= $is_disabled ? ' disabled="disabled"' : '';
1823 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
1824 $html .= $input_id ? ' id="text_' . $input_id . '"' : ''; // Already sanitized.
1825 $html .= ' value="' . esc_attr( $input_value ) . '"';
1826 $html .= ' ' . $el_attr . '/>' . "\n";
1827 $html .= '</div><!-- .multi_input_el -->' . "\n";
1828 $html .= '</div><!-- .multi_input -->' . "\n";
1829 $html .= '</div><!-- .multi_container.input_multi -->' . "\n";
1830
1831 $one_more = empty( $input_value ) && ! is_numeric( $input_value ) ? false : true; // Allow for 0.
1832 }
1833
1834 return $html;
1835 }
1836
1837 public function get_mixed_multi( $mixed, $css_class, $css_id, $show_max = 5, $show_first = 1, $is_disabled = false ) {
1838
1839 if ( empty( $mixed ) ) {
1840
1841 return; // Just in case.
1842 }
1843
1844 $html = '';
1845 $display = true;
1846 $one_more = false;
1847 $show_first = $show_first > $show_max ? $show_max : $show_first;
1848 $start_num = 0;
1849 $end_num = $show_max > 0 ? $show_max - 1 : 0;
1850
1851 foreach ( range( $start_num, $end_num, 1 ) as $key_num ) {
1852
1853 $display = $one_more || $key_num < $show_first ? true : false;
1854 $prev_num = $key_num > 0 ? $key_num - 1 : 0;
1855 $next_num = $key_num + 1;
1856
1857 $multi_class = trim( 'multi_container mixed_multi ' . $css_class );
1858 $multi_id = $css_id . '_' . $key_num;
1859 $multi_id_prev = $css_id . '_' . $prev_num;
1860 $multi_id_next = $css_id . '_' . $next_num;
1861
1862 $el_attr = 'onFocus="jQuery(\'div#multi_' . esc_attr( $multi_id_next ) . '\').show();"';
1863
1864 $html .= '<div class="' . $multi_class . '" id="multi_' . esc_attr( $multi_id ) . '"'; // .multi_container.mixed_multi.
1865 $html .= $display ? '' : ' style="display:none;"';
1866 $html .= '>' . "\n";
1867 $html .= '<div class="multi_number">' . ( $key_num + 1 ) . '.</div>' . "\n";
1868 $html .= '<div class="multi_input">' . "\n";
1869
1870 $one_more = false; // Return to default.
1871
1872 $multi_label_num = 0;
1873
1874 foreach ( $mixed as $name => $atts ) {
1875
1876 $input_name = $name . '_' . $key_num;
1877 $input_title = empty( $atts[ 'input_title' ] ) ? '' : $atts[ 'input_title' ];
1878 $input_class = empty( $atts[ 'input_class' ] ) ? '' : $atts[ 'input_class' ];
1879 $container_class = SucomUtil::sanitize_css_class( $input_class );
1880 $input_class .= $this->get_options( $input_name . ':disabled' ) ? ' disabled' : '';
1881 $input_class = SucomUtil::sanitize_css_class( $input_class );
1882 $input_id = empty( $atts[ 'input_id' ] ) ? $input_name : $atts[ 'input_id' ] . '_' . $key_num;
1883 $input_id = SucomUtil::sanitize_css_id( $input_id );
1884 $input_content = empty( $atts[ 'input_content' ] ) ? '' : $atts[ 'input_content' ];
1885 $input_values = empty( $atts[ 'input_values' ] ) ? array() : $atts[ 'input_values' ];
1886 $in_options = $this->in_options( $input_name ); // Optimize and call only once.
1887 $in_defaults = $this->in_defaults( $input_name ); // Optimize and call only once.
1888
1889 if ( ! empty( $atts[ 'event_names' ] ) ) {
1890
1891 if ( is_array( $atts[ 'event_names' ] ) ) {
1892
1893 $event_names = $atts[ 'event_names' ];
1894
1895 } elseif ( is_string( $atts[ 'event_names' ] ) ) {
1896
1897 $event_names = array( $atts[ 'event_names' ] );
1898
1899 } elseif ( ! is_array( $event_names ) ) { // Ignore true, false, null, etc.
1900
1901 $event_names = array();
1902 }
1903
1904 } else {
1905
1906 $event_names = array();
1907 }
1908
1909 $event_args = empty( $atts[ 'event_args' ] ) ? array() : $atts[ 'event_args' ];
1910
1911 if ( isset( $atts[ 'placeholder' ] ) ) {
1912
1913 $holder = $this->get_placeholder_sanitized( $input_name, $atts[ 'placeholder' ] );
1914
1915 } else $holder = '';
1916
1917 if ( $is_disabled && $key_num >= $show_first && empty( $display ) ) {
1918
1919 continue;
1920 }
1921
1922 $html .= '<div class="multi_input_el">' . "\n";
1923
1924 /*
1925 * Default paragraph display is an inline-block.
1926 */
1927 if ( ! empty( $atts[ 'input_label' ] ) ) {
1928
1929 $multi_label_num++;
1930
1931 $html .= '<div class="multi_input_label ' . $container_class . ( 1 === $multi_label_num ? ' first_label' : '' ) . '">';
1932 $html .= $atts[ 'input_label' ] . ':';
1933 $html .= '</div>' . "\n";
1934 }
1935
1936 if ( isset( $atts[ 'input_type' ] ) ) {
1937
1938 switch ( $atts[ 'input_type' ] ) {
1939
1940 case 'image':
1941
1942 $html .= '<div tabindex="-1" ' . $el_attr . ' style="display:inline-block;">' . "\n";
1943 $html .= $this->get_input_image_upload( $input_name, $holder, $is_disabled, $el_attr );
1944 $html .= '</div>'. "\n";
1945
1946 break;
1947
1948 case 'radio':
1949
1950 $radio_inputs = array();
1951
1952 foreach ( $input_values as $input_value ) {
1953
1954 if ( $in_options ) {
1955
1956 $input_checked = checked( $this->options[ $input_name ], $input_value, false );
1957
1958 } elseif ( isset( $atts[ 'input_default' ] ) ) {
1959
1960 $input_checked = checked( $atts[ 'input_default' ], $input_value, false );
1961
1962 } elseif ( $in_defaults ) {
1963
1964 $input_checked = checked( $this->defaults[ $input_name ], $input_value, false );
1965
1966 } else $input_checked = '';
1967
1968 $radio_inputs[] = '<span class="sucom-radio"><input type="radio"' .
1969 ( $is_disabled ? ' disabled="disabled"' :
1970 ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"' .
1971 ' class="' . $input_class . '"' . // Already sanitized.
1972 ' value="' . esc_attr( $input_value ) . '"' ) .
1973 $input_checked . '/></span>';
1974 }
1975
1976 if ( ! empty( $radio_inputs ) ) {
1977
1978 $html .= '<div';
1979 $html .= ' class="' . $container_class . '"'; // Already sanitized.
1980 $html .= ' id="' . $input_id . '"'; // Already sanitized.
1981 $html .= ' ' . $el_attr . '>';
1982 $html .= vsprintf( $atts[ 'input_content' ], $radio_inputs );
1983 $html .= '</div>' . "\n";
1984 }
1985
1986 break;
1987
1988 case 'select':
1989
1990 $select_options = empty( $atts[ 'select_options' ] ) ||
1991 ! is_array( $atts[ 'select_options' ] ) ?
1992 array() : $atts[ 'select_options' ];
1993
1994 $select_selected = empty( $atts[ 'select_selected' ] ) ? null : $atts[ 'select_selected' ];
1995 $select_default = empty( $atts[ 'select_default' ] ) ? null : $atts[ 'select_default' ];
1996
1997 $event_json_var = false;
1998
1999 if ( in_array( 'on_focus_load_json', $event_names ) ) {
2000
2001 $event_json_var = $this->plugin_id . '_select';
2002
2003 if ( $event_args && is_string( $event_args ) ) {
2004
2005 $event_json_var .= '_' . $event_args;
2006
2007 } elseif ( ! empty( $event_args[ 'json_var' ] ) ) {
2008
2009 $event_json_var = '_' . $event_args[ 'json_var' ];
2010 }
2011
2012 $event_json_var .= '_' . md5( serialize( $select_options ) );
2013
2014 $event_json_var = SucomUtil::sanitize_hookname( $event_json_var );
2015 }
2016
2017 $select_opt_count = 0; // Used to check for first option.
2018 $select_opt_added = 0;
2019 $select_opt_arr = array();
2020 $select_json_arr = array();
2021 $default_value = '';
2022 $default_text = '';
2023 $select_options = self::maybe_transl_sort_values( $input_name,
2024 $select_options, $is_assoc = null, $event_args );
2025
2026 foreach ( $select_options as $option_value => $label_transl ) {
2027
2028 if ( is_array( $label_transl ) ) { // Just in case.
2029
2030 $label_transl = implode( $glue = ', ', $label_transl );
2031 }
2032
2033 /*
2034 * Save the option value and translated label for the JSON
2035 * array before adding the "(default)" suffix.
2036 */
2037 if ( $event_json_var ) {
2038
2039 if ( empty( $this->json_array_added[ $event_json_var ] ) ) {
2040
2041 $select_json_arr[ $option_value ] = $label_transl;
2042 }
2043 }
2044
2045 /*
2046 * Save the default value and its text so we can add them (as jquery data) to the select.
2047 */
2048 if ( ( $in_defaults && (string) $option_value === (string) $this->defaults[ $input_name ] ) ||
2049 ( null !== $select_default && $option_value === $select_default ) ) {
2050
2051 $default_value = $option_value;
2052 $default_text = $this->get_option_value_transl( '(default)' );
2053 $label_transl .= ' ' . $default_text;
2054 }
2055
2056 /*
2057 * Maybe get a selected="selected" string for this option.
2058 */
2059 if ( $select_selected !== null ) {
2060
2061 $is_selected_html = selected( $select_selected, $option_value, false );
2062
2063 } elseif ( $in_options ) {
2064
2065 $is_selected_html = selected( $this->options[ $input_name ], $option_value, false );
2066
2067 } elseif ( $select_default !== null ) {
2068
2069 $is_selected_html = selected( $select_default, $option_value, false );
2070
2071 } elseif ( $in_defaults ) {
2072
2073 $is_selected_html = selected( $this->defaults[ $input_name ], $option_value, false );
2074
2075 } else $is_selected_html = '';
2076
2077 /*
2078 * If the selected value is the default, add the default class.
2079 */
2080 if ( $is_selected_html && $in_defaults && $option_value === $this->defaults[ $input_name ] ) {
2081
2082 $input_class .= ' default';
2083 }
2084
2085 $select_opt_count++; // Used to check for first option.
2086
2087 /*
2088 * For disabled selects, only include the first and/or selected option.
2089 */
2090 if ( ( ! $is_disabled && ! $event_json_var ) || $is_selected_html || $select_opt_count === 1 ) {
2091
2092 if ( ! isset( $select_opt_arr[ $option_value ] ) ) {
2093
2094 $select_opt_arr[ $option_value ] = '<option value="' .
2095 esc_attr( $option_value ) . '"' . $is_selected_html . '>' .
2096 $label_transl . '</option>';
2097
2098 $select_opt_added++;
2099 }
2100 }
2101 }
2102
2103 $html .= "\n" . '<select ';
2104 $html .= $is_disabled ? ' disabled="disabled"' : '';
2105 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
2106 $html .= $input_id ? ' id="select_' . $input_id . '"' : ''; // Already sanitized.
2107 $html .= ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"';
2108 $html .= ' title="' . esc_attr( $input_title ) . '"';
2109 $html .= ' data-default-value="' . esc_attr( $default_value ) . '"';
2110 $html .= ' data-default-text="' . esc_attr( $default_text ) . '"';
2111 $html .= ' ' . $el_attr . '>' . "\n";
2112 $html .= implode( $glue = "\n", $select_opt_arr );
2113 $html .= '<!-- ' . $select_opt_added . ' select options added -->' . "\n";
2114 $html .= '</select>' . "\n";
2115
2116 foreach ( $event_names as $event_name ) {
2117
2118 $html .= '<!-- event name: ' . $event_name . ' -->' . "\n";
2119
2120 switch ( $event_name ) {
2121
2122 case 'on_focus_load_json':
2123
2124 $html .= $this->get_script_load_json( $event_json_var, $event_args,
2125 $select_json_arr, 'select_' . $input_id );
2126
2127 break;
2128 }
2129 }
2130
2131 break;
2132
2133 case 'text':
2134
2135 $input_value = $in_options ? $this->options[ $input_name ] : '';
2136
2137 $html .= '<input type="text"';
2138 $html .= $is_disabled ? ' disabled="disabled"' : '';
2139 $html .= ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"';
2140 $html .= ' title="' . esc_attr( $input_title ) . '"';
2141 $html .= ' class="' . $input_class . '"'; // Already sanitized.
2142 $html .= ' id="text_' . $input_id . '"'; // Already sanitized.
2143 $html .= ' value="' . esc_attr( $input_value ) . '"';
2144 $html .= ' ' . $el_attr . '/>' . "\n";
2145
2146 if ( $input_value || is_numeric( $input_value ) ) {
2147
2148 $one_more = true;
2149 }
2150
2151 break;
2152
2153 case 'textarea':
2154
2155 $input_value = $in_options ? $this->options[ $input_name ] : '';
2156
2157 $html .= '<textarea';
2158 $html .= $is_disabled ? ' disabled="disabled"' : '';
2159 $html .= ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"';
2160 $html .= ' title="' . esc_attr( $input_title ) . '"';
2161 $html .= ' class="' . $input_class . '"'; // Already sanitized.
2162 $html .= ' id="textarea_' . $input_id . '"'; // Already sanitized.
2163 $html .= $this->get_placeholder_attrs( $type = 'textarea', $holder );
2164 $html .= ' ' . $el_attr . '>' . esc_attr( $input_value );
2165 $html .= '</textarea>' . "\n";
2166
2167 if ( $input_value || is_numeric( $input_value ) ) {
2168
2169 $one_more = true;
2170 }
2171
2172 break;
2173 }
2174 }
2175
2176 $html .= '</div><!-- .multi_input_el -->' . "\n";
2177 }
2178
2179 $html .= '</div><!-- .multi_input -->' . "\n";
2180 $html .= '</div><!-- .multi_container.mixed_multi -->' . "\n";
2181 }
2182
2183 return $html;
2184 }
2185
2186 /*
2187 * $is_disabled can be true, false, or a text string (ie. "WPSSO PLM required").
2188 */
2189 public function get_select_multi( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null,
2190 $show_max = 5, $show_first = 1, $is_disabled = false, $event_names = array(), $event_args = array() ) {
2191
2192 if ( empty( $name ) ) {
2193
2194 return; // Just in case.
2195 }
2196
2197 $html = '';
2198 $display = true;
2199 $one_more = false;
2200 $show_first = $show_first > $show_max ? $show_max : $show_first;
2201 $start_num = 0;
2202 $end_num = $show_max > 0 ? $show_max - 1 : 0;
2203
2204 $event_names[] = 'on_focus_show';
2205
2206 foreach ( range( $start_num, $end_num, 1 ) as $key_num ) {
2207
2208 $display = $one_more || $key_num < $show_first ? true : false;
2209 $prev_num = $key_num > 0 ? $key_num - 1 : 0;
2210 $next_num = $key_num + 1;
2211 $disp_num = $key_num + 1;
2212
2213 $input_name = $name . '_' . $key_num;
2214 $input_class = empty( $css_class ) ? '' : SucomUtil::sanitize_css_class( $css_class );
2215 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $input_name : $css_id . '_' . $key_num );
2216 $input_id_prev = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $prev_num : $css_id . '_' . $prev_num );
2217 $input_id_next = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $next_num : $css_id . '_' . $next_num );
2218 $input_value = $this->in_options( $input_name ) ? $this->options[ $input_name ] : false;
2219
2220 if ( $is_disabled && $key_num >= $show_first && empty( $display ) ) {
2221
2222 continue;
2223 }
2224
2225 $event_args[ 'show_id' ] = 'div#multi_' . $input_id_next;
2226
2227 $html .= '<div class="multi_container select_multi" id="multi_' . $input_id . '"';
2228 $html .= $display ? '' : ' style="display:none;"';
2229 $html .= '>' . "\n";
2230 $html .= '<div class="multi_number">' . $disp_num . '.</div>' . "\n";
2231 $html .= '<div class="multi_input">' . "\n";
2232 $html .= '<div class="multi_input_el">' . "\n"; // Container for each input field.
2233
2234 /*
2235 * $is_disabled can be true, false, or an option value for the disabled select.
2236 */
2237 $html .= $this->get_select( $input_name, $values, $input_class, $input_id, $is_assoc,
2238 $is_disabled, $input_value, $event_names, $event_args );
2239
2240 $html .= is_string( $is_disabled ) ? $is_disabled : ''; // Allow comment.
2241
2242 $html .= '</div><!-- .multi_input_el -->' . "\n";
2243 $html .= '</div><!-- .multi_input -->' . "\n";
2244 $html .= '</div><!-- .multi_container.select_multi -->' . "\n";
2245
2246 $one_more = 'none' === $input_value || ( empty( $input_value ) && ! is_numeric( $input_value ) ) ? false : true; // Allow for 0.
2247 }
2248
2249 return $html;
2250 }
2251
2252 public function get_textarea_multi( $name, $css_class = '', $css_id = '', $len = 0, $show_max = 5, $show_first = 1, $is_disabled = false ) {
2253
2254 if ( empty( $name ) ) {
2255
2256 return; // Just in case.
2257 }
2258
2259 $html = '';
2260 $display = true;
2261 $one_more = false;
2262 $show_first = $show_first > $show_max ? $show_max : $show_first;
2263 $start_num = 0;
2264 $end_num = $show_max > 0 ? $show_max - 1 : 0;
2265
2266 foreach ( range( $start_num, $end_num, 1 ) as $key_num ) {
2267
2268 $display = $one_more || $key_num < $show_first ? true : false;
2269 $prev_num = $key_num > 0 ? $key_num - 1 : 0;
2270 $next_num = $key_num + 1;
2271 $disp_num = $key_num + 1;
2272
2273 $input_name = $name . '_' . $key_num;
2274 $input_class = empty( $css_class ) ? '' : SucomUtil::sanitize_css_class( $css_class );
2275 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? $input_name : $css_id . '_' . $key_num );
2276 $input_id_prev = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $prev_num : $css_id . '_' . $prev_num );
2277 $input_id_next = SucomUtil::sanitize_css_id( empty( $css_id ) ? $name . '_' . $next_num : $css_id . '_' . $next_num );
2278 $input_value = $this->in_options( $input_name ) ? $this->options[ $input_name ] : '';
2279
2280 if ( $is_disabled && $key_num >= $show_first && empty( $display ) ) {
2281
2282 continue;
2283 }
2284
2285 if ( $start_num === $key_num ) {
2286
2287 $el_attr = 'onFocus="jQuery(\'div#multi_' . $input_id_next . '\').show();"';
2288
2289 } else {
2290
2291 $el_attr = 'onFocus="if ( jQuery(\'textarea#textarea_' . $input_id_prev . '\').val().length )' .
2292 ' { jQuery(\'div#multi_' . $input_id_next . '\').show(); } else' .
2293 ' if ( ! jQuery(\'textarea#textarea_' . $input_id . '\').val().length )' .
2294 ' { jQuery(\'textarea#textarea_' . $input_id_prev . '\').focus(); }"';
2295 }
2296
2297 $html .= '<div';
2298 $html .= ' class="multi_container textarea_multi"';
2299 $html .= ' id="multi_' . $input_id . '"';
2300 $html .= $display || '' !== $input_value ? '' : ' style="display:none;"';
2301 $html .= '>' . "\n";
2302 $html .= '<div class="multi_number">' . $disp_num . '.</div>' . "\n";
2303 $html .= '<div class="multi_input">' . "\n";
2304 $html .= '<div class="multi_input_el">' . "\n"; // Container for each input field.
2305 $html .= '<textarea';
2306 $html .= $is_disabled ? ' disabled="disabled"' : '';
2307 $html .= ' name="' . esc_attr( $this->opts_name . '[' . $input_name . ']' ) . '"';
2308 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
2309 $html .= $input_id ? ' id="textarea_' . $input_id . '"' : ''; // Already sanitized.
2310 $html .= ' ' . $el_attr . '>' . esc_attr( $input_value );
2311 $html .= '</textarea>' . "\n";
2312 $html .= '</div><!-- .multi_input_el -->' . "\n";
2313 $html .= '</div><!-- .multi_input -->' . "\n";
2314 $html .= '</div><!-- .multi_container.textarea_multi -->' . "\n";
2315
2316 $one_more = empty( $input_value ) && ! is_numeric( $input_value ) ? false : true; // Allow for 0.
2317 }
2318
2319 return $html;
2320 }
2321
2322 /*
2323 * AUTOMATICALLY LOCALIZED METHODS:
2324 *
2325 * get_options_locale()
2326 * get_defaults_locale()
2327 * get_input_locale()
2328 * get_input_image_upload_locale()
2329 * get_input_image_url_locale()
2330 * get_input_video_url_locale()
2331 * get_select_locale()
2332 * get_textarea_locale()
2333 * get_th_html_locale()
2334 */
2335 public function get_options_locale( $opt_key = false, $def_val = null ) {
2336
2337 if ( false !== $opt_key ) {
2338
2339 if ( null === $def_val ) {
2340
2341 /*
2342 * Returns an option value or null.
2343 *
2344 * Note that for non-existing keys, or empty strings, this method will return the default non-localized value.
2345 */
2346 return SucomUtilOptions::get_key_value( $opt_key, $this->options, $mixed = 'current' );
2347 }
2348 }
2349
2350 return $this->get_options( $opt_key, $def_val );
2351 }
2352
2353 public function get_defaults_locale( $opt_key = false ) {
2354
2355 if ( false !== $opt_key ) {
2356
2357 /*
2358 * Returns an option value or null.
2359 *
2360 * Note that for non-existing keys, or empty strings, this method will return the default non-localized value.
2361 */
2362 return SucomUtilOptions::get_key_value( $opt_key, $this->defaults, $mixed = 'current' );
2363 }
2364
2365 return $this->defaults;
2366 }
2367
2368 public function get_input_locale( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false ) {
2369
2370 $name = SucomUtilOptions::get_key_locale( $name, $this->options );
2371
2372 return $this->get_input( $name, $css_class, $css_id, $len, $holder, $is_disabled );
2373 }
2374
2375 public function get_input_image_upload_locale( $name_prefix, $holder = '', $is_disabled = false, $el_attr = '' ) {
2376
2377 $name_prefix = SucomUtilOptions::get_key_locale( $name_prefix, $this->options );
2378
2379 return $this->get_input_image_upload( $name_prefix, $holder = '', $is_disabled = false, $el_attr = '' );
2380 }
2381
2382 public function get_input_image_url_locale( $name_prefix, $url = '', $is_disabled = false ) {
2383
2384 $name_prefix = SucomUtilOptions::get_key_locale( $name_prefix, $this->options );
2385
2386 return $this->get_input_image_url( $name_prefix, $url, $is_disabled );
2387 }
2388
2389 public function get_input_video_url_locale( $name_prefix, $url = '', $is_disabled = false ) {
2390
2391 $name_prefix = SucomUtilOptions::get_key_locale( $name_prefix, $this->options );
2392
2393 return $this->get_input_video_url( $name_prefix, $primary_suffix = 'embed', $url, $is_disabled );
2394 }
2395
2396 public function get_select_locale( $name, $values = array(), $css_class = '', $css_id = '',
2397 $is_assoc = null, $is_disabled = false, $selected = false, $event_names = array(), $event_args = null ) {
2398
2399 $name = SucomUtilOptions::get_key_locale( $name, $this->options );
2400
2401 return $this->get_select( $name, $values, $css_class, $css_id, $is_assoc, $is_disabled, $selected, $event_names, $event_args );
2402 }
2403
2404 public function get_textarea_locale( $name, $css_class = '', $css_id = '', $len = 0, $holder = '', $is_disabled = false ) {
2405
2406 $name = SucomUtilOptions::get_key_locale( $name, $this->options );
2407
2408 return $this->get_textarea( $name, $css_class, $css_id, $len, $holder, $is_disabled );
2409 }
2410
2411 public function get_th_html_locale( $label = '', $css_class = '', $css_id = '', $atts = array() ) {
2412
2413 $atts[ 'is_locale' ] = true;
2414
2415 return $this->get_th_html( $label, $css_class, $css_id, $atts );
2416 }
2417
2418 /*
2419 * AUTOMATICALLY DISABLED METHODS:
2420 *
2421 * get_no_td_checkbox()
2422 * get_no_checkbox()
2423 * get_no_checkbox_options()
2424 * get_no_checkbox_comment()
2425 * get_no_checklist()
2426 * get_no_checklist_post_types()
2427 * get_no_checklist_post_tax_user()
2428 * get_no_columns_post_tax_user()
2429 * get_no_date_time_timezone()
2430 * get_no_date_time_tz()
2431 * get_no_input()
2432 * get_no_input_clipboard()
2433 * get_no_input_options()
2434 * get_no_input_holder()
2435 * get_no_input_date()
2436 * get_no_input_date_options()
2437 * get_no_input_time_dhms()
2438 * get_no_input_image_crop_area()
2439 * get_no_input_image_dimensions()
2440 * get_no_input_image_upload()
2441 * get_no_input_video_dimensions()
2442 * get_no_input_value()
2443 * get_no_radio()
2444 * get_no_select()
2445 * get_no_select_country()
2446 * get_no_select_country_options()
2447 * get_no_select_none()
2448 * get_no_select_options()
2449 * get_no_select_time()
2450 * get_no_select_time_none()
2451 * get_no_select_time_options()
2452 * get_no_select_time_options_none()
2453 * get_no_select_timezone()
2454 * get_no_textarea()
2455 * get_no_textarea_options()
2456 * get_no_textarea_value()
2457 *
2458 */
2459 public function get_no_td_checkbox( $name, $comment = '', $extra_css_class = '' ) {
2460
2461 return '<td class="blank ' . $extra_css_class . '">' . $this->get_no_checkbox_comment( $name, $comment ) . '</td>';
2462 }
2463
2464 public function get_no_checkbox( $name, $css_class = '', $css_id = '', $force = null, $group = null ) {
2465
2466 return $this->get_checkbox( $name, $css_class, $css_id, $is_disabled = true, $force, $group );
2467 }
2468
2469 public function get_no_checkbox_options( $name, array $opts, $css_class = '', $css_id = '', $group = null ) {
2470
2471 $force = empty( $opts[ $name ] ) ? 0 : 1;
2472
2473 return $this->get_checkbox( $name, $css_class, $css_id, $is_disabled = true, $force, $group );
2474 }
2475
2476 public function get_no_checkbox_comment( $name, $comment = '' ) {
2477
2478 return $this->get_checkbox( $name, $css_class = '', $css_id = '', $is_disabled = true ) . ( empty( $comment ) ? '' : ' ' . $comment );
2479 }
2480
2481 public function get_no_checklist( $name_prefix, $values = array(), $css_class = 'column-list', $css_id = '', $is_assoc = null ) {
2482
2483 return $this->get_checklist( $name_prefix, $values, $css_class, $css_id, $is_assoc, $is_disabled = true );
2484 }
2485
2486 public function get_no_checklist_post_types( $name_prefix, $css_class = 'column-list', $css_id = '' ) {
2487
2488 return $this->get_checklist_post_types( $name_prefix, $css_class, $css_id, $is_disabled = true );
2489 }
2490
2491 public function get_no_checklist_post_tax_user( $name_prefix, $css_class = 'column-list', $css_id = '' ) {
2492
2493 return $this->get_checklist_post_tax_user( $name_prefix, $css_class, $css_id, $is_disabled = true );
2494 }
2495
2496 public function get_no_columns_post_tax_user( $name_prefix, $css_class = 'column-list', $css_id = '' ) {
2497
2498 return $this->get_columns_post_tax_user( $name_prefix, $css_class, $css_id, $is_disabled = true );
2499 }
2500
2501 public function get_no_date_time_timezone( $name_prefix = '' ) {
2502
2503 return $this->get_date_time_timezone( $name_prefix, $media_info = array(), $is_disabled = true );
2504 }
2505
2506 /*
2507 * Deprecated on 2024/08/09.
2508 */
2509 public function get_no_date_time_tz( $name_prefix = '' ) {
2510
2511 return $this->get_date_time_timezone( $name_prefix, $media_info = array(), $is_disabled = true );
2512 }
2513
2514 public function get_no_input( $name = '', $css_class = '', $css_id = '', $holder = '' ) {
2515
2516 $html = '';
2517 $value = $this->in_options( $name ) ? $this->options[ $name ] : '';
2518 $holder = $this->get_placeholder_sanitized( $name, $holder );
2519
2520 if ( ! empty( $name ) ) {
2521
2522 $html .= $this->get_hidden( $name );
2523 }
2524
2525 $html .= $this->get_no_input_value( $value, $css_class, $css_id, $holder );
2526
2527 return $html;
2528 }
2529
2530 public function get_no_input_clipboard( $value, $css_class = 'wide', $css_id = '' ) {
2531
2532 if ( empty( $css_id ) ) { // Make sure we have an ID string.
2533
2534 $css_id = uniqid();
2535 }
2536
2537 $input_class = SucomUtil::sanitize_css_class( $css_class );
2538 $input_id = SucomUtil::sanitize_css_id( $css_id );
2539
2540 $input_text = '<input type="text"';
2541 $input_text .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
2542 $input_text .= empty( $input_id ) ? '' : ' id="text_' . $input_id . '"'; // Already sanitized.
2543 $input_text .= ' value="' . esc_attr( $value ) . '" readonly';
2544 $input_text .= ' onFocus="this.select();"';
2545 $input_text .= ' onMouseUp="return false;"/>';
2546
2547 /*
2548 * Add a dashicons copy-to-clipboard button to the input text field.
2549 */
2550 if ( ! empty( $input_id ) ) { // Just in case.
2551
2552 $html = '<div class="no_input_clipboard">';
2553 $html .= '<div class="copy_button"><a href="" onClick="return sucomCopyById( \'text_' . $input_id . '\', \'' . $this->admin_l10n . '\' );">';
2554 $html .= '<span class="dashicons dashicons-clipboard"></span>';
2555 $html .= '</a></div><!-- .copy_button -->' . "\n";
2556 $html .= '<div class="copy_text">' . $input_text . '</div><!-- .copy_text -->' . "\n";
2557 $html .= '</div><!-- .no_input_clipboard -->' . "\n";
2558
2559 } else {
2560
2561 $html = $input_text;
2562 }
2563
2564 return $html;
2565 }
2566
2567 public function get_no_input_options( $name, array $opts, $css_class = '', $css_id = '', $holder = '' ) {
2568
2569 $value = isset( $opts[ $name ] ) ? $opts[ $name ] : '';
2570
2571 return $this->get_no_input_value( $value, $css_class, $css_id, $holder );
2572 }
2573
2574 public function get_no_input_holder( $holder = '', $css_class = '', $css_id = '' ) {
2575
2576 return $this->get_no_input_value( $value = '', $css_class, $css_id, $holder );
2577 }
2578
2579 public function get_no_input_date( $name = '' ) {
2580
2581 return $this->get_input_date( $name, $css_class = '', $css_id = '', $holder = '', $is_disabled = true );
2582 }
2583
2584 public function get_no_input_date_options( $name, $opts ) {
2585
2586 $value = isset( $opts[ $name ] ) ? $opts[ $name ] : '';
2587
2588 return $this->get_no_input_value( $value, 'datepicker', '', 'yyyy-mm-dd' );
2589 }
2590
2591 public function get_no_input_time_dhms() {
2592
2593 static $days_sep = null;
2594 static $hours_sep = null;
2595 static $mins_sep = null;
2596 static $secs_sep = null;
2597
2598 if ( null === $days_sep ) { // Translate only once.
2599
2600 $days_sep = ' ' . _x( 'days', 'option comment', 'wpsso' ) . ', ';
2601 $hours_sep = ' ' . _x( 'hours', 'option comment', 'wpsso' ) . ', ';
2602 $mins_sep = ' ' . _x( 'mins', 'option comment', 'wpsso' ) . ', ';
2603 $secs_sep = ' ' . _x( 'secs', 'option comment', 'wpsso' );
2604 }
2605
2606 return $this->get_no_input_value( $value = '0', $css_class = 'xshort' ) . $days_sep .
2607 $this->get_no_input_value( $value = '0', $css_class = 'xshort' ) . $hours_sep .
2608 $this->get_no_input_value( $value = '0', $css_class = 'xshort' ) . $mins_sep .
2609 $this->get_no_input_value( $value = '0', $css_class = 'xshort' ) . $secs_sep;
2610 }
2611
2612 public function get_no_input_image_crop_area( $name, $add_none = false ) {
2613
2614 return $this->get_input_image_crop_area( $name, $add_none = false, $is_disabled = true );
2615 }
2616
2617 public function get_no_input_image_dimensions( $name ) {
2618
2619 return $this->get_input_image_dimensions( $name, $is_disabled = true );
2620 }
2621
2622 public function get_no_input_image_upload( $name_prefix, $holder = '' ) {
2623
2624 return $this->get_input_image_upload( $name_prefix, $holder, $is_disabled = true );
2625 }
2626
2627 public function get_no_input_video_dimensions( $name, $media_info = array() ) {
2628
2629 return $this->get_input_video_dimensions( $name, $media_info, $is_disabled = true );
2630 }
2631
2632 public function get_no_input_value( $value = '', $css_class = '', $css_id = '', $holder = '', $show_max = 1 ) {
2633
2634 $html = '';
2635 $input_class = SucomUtil::sanitize_css_class( $css_class );
2636 $holder = $this->get_placeholder_sanitized( $name = '', $holder );
2637 $end_num = $show_max > 0 ? $show_max - 1 : 0;
2638
2639 foreach ( range( 0, $end_num, 1 ) as $key_num ) {
2640
2641 if ( $show_max > 1 ) {
2642
2643 $input_id = SucomUtil::sanitize_css_id( empty( $css_id ) ? '' : $css_id . '_' . $key_num );
2644
2645 $html .= '<div class="multi_container">' . "\n";
2646 $html .= '<div class="multi_number">' . ( $key_num + 1 ) . '.</div>' . "\n";
2647 $html .= '<div class="multi_input">' . "\n";
2648 $html .= '<div class="multi_input_el">' . "\n"; // Container for each input field.
2649 }
2650
2651 $html .= '<input type="text" disabled="disabled"';
2652 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
2653 $html .= empty( $input_id ) ? '' : ' id="text_' . $input_id . '"'; // Already sanitized.
2654
2655 /*
2656 * Only show a placeholder and value for input field 0.
2657 */
2658 if ( ! $key_num ) {
2659
2660 if ( '' !== $holder ) {
2661
2662 $html .= ' placeholder="' . esc_attr( $holder ) . '"';
2663 }
2664
2665 $html .= ' value="' . esc_attr( $value ) . '"';
2666 }
2667
2668 $html .= '/>' . "\n";
2669
2670 if ( $show_max > 1 ) {
2671
2672 $html .= '</div><!-- .multi_input_el -->' . "\n";
2673 $html .= '</div><!-- .multi_input -->' . "\n";
2674 $html .= '</div><!-- .multi_container -->' . "\n";
2675 }
2676 }
2677
2678 return $html;
2679 }
2680
2681 public function get_no_radio( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null ) {
2682
2683 return $this->get_radio( $name, $values, $css_class, $css_id, $is_assoc, $is_disabled = true );
2684 }
2685
2686 public function get_no_select( $name, $values = array(), $css_class = '', $css_id = '',
2687 $is_assoc = null, $selected = false, $event_names = array(), $event_args = array() ) {
2688
2689 return $this->get_select( $name, $values, $css_class, $css_id,
2690 $is_assoc, $is_disabled = true, $selected, $event_names, $event_args );
2691 }
2692
2693 public function get_no_select_country( $name, $css_class = '', $css_id = '', $selected = false ) {
2694
2695 return $this->get_select_country( $name, $css_class, $css_id, $is_disabled = true, $selected );
2696 }
2697
2698 public function get_no_select_country_options( $name, array $opts, $css_class = '', $css_id = '' ) {
2699
2700 $selected = isset( $opts[ $name ] ) ? $opts[ $name ] : false;
2701
2702 return $this->get_select_country( $name, $css_class, $css_id, $is_disabled = true, $selected );
2703 }
2704
2705 public function get_no_select_none( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null,
2706 $selected = false, $event_names = array() ) {
2707
2708 return $this->get_select_none( $name, $values, $css_class, $css_id, $is_assoc,
2709 $is_disabled = true, $selected, $event_names );
2710 }
2711
2712 public function get_no_select_options( $name, array $opts, $values = array(), $css_class = '', $css_id = '',
2713 $is_assoc = null, $event_names = array(), $event_args = array() ) {
2714
2715 $selected = isset( $opts[ $name ] ) ? $opts[ $name ] : true;
2716
2717 return $this->get_select( $name, $values, $css_class, $css_id,
2718 $is_assoc, $is_disabled = true, $selected, $event_names, $event_args );
2719 }
2720
2721 public function get_no_select_time( $name, $css_class = '', $css_id = '', $selected = false, $step_mins = 15, $add_none = false ) {
2722
2723 return $this->get_select_time( $name, $css_class, $css_id, $is_disabled = true, $selected, $step_mins, $add_none );
2724 }
2725
2726 public function get_no_select_time_none( $name, $css_class = '', $css_id = '', $selected = false, $step_mins = 15 ) {
2727
2728 /*
2729 * Set 'none' as the default if no default is defined.
2730 */
2731 if ( ! empty( $name ) ) {
2732
2733 if ( ! $this->in_defaults( $name ) ) {
2734
2735 $this->defaults[ $name ] = 'none';
2736 }
2737 }
2738
2739 return $this->get_select_time( $name, $css_class, $css_id, $is_disabled = true, $selected, $step_mins, $add_none = true );
2740 }
2741
2742 public function get_no_select_time_options( $name, array $opts, $css_class = '', $css_id = '', $step_mins = 15, $add_none = false ) {
2743
2744 $selected = isset( $opts[ $name ] ) ? $opts[ $name ] : true;
2745
2746 return $this->get_select_time( $name, $css_class, $css_id, $is_disabled = true, $selected, $step_mins, $add_none );
2747 }
2748
2749 public function get_no_select_time_options_none( $name, array $opts, $css_class = '', $css_id = '', $step_mins = 15 ) {
2750
2751 /*
2752 * Set 'none' as the default if no default is defined.
2753 */
2754 if ( ! empty( $name ) ) {
2755
2756 if ( ! $this->in_defaults( $name ) ) {
2757
2758 $this->defaults[ $name ] = 'none';
2759 }
2760 }
2761
2762 $selected = isset( $opts[ $name ] ) ? $opts[ $name ] : true;
2763
2764 return $this->get_select_time( $name, $css_class, $css_id, $is_disabled = true, $selected, $step_mins, $add_none = true );
2765 }
2766
2767 public function get_no_select_timezone( $name, $css_class = '', $css_id = '', $selected = false ) {
2768
2769 /*
2770 * The "timezone" class is always prefixed to the $css_class value.
2771 */
2772 return $this->get_select_timezone( $name, $css_class, $css_id, $is_disabled = true, $selected );
2773 }
2774
2775 public function get_no_textarea( $name, $css_class = '', $css_id = '', $len = 0, $holder = '' ) {
2776
2777 return $this->get_textarea( $name, $css_class, $css_id, $len, $holder, $is_disabled = true );
2778 }
2779
2780 public function get_no_textarea_options( $name, array $opts, $css_class = '', $css_id = '', $len = 0, $holder = '' ) {
2781
2782 $value = isset( $opts[ $name ] ) ? $opts[ $name ] : '';
2783
2784 return $this->get_no_textarea_value( $value, $css_class, $css_id, $len, $holder );
2785 }
2786
2787 public function get_no_textarea_value( $value = '', $css_class = '', $css_id = '', $len = 0, $holder = '' ) {
2788
2789 $input_class = SucomUtil::sanitize_css_class( $css_class );
2790 $input_id = SucomUtil::sanitize_css_id( $css_id );
2791 $input_rows = '';
2792
2793 if ( ! is_array( $len ) ) { // A non-array value defaults to a max length.
2794
2795 $len = empty( $len ) ? array() : array( 'max' => $len );
2796 }
2797
2798 if ( ! empty( $len[ 'rows' ] ) ) {
2799
2800 $input_rows = $len[ 'rows' ];
2801
2802 } elseif ( ! empty( $len[ 'max' ] ) ) {
2803
2804 $input_rows = round( $len[ 'max' ] / 100 ) + 1;
2805 }
2806
2807 $html = '<textarea disabled="disabled"';
2808 $html .= $input_class ? ' class="' . $input_class . '"' : ''; // Already sanitized.
2809 $html .= $input_id ? ' id="textarea_' . $input_id . '"' : ''; // Already sanitized.
2810 $html .= $input_rows ? ' rows="' . $input_rows . '"' : '';
2811 $html .= '>' . esc_attr( $value ) . '</textarea>';
2812
2813 return $html;
2814 }
2815
2816 /*
2817 * AUTOMATICALLY DISABLED AND LOCALIZED METHODS:
2818 *
2819 * get_no_input_locale()
2820 * get_no_input_image_upload_locale()
2821 * get_no_input_image_url_locale()
2822 * get_no_input_video_url_locale()
2823 * get_no_select_locale()
2824 * get_no_textarea_locale()
2825 */
2826 public function get_no_input_locale( $name, $css_class = '', $css_id = '', $holder = '' ) {
2827
2828 return $this->get_input_locale( $name, $css_class, $css_id, $len = 0, $holder, $is_disabled = true );
2829 }
2830
2831 public function get_no_input_image_upload_locale( $name_prefix, $holder = '' ) {
2832
2833 return $this->get_input_image_upload_locale( $name_prefix, $holder, $is_disabled = true );
2834 }
2835
2836 public function get_no_input_image_url_locale( $name_prefix, $url = '' ) {
2837
2838 return $this->get_input_image_url_locale( $name_prefix, $url, $is_disabled = true );
2839 }
2840
2841 public function get_no_input_video_url_locale( $name_prefix, $url = '' ) {
2842
2843 return $this->get_input_video_url_locale( $name_prefix, $primary_suffix = 'embed', $url, $is_disabled = true );
2844 }
2845
2846 public function get_no_select_locale( $name, $values = array(), $css_class = '', $css_id = '',
2847 $is_assoc = null, $selected = false, $event_names = array(), $event_args = array() ) {
2848
2849 return $this->get_select_locale( $name, $values, $css_class, $css_id,
2850 $is_assoc, $is_disabled = true, $selected, $event_names, $event_args );
2851 }
2852
2853 public function get_no_textarea_locale( $name, $css_class = '', $css_id = '', $len = 0, $holder = '' ) {
2854
2855 return $this->get_textarea_locale( $name, $css_class, $css_id, $len, $holder, $is_disabled = true );
2856 }
2857
2858 /*
2859 * AUTOMATICALLY DISABLED MULTIPLE FIELDS METHODS:
2860 *
2861 * get_no_input_multi()
2862 * get_no_mixed_multi()
2863 * get_no_select_multi()
2864 */
2865 public function get_no_input_multi( $name, $css_class = '', $css_id = '', $repeat = 1 ) {
2866
2867 return $this->get_input_multi( $name, $css_class, $css_id, $repeat, $repeat, $is_disabled = true );
2868 }
2869
2870 public function get_no_mixed_multi( $mixed, $css_class, $css_id, $repeat = 1 ) {
2871
2872 return $this->get_mixed_multi( $mixed, $css_class, $css_id, $repeat, $repeat, $is_disabled = true );
2873 }
2874
2875 public function get_no_select_multi( $name, $values = array(), $css_class = '', $css_id = '', $is_assoc = null, $repeat = 1, $is_disabled = true ) {
2876
2877 $is_disabled = empty( $is_disabled ) ? true : $is_disabled; // Allow a comment string.
2878
2879 return $this->get_select_multi( $name, $values, $css_class, $css_id, $is_assoc, $repeat, $repeat, $is_disabled );
2880 }
2881
2882 /*
2883 * PRIVATE METHODS:
2884 *
2885 * maybe_transl_sort_values()
2886 * split_name_locale()
2887 * sort_select_labels()
2888 * get_input_media_url()
2889 * get_placeholder_sanitized()
2890 * get_placeholder_attrs()
2891 * get_script_placeholder_dep()
2892 * get_script_text_len()
2893 * get_script_load_json()
2894 * get_script_trigger_show_hide()
2895 */
2896 private function maybe_transl_sort_values( $name, array $values, $is_assoc, array $event_args, $optgroup_transl = '' ) {
2897
2898 $sorted = array();
2899
2900 $values_assoc = null === $is_assoc ? SucomUtil::is_assoc( $values ) : $is_assoc;
2901
2902 $sort_by_key = false;
2903
2904 foreach ( $values as $option_value => $label ) {
2905
2906 unset( $values[ $option_value ] ); // Optimize and unset as we go.
2907
2908 if ( is_array( $label ) ) { // Two dimensional array.
2909
2910 $label_transl = empty( $event_args[ 'is_transl' ] ) ? $this->get_option_value_transl( $option_value ) : $option_value;
2911
2912 $sorted[ $label_transl ] = self::maybe_transl_sort_values( $name, $label, null, $event_args, $label_transl );
2913
2914 $sort_by_key = true;
2915
2916 } else {
2917
2918 $option_value = $values_assoc ? (string) $option_value : (string) $label;
2919
2920 $label_transl = empty( $event_args[ 'is_transl' ] ) ? $this->get_option_value_transl( $label ) : $label;
2921
2922 if ( 0 === $label ) {
2923
2924 if ( preg_match( '/_img_max/', $name ) ) {
2925
2926 $label_transl = trim( $label_transl . ' ' . $this->get_option_value_transl( '(no images)' ) );
2927
2928 } elseif ( preg_match( '/_vid_max/', $name ) ) {
2929
2930 $label_transl = trim( $label_transl . ' ' . $this->get_option_value_transl( '(no videos)' ) );
2931 }
2932
2933 } elseif ( '' === $label || 'none' === $label || '[None]' === $label ) {
2934
2935 $label_transl = $this->get_option_value_transl( '[None]' );
2936 }
2937
2938 $sorted[ $option_value ] = trim( $optgroup_transl . ' ' . $label_transl );
2939 }
2940 }
2941
2942 if ( $sort_by_key ) {
2943
2944 uksort( $sorted, array( __CLASS__, 'sort_select_labels' ) );
2945
2946 } elseif ( empty( $event_args[ 'is_sorted' ] ) ) {
2947
2948 uasort( $sorted, array( __CLASS__, 'sort_select_labels' ) );
2949 }
2950
2951 return $sorted;
2952 }
2953
2954 private function split_name_locale( $name_prefix ) {
2955
2956 $name_suffix = '';
2957
2958 /*
2959 * The '.*?' syntax is required to make the expression ungreedy.
2960 */
2961 if ( preg_match( '/^(.*?)((_[0-9]+)?(#[a-zA-Z_]+)?)$/', $name_prefix, $matches ) ) {
2962
2963 $name_prefix = $matches[ 1 ];
2964
2965 $name_suffix = $matches[ 2 ];
2966 }
2967
2968 return array( $name_prefix, $name_suffix );
2969 }
2970
2971 private static function sort_select_labels( $a_label, $b_label ) {
2972
2973 /*
2974 * Option labels in square brackets (ie. "[None]") are always top-most in the select options list.
2975 */
2976 $a_char = substr( $a_label, 0, 1 );
2977 $b_char = substr( $b_label, 0, 1 );
2978
2979 if ( 'none' === $a_label || $a_char === '[' ) {
2980
2981 if ( $a_char === $b_char ) {
2982
2983 return strnatcmp( $a_label, $b_label );
2984 }
2985
2986 return -1; // $a is first.
2987
2988 } elseif ( 'none' === $b_label || $b_char === '[' ) {
2989
2990 return 1; // $b is first.
2991 }
2992
2993 return strnatcmp( $a_label, $b_label ); // Binary safe case-insensitive string comparison.
2994 }
2995
2996 private function get_input_media_url( $name_prefix, $primary_suffix = 'id', $holder = '', $is_disabled = false ) {
2997
2998 list( $name_prefix, $name_suffix ) = $this->split_name_locale( $name_prefix );
2999
3000 $name = $name_prefix . '_url' . $name_suffix;
3001
3002 $primary_name = $name_prefix . '_' . $primary_suffix . $name_suffix;
3003 $primary_value = $this->get_options_locale( $primary_name );
3004
3005 if ( ! empty( $primary_value ) ) {
3006
3007 $this->options[ $name ] = '';
3008
3009 $is_disabled = true;
3010 }
3011
3012 $html = '';
3013 $holder = $this->get_placeholder_sanitized( $name, $holder );
3014 $value = $this->in_options( $name ) ? $this->options[ $name ] : '';
3015 $input_class = SucomUtil::sanitize_css_class( $css_class = 'wide' );
3016 $input_id = SucomUtil::sanitize_css_id( $name );
3017
3018 $html .= '<input type="text" name="' . esc_attr( $this->opts_name . '[' . $name . ']' ) . '"';
3019 $html .= $is_disabled ? ' disabled="disabled"' : '';
3020 $html .= empty( $input_class ) ? '' : ' class="' . $input_class . '"'; // Already sanitized.
3021 $html .= empty( $input_id ) ? '' : ' id="text_' . $input_id . '"'; // Already sanitized.
3022 $html .= $this->get_placeholder_attrs( $type = 'input', $holder, $name );
3023 $html .= ' value="' . esc_attr( $value ) . '" />' . "\n";
3024
3025 return $html;
3026 }
3027
3028 private function get_placeholder_sanitized( $name, $holder = '' ) {
3029
3030 if ( ! empty( $name ) ) { // Just in case.
3031
3032 if ( true === $holder ) { // Use default value.
3033
3034 if ( isset( $this->defaults[ $name ] ) ) { // Not null.
3035
3036 $holder = $this->defaults[ $name ];
3037 }
3038 }
3039
3040 if ( true === $holder || '' === $holder ) {
3041
3042 if ( ( $pos = strpos( $name, '#' ) ) > 0 ) {
3043
3044 $key_default = SucomUtilOptions::get_key_locale( substr( $name, 0, $pos ), $this->options, 'default' );
3045
3046 if ( $name !== $key_default ) {
3047
3048 if ( isset( $this->options[ $key_default ] ) ) {
3049
3050 $holder = $this->options[ $key_default ];
3051
3052 } elseif ( true === $holder ) {
3053
3054 if ( isset( $this->defaults[ $key_default ] ) ) {
3055
3056 $holder = $this->defaults[ $key_default ];
3057 }
3058 }
3059 }
3060 }
3061 }
3062 }
3063
3064 return is_bool( $holder ) ? '' : $holder; // Must be numeric or string.
3065 }
3066
3067 private function get_placeholder_attrs( $type = 'input', $holder = '', $name = '' ) {
3068
3069 if ( $holder === '' ) {
3070
3071 return '';
3072 }
3073
3074 /*
3075 * Do not pre-populate an empty input field for these option names.
3076 */
3077 if ( preg_match( '/_tid$/', $name ) ) {
3078
3079 $js_if_empty = '';
3080
3081 } else {
3082
3083 $js_if_empty = 'if ( this.value == \'\' ) this.value = this.getAttribute( \'placeholder\' );';
3084 }
3085
3086 $js_if_same = 'if ( this.value == this.getAttribute( \'placeholder\' ) ) this.value = \'\';';
3087
3088 $html = ' placeholder="' . esc_attr( $holder ) . '"';
3089
3090 /*
3091 * If the value is an empty string, then set the value to the placeholder.
3092 */
3093 $html .= $js_if_empty ? ' onClick="' . $js_if_empty . '"' : '';
3094 $html .= $js_if_empty ? ' onFocus="' . $js_if_empty . '"' : '';
3095 $html .= $js_if_empty ? ' onMouseEnter="' . $js_if_empty . '"' : '';
3096
3097 /*
3098 * If the value is the placeholder, then set the value to an empty string.
3099 */
3100 $html .= $js_if_same ? ' onChange="' . $js_if_same . '"' : '';
3101 $html .= $js_if_same ? ' onBlur="' . $js_if_same . '"' : '';
3102 $html .= $js_if_same ? ' onMouseLeave="' . $js_if_same . '"' : '';
3103
3104 /*
3105 * Check for the enter key, which submits the current form in an input field.
3106 */
3107 $html .= $js_if_same && 'input' === $type ? ' onKeyPress="if ( event.keyCode === 13 ) { ' . $js_if_same . ' }"' : '';
3108
3109 return $html;
3110 }
3111
3112 private function get_script_placeholder_dep( $container_id, $container_dep_id ) {
3113
3114 $html = '<script>';
3115 $html .= 'jQuery( \'' . $container_dep_id . '\' ).on( \'sucom_changed\', function(){';
3116 $html .= 'sucomPlaceholderDep( \'' . $container_id . '\', \'' . $container_dep_id . '\' );';
3117 $html .= '});';
3118 $html .= '</script>' . "\n";
3119
3120 return $html;
3121 }
3122
3123 private function get_script_text_len( $input_id ) {
3124
3125 if ( empty( $input_id ) ) { // Nothing to do.
3126
3127 return ''; // Return an empty string.
3128 }
3129
3130 $input_id = SucomUtil::sanitize_css_id( $input_id );
3131 $doing_ajax = SucomUtilWP::doing_ajax();
3132
3133 $html = '<script>';
3134 $html .= $doing_ajax ? '' : 'jQuery( document ).on( \'ready\', function(){'; // Make sure sucomTextLen() is available.
3135 $html .= 'jQuery( \'#' . $input_id . '\' )';
3136 $html .= '.mouseenter( function(){ window.sucom_text_len_t = setTimeout( function() { ';
3137 $html .= 'sucomTextLen( \'' . $input_id . '\', \'' . $this->admin_l10n . '\' ); }, 300 ) })';
3138 $html .= '.mouseleave( function(){ clearTimeout( window.sucom_text_len_t ); window.sucom_text_len_t = undefined; ';
3139 $html .= 'sucomTextLenReset( \'' . $input_id . '\' ); })';
3140 $html .= '.focus( function(){ sucomTextLen( \'' . $input_id . '\', \'' . $this->admin_l10n . '\' ); })';
3141 $html .= '.keyup( function(){ sucomTextLen( \'' . $input_id . '\', \'' . $this->admin_l10n . '\' ); })';
3142 $html .= '.blur( function(){ sucomTextLenReset( \'' . $input_id . '\' ); });';
3143 $html .= $doing_ajax ? '' : '});';
3144 $html .= '</script>' . "\n";
3145
3146 return $html;
3147 }
3148
3149 private function get_script_load_json( $event_json_var, $event_args, $select_json_arr, $select_id ) {
3150
3151 $html = '';
3152
3153 if ( ! $event_json_var || ! is_string( $event_json_var ) ) { // Just in case.
3154
3155 return $html;
3156 }
3157
3158 /*
3159 * Encode the PHP array to JSON only once per page load.
3160 */
3161 if ( empty( $this->json_array_added[ $event_json_var ] ) ) {
3162
3163 $this->json_array_added[ $event_json_var ] = true;
3164
3165 /*
3166 * json_encode() cannot encode an associative array - only an object or a standard numerically
3167 * indexed array - and the object element order, when read by the browser, cannot be controlled.
3168 * Firefox, for example, will sort an object numerically instead of maintaining the original object
3169 * element order. For this reason, we must use different arrays for the array keys and their
3170 * values.
3171 */
3172 $json_array_keys = wp_json_encode( array_keys( $select_json_arr ) );
3173 $json_array_values = wp_json_encode( array_values( $select_json_arr ) );
3174
3175 $script_js = 'var ' . $event_json_var . '_keys = ' . $json_array_keys . ';' . "\n";
3176 $script_js .= 'var ' . $event_json_var . '_vals = ' . $json_array_values . ';' . "\n";
3177
3178 $html .= '<!-- adding ' . $event_json_var . ' array -->' . "\n";
3179
3180 if ( ! empty( $event_args[ 'exp_secs' ] ) ) {
3181
3182 /*
3183 * Array values may be localized, so include the current locale in the cache salt string.
3184 */
3185 $cache_salt = $event_json_var . '_locale:' . SucomUtilWP::get_locale();
3186
3187 /*
3188 * Returns false on error.
3189 */
3190 $script_url = $this->p->cache->get_data_url( $cache_salt, $script_js, $event_args[ 'exp_secs' ], $pre_ext = '.js' );
3191
3192 if ( ! empty( $script_url ) ) {
3193
3194 $html .= '<script src="' . $script_url . '" async></script>' . "\n";
3195
3196 } else $html .= '<script>' . "\n" . $script_js . '</script>' . "\n";
3197
3198 } else $html .= '<script>' . "\n" . $script_js . '</script>' . "\n";
3199
3200 } else $html .= '<!-- ' . $event_json_var . ' array already added -->' . "\n";
3201
3202 /*
3203 * The 'mouseenter' event is required for Firefox to render the option list correctly.
3204 *
3205 * sucomSelectLoadJson() is loaded in the footer, so test to make sure the function is available.
3206 */
3207 $select_id_esc = esc_js( $select_id );
3208
3209 $html .= '<script>';
3210 $html .= 'jQuery( \'select#' . $select_id_esc . ':not( .json_loaded )\' ).on( \'mouseenter focus sucom_load_json\', function(){';
3211 $html .= 'if ( \'function\' === typeof sucomSelectLoadJson ) {';
3212 $html .= 'sucomSelectLoadJson( \'select#' . $select_id_esc . '\', \'' . $event_json_var . '\' );';
3213 $html .= '}';
3214 $html .= '});';
3215 $html .= '</script>' . "\n";
3216
3217 return $html;
3218 }
3219
3220 private function get_script_trigger_show_hide() {
3221
3222 if ( $this->show_hide_js_added ) { // Only add the event script once.
3223
3224 return '';
3225 }
3226
3227 $this->show_hide_js_added = true;
3228
3229 $html = <<<EOF
3230 <script>
3231
3232 jQuery.each( [ 'show', 'hide' ], function( i, ev ){
3233
3234 var el = jQuery.fn[ ev ];
3235
3236 jQuery.fn[ ev ] = function(){
3237
3238 if ( jQuery( this ).is( 'tr' ) ) {
3239
3240 var css_class = jQuery( this ).attr( 'class' );
3241
3242 if ( 'string' === typeof css_class && css_class.indexOf( 'hide_' ) == 0 ) {
3243
3244 this.trigger( ev );
3245 }
3246 }
3247
3248 return el.apply( this, arguments );
3249 };
3250 });
3251
3252 </script>
3253 EOF;
3254
3255 return $html;
3256 }
3257 }
3258 }
3259