PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 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
← All changes | lib/com/form.php +3258 -0 22.5.322.7.0 View file →
@@ -1,0 +1,3258 @@
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 +}