PluginProbe ʕ •ᴥ•ʔ
پارسی دیت – Parsi Date / 6.2.1
پارسی دیت – Parsi Date v6.2.1
6.2.1 6.2 6.1 5.1.6 5.1.7 5.1.8 5.1.8.2 6.0 trunk 1.0 1.1 1.2 1.3 1.3.1 1.3.2 1.3.3 1.3.4 1.3.5 2.0.0-alpha 2.1 2.1.1 2.1.2 2.1.3 2.1.5 2.1.6 2.1.7 2.2.0 2.2.1 2.2.2 2.2.3 2.3.0.1 2.3.0.2 2.3.1 2.3.2 2.3.3 2.3.4 3.0.1 3.0.2 3.0.3 4.0.0 4.0.1 4.0.2 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5
wp-parsidate / inc / Helper / HTML.php
wp-parsidate / inc / Helper Last commit date
Assets.php 2 weeks ago Cache.php 2 weeks ago Date.php 2 weeks ago Debug.php 2 weeks ago FeedReader.php 2 weeks ago HTML.php 2 weeks ago Helper.php 2 weeks ago JSON.php 2 weeks ago Nonce.php 2 weeks ago Notice.php 2 weeks ago Number.php 2 weeks ago NumberConverter.php 2 weeks ago Param.php 2 weeks ago Sanitizing.php 2 weeks ago Strip.php 2 weeks ago Templates.php 2 weeks ago User.php 2 weeks ago Validating.php 2 weeks ago WooCommerce.php 2 weeks ago WordPress.php 2 weeks ago
HTML.php
1304 lines
1 <?php
2
3 namespace WPParsidate\Helper;
4
5 defined( 'ABSPATH' ) || exit;
6
7 use WP_Query;
8
9 class HTML {
10 private const prefix = WP_PARSI_CLASS_PREFIX;
11 private const prefixName = WP_PARSI_INPUT_PREFIX;
12
13 public const saveFields = [
14 'toggle',
15 'checkbox',
16 'radio',
17 'radioinline',
18 'checkboxinline',
19 'textarea',
20 'text',
21 'password',
22 'number',
23 'url',
24 'email',
25 'tel',
26 'search',
27 'color',
28 'colorpalette',
29 'gradientcolorpicker',
30 'range',
31 'hidden',
32 'select',
33 'posttypeselect',
34 'postselect',
35 'taxonomyselect',
36 'termselect',
37 'menuselect',
38 'imagesizeselect',
39 'userroleselect',
40 'userselect',
41 'orderstatusselect',
42 'currencyselect',
43 'media',
44 'addon',
45 'tinyaddon',
46 'wpcolorpicker'
47 ];
48 // FAQ
49
50 private const checkIcon = '<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 20 20" class="' . self::prefix . 'check-icon"><path fill="#4f8ccf" fill-rule="evenodd" d="M20 10c0 5.523-4.477 10-10 10S0 15.523 0 10 4.477 0 10 0s10 4.477 10 10m-5.97-3.03a.75.75 0 0 1 0 1.06l-5 5a.75.75 0 0 1-1.06 0l-2-2a.75.75 0 1 1 1.06-1.06l1.47 1.47 2.235-2.235L12.97 6.97z" clip-rule="evenodd"/></svg>';
51 private const crossIcon = '<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" class="' . self::prefix . 'cross-icon">
52 <path fill-rule="evenodd" clip-rule="evenodd" d="M13.5356 12.65C13.78 12.8937 13.78 13.2938 13.5356 13.5375C13.2919 13.7813 12.8956 13.7813 12.6513 13.5375L10.0037 10.8875L7.33749 13.5562C7.09124 13.8 6.69252 13.8 6.44627 13.5562C6.20064 13.3062 6.20064 12.9063 6.44627 12.6625L9.11251 9.99374L6.465 7.35001C6.22062 7.10626 6.22062 6.70623 6.465 6.46248C6.70812 6.21873 7.10437 6.21873 7.34875 6.46248L9.99626 9.11247L12.6825 6.42502C12.9287 6.18127 13.3269 6.18127 13.5731 6.42502C13.8187 6.67502 13.8187 7.06873 13.5731 7.31873L10.8875 10.0063L13.5356 12.65ZM10 0C4.47688 0 0 4.475 0 10C0 15.525 4.47688 20 10 20C15.5231 20 20 15.525 20 10C20 4.475 15.5231 0 10 0Z" fill="#8A8A8A"/>
53 </svg>';
54
55 private static function wrap( $field, $data ): string {
56 if ( isset( $data['wrap'] ) && ! $data['wrap'] ) {
57 return $field;
58 }
59
60 $controlDisabled = isset( $data['attributes']['disabled'] ) && $data['attributes']['disabled'] === 'disabled';
61 $style = isset( $data['wrap_style'] ) ? 'style="' . $data['wrap_style'] . '"' : '';
62
63 return '<div class="' . self::getClass( $data,
64 self::prefix . 'field-wrap ' . self::prefix . 'field-' . $data['type'] . ( $controlDisabled ? ' ' . self::prefix . 'control-disabled' : '' ) ) . '" ' . $style . '><div class="' . self::prefix . 'field-head">' . $field . '</div>' . ( ! empty( $data['desc'] ) ? '<div class="' . self::prefix . 'description">' . nl2br( $data['desc'] ) . '</div>' : '' ) . '</div>';
65 }
66
67 public static function textarea( $data ): string {
68 if ( ! $data = self::checkData( $data ) ) {
69 return '';
70 }
71
72 $id = self::prefix . $data['type'] . '-' . $data['id'];
73 $name = self::prefixName . $data['id'];
74
75 if ( isset( $data['is_repeatable'] ) && $data['is_repeatable'] ) {
76 $name .= '[]';
77 $id = '';
78 }
79 $field = '';
80
81 if ( ! empty( $data['title'] ) ) {
82 $field .= '<label for="' . $id . '" class="' . self::prefix . 'input-label">' . $data['title'] . $data['required_text'] . '</label>';
83 }
84
85 $field .= '<textarea name="' . $name . '" id="' . $id . '" class="' . self::getClass( $data,
86 self::prefix . 'field-textarea' ) . '" ' . self::getAttributes( $data ) . '>' . $data['setting_value'] . '</textarea>';
87
88 return self::wrap( $field, $data );
89 }
90
91 public static function inputText( $data ): string {
92 if ( ! $data = self::checkData( $data ) ) {
93 return '';
94 }
95
96 $id = self::prefix . $data['type'] . '-' . $data['id'];
97 $name = self::prefixName . $data['id'];
98
99 if (
100 ( isset( $data['is_repeatable'] ) && $data['is_repeatable'] ) ||
101 ( isset( $data['is_multiple'] ) )
102 ) {
103 $name .= isset( $data['is_multiple'] ) && is_numeric( $data['is_multiple'] ) ? '[' . $data['is_multiple'] . ']' : '[]';
104 $id = '';
105 }
106
107 $field = '';
108
109 if ( ! empty( $data['title'] ) ) {
110 $field .= '<label for="' . $id . '" class="' . self::prefix . 'input-label">' . $data['title'] . $data['required_text'] . '</label>';
111 }
112
113 $field .= '<input type="' . $data['type'] . '" name="' . $name . '" id="' . $id . '" class="' . self::prefix . 'input-' . $data['type'] . '" value="' . $data['setting_value'] . '" ' . self::getAttributes( $data ) . '>';
114
115 return self::wrap( $field, $data );
116 }
117
118 public static function color( $data ): string {
119 return self::inputText( $data );
120 }
121
122 public static function wpcolorpicker( $data ): string {
123 return self::inputText( $data );
124 }
125
126 public static function text( $data ): string {
127 return self::inputText( $data );
128 }
129
130 public static function email( $data ): string {
131 return self::inputText( $data );
132 }
133
134 public static function tel( $data ): string {
135 return self::inputText( $data );
136 }
137
138 public static function url( $data ): string {
139 return self::inputText( $data );
140 }
141
142 public static function number( $data ): string {
143 return self::inputText( $data );
144 }
145
146 public static function password( $data ): string {
147 return self::inputText( $data );
148 }
149
150 public static function search( $data ): string {
151 return self::inputText( $data );
152 }
153
154 public static function select( $data ): string {
155 if ( ! $data = self::checkData( $data ) ) {
156 return '';
157 }
158
159 $name = self::prefixName . $data['id'] . ( isset( $data['attributes']['multiple'] ) && $data['attributes']['multiple'] ? '[]' : '' );
160 $field = '';
161
162 if ( ! empty( $data['title'] ) ) {
163 $field .= '<label for="' . self::prefix . $data['type'] . '-' . $data['id'] . '" class="' . self::prefix . 'select-label">' . $data['title'] . $data['required_text'] . '</label>';
164 }
165
166 $field .= '<select name="' . $name . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" class="' . self::prefix . 'input-' . $data['type'] . '" ' . self::getAttributes( $data ) . '>';
167
168 if ( ! empty( $data['option_none'] ) ) {
169 $field .= '<option value="' . $data['option_none_value'] . '">-- ' . $data['option_none'] . ' --</option>';
170 }
171
172 if ( ! empty( $data['options'] ) && is_array( $data['options'] ) ) {
173 $isList = array_is_list( $data['options'] );
174
175 foreach ( $data['options'] as $key => $value ) {
176 $selected = isset( $data['multiple'] ) && $data['multiple'] && is_array( $data['setting_value'] ) ? in_array( ( $isList ? $value : $key ),
177 $data['setting_value'], true ) : $data['setting_value'] == ( $isList ? $value : $key );
178
179 $field .= '<option value="' . ( $isList ? $value : $key ) . '" ' . selected( $selected, true,
180 false ) . '>' . $value . '</option>';
181 }
182 }
183
184 $field .= '</select>';
185
186 return self::wrap( $field, $data );
187 }
188
189 public static function imagesizeselect( $data ): string {
190 if ( ! $data = self::checkData( $data ) ) {
191 return '';
192 }
193 $data['options'] = apply_filters( 'wp_parsidate_image_sizes_select_items', Assets::getImageSizes() );
194
195 return self::select( $data );
196 }
197
198 public static function userselect( $data ): string {
199 if ( ! $data = self::checkData( $data ) ) {
200 return '';
201 }
202
203 $userList = [];
204 $defaultArgs = array(
205 'number' => 50,
206 'count_total' => false
207 );
208 $args = wp_parse_args( $data['args'], $defaultArgs );
209 $args['fields'] = [ 'ID', 'display_name', 'user_login', 'user_email' ];
210 $users = get_users( $args );
211 if ( ! empty( $users ) && is_array( $users ) ) {
212 foreach ( $users as $user ) {
213 $userList[ $user->ID ] = $user->display_name . ' (' . $user->ID . ', ' . $user->user_login . ', ' . $user->user_email . ')';
214 }
215 }
216 $data['options'] = $userList;
217
218 return self::select( $data );
219 }
220
221 public static function userroleselect( $data ): string {
222 if ( ! $data = self::checkData( $data ) ) {
223 return '';
224 }
225
226 $roles = get_editable_roles();
227 $roleNames = array_keys( $roles );
228 $roleLabels = wp_list_pluck( $roles, 'name' );
229 $data['options'] = array_combine( $roleNames, $roleLabels );
230
231 return self::select( $data );
232 }
233
234 public static function taxonomyselect( $data ): string {
235 if ( ! $data = self::checkData( $data ) ) {
236 return '';
237 }
238
239 $defaultArgs = array( 'public' => true );
240 $args = wp_parse_args( $data['args'], $defaultArgs );
241 $taxonomies = get_taxonomies( $args, 'objects' );
242 $taxonomyNames = wp_list_pluck( $taxonomies, 'name' );
243 $taxonomyLabels = wp_list_pluck( $taxonomies, 'label' );
244 $data['options'] = array_combine( $taxonomyNames, $taxonomyLabels );
245
246 return self::select( $data );
247 }
248
249 public static function termselect( $data ): string {
250 if ( ! $data = self::checkData( $data ) ) {
251 return '';
252 }
253
254 $defaultArgs = array(
255 'taxonomy' => 'category',
256 'hide_empty' => true,
257 'orderby' => 'name',
258 'order' => 'ASC',
259 );
260 $args = wp_parse_args( $data['args'], $defaultArgs );
261 $args['fields'] = 'all';
262 $terms = get_terms( $args );
263 $termIds = wp_list_pluck( $terms, 'term_id' );
264 $termNames = wp_list_pluck( $terms, 'name' );
265 $data['options'] = array_combine( $termIds, $termNames );
266
267 return self::select( $data );
268 }
269
270 public static function posttypeselect( $data ): string {
271 if ( ! $data = self::checkData( $data ) ) {
272 return '';
273 }
274
275 $defaultArgs = array( 'public' => true );
276 $args = wp_parse_args( $data['args'], $defaultArgs );
277 $postTypes = get_post_types( $args, 'objects' );
278 $postTypeNames = wp_list_pluck( $postTypes, 'name' );
279 $postTypeLabels = wp_list_pluck( $postTypes, 'label' );
280 $data['options'] = array_combine( $postTypeNames, $postTypeLabels );
281
282 return self::select( $data );
283 }
284
285 public static function postselect( $data ): string {
286 global $post;
287 if ( ! $data = self::checkData( $data ) ) {
288 return '';
289 }
290
291 $postTemp = $post;
292 $defaultArgs = array(
293 'post_type' => 'post',
294 'post_status' => 'publish',
295 'posts_per_page' => 50,
296 'ignore_sticky_posts' => true,
297 'no_found_rows' => true,
298 'order' => 'DESC',
299 'orderby' => 'date',
300 'update_post_meta_cache' => false,
301 'update_post_term_cache' => false,
302 );
303 $args = wp_parse_args( $data['args'], $defaultArgs );
304 $args['fields'] = 'all';
305 $postsQuery = new WP_Query( $args );
306 $postIds = wp_list_pluck( $postsQuery->posts, 'ID' );
307 $postTitles = wp_list_pluck( $postsQuery->posts, 'post_title' );
308 $data['options'] = array_combine( $postIds, $postTitles );
309
310 wp_reset_postdata();
311 $post = $postTemp;
312
313 return self::select( $data );
314 }
315
316 public static function menuselect( $data ): string {
317 if ( ! $data = self::checkData( $data ) ) {
318 return '';
319 }
320
321 $defaults = array(
322 'hide_empty' => false,
323 'orderby' => 'name',
324 );
325
326 $data['args'] = wp_parse_args( $data['args'], $defaults );
327 $data['args']['taxonomy'] = 'nav_menu';
328
329 return self::termselect( $data );
330 }
331
332 public static function orderstatusselect( $data ): string {
333 if ( ! $data = self::checkData( $data ) ) {
334 return '';
335 }
336
337 $data['options'] = WooCommerce::getOrderStatuses();
338
339 return self::select( $data );
340 }
341
342 public static function currencyselect( $data ): string {
343 if ( ! $data = self::checkData( $data ) ) {
344 return '';
345 }
346
347 $options = [];
348 foreach ( get_woocommerce_currencies() as $code => $name ) {
349 $options[ $code ] = esc_html( sprintf( '%1$s (%2$s)', $name, $code ) );
350 }
351
352 $data['options'] = $options;
353
354 return self::select( $data );
355 }
356
357 public static function media( $data ): string {
358 if ( ! $data = self::checkData( $data ) ) {
359 return '';
360 }
361
362 $field = '';
363 if ( ! empty( $data['title'] ) ) {
364 $field .= '<label class="' . self::prefix . 'input-label">' . $data['title'] . '</label>';
365 }
366
367 $id = self::prefix . $data['type'] . '-' . $data['id'];
368 $placeholder = $data['placeholder'] ?? esc_html__( 'Select Media(s)',
369 'wp-parsidate' );
370 $selectButton = $data['select_button'] ?? $placeholder;
371 $removeAllButton = $data['remove_all_button'] ?? esc_html__( 'Remove all media',
372 'wp-parsidate' );
373 $maxNumber = $data['media_max_number'] ?? 1;
374 $data['attributes']['data-title'] = $data['media_title'] ?? esc_html__( 'Select or Upload Media',
375 'wp-parsidate' );
376 $data['attributes']['data-button'] = $data['media_button'] ?? esc_html__( 'Use this media',
377 'wp-parsidate' );
378 $data['attributes']['data-type'] = $data['media_type'] ?? ''; // image, video, audio
379 $data['attributes']['data-multi-selection'] = (int) ( $data['upload_multi_selection'] ?? true );
380 $data['attributes']['data-accept-extensions'] = $data['upload_accept_extensions'] ?? ''; // Separate with comma (,), example: pdf,doc,docx
381 $_mediaIDs = explode( ',', $data['setting_value'] );
382 $_mediaIDs = array_filter( $_mediaIDs );
383 $_mediaIDs = array_map( 'intval', $_mediaIDs );
384 $medias = $mediaIDs = [];
385 $counter = 0;
386
387 foreach ( $_mediaIDs as $_mediaID ) {
388 if ( $counter >= $maxNumber ) {
389 break;
390 }
391
392 $media = false;
393
394 if ( wp_attachment_is( 'image', $_mediaID ) ) {
395 $media = wp_get_attachment_thumb_url( $_mediaID );
396 } else {
397 $attachmentThumbnailID = get_post_thumbnail_id( $_mediaID );
398 if ( $attachmentThumbnailID ) {
399 $image = wp_get_attachment_image_src( $attachmentThumbnailID, 'thumbnail', true );
400 if ( is_array( $image ) ) {
401 $media = $image[0];
402 }
403 }
404
405 if ( ! $media ) {
406 $image = wp_get_attachment_image_src( $_mediaID, 'thumbnail', true );
407 if ( is_array( $image ) ) {
408 $media = $image[0];
409 }
410 }
411 }
412
413 if ( $media ) {
414 $medias[ $_mediaID ] = $media;
415 $mediaIDs[] = $_mediaID;
416 $counter ++;
417 }
418 }
419
420 $field .= '<div id="' . $id . '" class="' . self::getClass( $data,
421 self::prefix . 'media-wrap ' . ( count( $medias ) ? self::prefix . 'media-selected' : '' ) ) . '" ' . self::getAttributes( $data ) . '>';
422 $field .= '<input type="hidden" name="' . self::prefixName . $data['id'] . '" class="' . self::prefix . 'media-value" value="' . implode( ',',
423 $mediaIDs ) . '">';
424
425 // Image(s)
426 $field .= '<div class="' . self::prefix . 'media-images">';
427 foreach ( $medias as $id => $media ) {
428 $imageTitle = $id . ': ';
429 $title = wp_get_attachment_caption( $id );
430 if ( empty( $title ) ) {
431 $title = get_the_title( $id );
432 }
433 $imageTitle .= $title;
434
435 $imageType = 'application';
436 if ( wp_attachment_is( 'image', $id ) || wp_attachment_is( 'svg', $id ) ) {
437 $imageType = 'image';
438 } elseif ( wp_attachment_is( 'video', $id ) ) {
439 $imageType = 'video';
440 } elseif ( wp_attachment_is( 'audio', $id ) ) {
441 $imageType = 'audio';
442 }
443
444 $imageTitle .= ' (' . $imageType . ')';
445
446 $field .= '<div class="' . self::prefix . 'media-image" data-id="' . $id . '"><img src="' . ( $media ?: '' ) . '" title="' . $imageTitle . '" alt="image"><span class="' . self::prefix . 'media-image-title">' . $imageTitle . '</span></div>';
447 }
448 $field .= '</div>';
449
450 // Buttons
451 $field .= '<div class="' . self::prefix . 'media-buttons">';
452 $field .= self::button( array(
453 'id' => $data['id'] . '_select',
454 'title' => $selectButton,
455 'type' => 'button',
456 'button_type' => 'button',
457 'button_theme' => 'secondary',
458 'class' => [ 'wppd-media-select' ]
459 ) );
460 if ( $removeAllButton ) {
461 $field .= self::button( array(
462 'id' => $data['id'] . '_remove_all',
463 'title' => $removeAllButton,
464 'type' => 'button',
465 'button_type' => 'button',
466 'class' => [ 'wppd-media-remove-all' ]
467 ) );
468 }
469 $field .= '</div>';
470
471 // Placeholder
472 $field .= '<div class="' . self::prefix . 'media-placeholder ' . self::prefix . 'media-select">' . $placeholder . '</div>';
473
474 $field .= '</div>';
475
476 return self::wrap( $field, $data );
477 }
478
479 public static function range( $data ): string {
480 if ( ! $data = self::checkData( $data ) ) {
481 return '';
482 }
483
484 $field = '';
485
486 if ( ! empty( $data['title'] ) ) {
487 $field .= '<label for="' . self::prefix . $data['type'] . '-' . $data['id'] . '" class="' . self::prefix . 'title ' . self::prefix . 'input-label ">' . $data['title'] . '</label>';
488 }
489
490 $field .= '<div class="' . self::prefix . 'range-field-wrap' . '"><input type="' . $data['type'] . '" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" class="' . self::getClass( $data,
491 self::prefix . 'input-' . $data['type'] ) . '" value="' . $data['setting_value'] . '" ' . self::getAttributes( $data ) . '>';
492
493 if ( isset( $data['display_value'] ) && $data['display_value'] ) {
494 $field .= '<output>' . $data['setting_value'] . '</output>';
495 }
496
497 $field .= '</div>';
498
499 return self::wrap( $field, $data );
500 }
501
502 public static function hidden( $data ): string {
503 return '<input type="hidden" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" value="' . $data['setting_value'] . '" >';
504 }
505
506 public static function radio( $data ): string {
507 if ( ! $data = self::checkData( $data ) ) {
508 return '';
509 }
510 $field = '<label class="' . self::prefix . 'radio-wrap">' .
511 '<input type="radio" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" value="' . $data['value'] . '" ' . checked( $data['setting_value'] == $data['value'],
512 true, false ) . self::getAttributes( $data ) . '>' .
513 '<span class="' . self::prefix . 'checkmark"></span><span class="' . self::prefix . 'title">' . $data['title'] . '</span></label>';
514
515 return self::wrap( $field, $data );
516 }
517
518 public static function radioinline( $data ): string {
519 if ( ! $data = self::checkData( $data ) ) {
520 return '';
521 }
522
523 if ( array_is_list( $data['options'] ) ) {
524 $data['options'] = array_combine( $data['options'], $data['options'] );
525 }
526
527 $field = self::startinlineelements( $data );
528 $labelClass = self::prefix . 'radio-inline' . ( isset( $data['not_equal'] ) && $data['not_equal'] ? ' wppd-not-equal' : '' );
529
530 foreach ( $data['options'] as $key => $value ) {
531 $field .= '<label class="' . $labelClass . '">' .
532 '<input type="radio" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" value="' . $key . '" ' . checked( $data['setting_value'] == $key,
533 true, false ) . self::getAttributes( $data ) . '>' .
534 '<span class="' . self::prefix . 'checkmark"></span><span class="' . self::prefix . 'title">' . $value . '</span></label>';
535 }
536
537 $field .= self::endinlineelements( $data );
538
539 return $field;
540 }
541
542 public static function checkboxinline( $data ): string {
543 if ( ! $data = self::checkData( $data ) ) {
544 return '';
545 }
546
547 $isList = array_is_list( $data['options'] );
548 if ( $isList ) {
549 $data['options'] = array_combine( $data['options'], $data['options'] );
550 }
551
552 $field = self::startinlineelements( $data );
553
554 $labelClass = self::prefix . 'checkbox-inline' . ( isset( $data['not_equal'] ) && $data['not_equal'] ? ' wppd-not-equal' : '' );
555 foreach ( $data['options'] as $key => $value ) {
556 $checked = is_array( $data['setting_value'] ) ? in_array( ( $isList ? $value : $key ),
557 $data['setting_value'], true ) : $data['setting_value'] == ( $isList ? $value : $key );
558
559 $field .= '<label class="' . $labelClass . '">' .
560 '<input type="checkbox" name="' . self::prefixName . $data['id'] . '[]" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" value="' . $key . '" ' . checked( $checked,
561 true, false ) . self::getAttributes( $data ) . '>' .
562 '<span class="' . self::prefix . 'checkmark"></span><span class="' . self::prefix . 'title">' . $value . '</span></label>';
563 }
564
565 $field .= self::endinlineelements( $data );
566
567 return $field;
568 }
569
570 public static function checkbox( $data ): string {
571 if ( ! $data = self::checkData( $data ) ) {
572 return '';
573 }
574 $field = '<label class="' . self::prefix . 'checkbox-wrap">' .
575 '<input type="hidden" name="' . self::prefixName . $data['id'] . '" value="' . $data['unchecked_value'] . '">' .
576 '<input type="checkbox" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . $data['type'] . '-' . $data['id'] . '" value="' . $data['value'] . '" ' . checked( $data['setting_value'] == $data['value'],
577 true, false ) . self::getAttributes( $data ) . '>' .
578 '<span class="' . self::prefix . 'checkmark"></span>' . ( ! empty( $data['title'] ) ? '<span class="' . self::prefix . 'title">' . $data['title'] . '</span>' : '' ) . '</label>';
579
580 return self::wrap( $field, $data );
581 }
582
583 public static function toggle( $data ): string {
584 if ( ! $data = self::checkData( $data ) ) {
585 return '';
586 }
587
588 $field = '<label class="' . self::prefix . 'toggle">' .
589 '<input type="hidden" name="' . self::prefixName . $data['id'] . '" value="' . $data['unchecked_value'] . '">' .
590 '<input type="checkbox" name="' . self::prefixName . $data['id'] . '" id="' . self::prefix . 'toggle-' . $data['id'] . '" value="' . $data['value'] . '" ' . checked( $data['setting_value'] == $data['value'],
591 true, false ) . self::getAttributes( $data ) . '>' .
592 '<span class="' . self::prefix . 'toggle-slider" type="button"><span class="' . self::prefix . 'toggle-handle">' . self::checkIcon . self::crossIcon . '</span></span></label>';
593 if ( ! empty( $data['title'] ) ) {
594 $field .= '<label for="' . self::prefix . 'toggle-' . $data['id'] . '" class="' . self::prefix . 'input-title">' . $data['title'] . '</label>';
595 }
596
597 return self::wrap( $field, $data );
598 }
599
600 public static function button( $data ): string {
601 $data['type'] = $data['type'] ?? 'button';
602 if ( ! $data = self::checkData( $data ) ) {
603 return '';
604 }
605
606 return '<button id="' . self::prefix . $data['id'] . '-button" class="' . self::getClass( $data,
607 self::prefix . 'button ' . self::prefix . 'button-' . $data['button_type'] ) . '" type="' . $data['button_type'] . '" ' . self::getAttributes( $data ) . '>' . $data['title'] . '</button>';
608 }
609
610 public static function hr(): string {
611 return '<hr />';
612 }
613
614 public static function space( $data ): string {
615 if ( ! $data = self::checkData( $data ) ) {
616 return '';
617 }
618
619 return '<div style="height: ' . $data['size'] . 'px"></div>';
620 }
621
622 public static function startinlineelements( $data ): string {
623 if ( $data['type'] === 'startinlineelements' ) {
624 $type = 'inline-elements';
625 } elseif ( $data['type'] === 'radioinline' ) {
626 $type = 'radio';
627 } else {
628 $type = 'checkbox';
629 }
630 $style = isset( $data['wrap_style'] ) ? 'style="' . $data['wrap_style'] . '"' : '';
631
632 // fieldset
633 $element = '<div id="' . self::prefix . ( empty( $data['id'] ) ? '' : $data['id'] . '-' ) . $type . '-group" class="' . self::getClass( $data,
634 self::prefix . $type . '-group' ) . '" ' . $style . '>';
635 if ( ! empty( $data['title'] ) ) {
636 $element .= '<legend class="' . self::prefix . 'title">' . $data['title'] . '</legend>';
637 }
638 $element .= '<div class="' . self::prefix . $type . '-group-options">';
639
640 return $element;
641 }
642
643 public static function endinlineelements( $data ): string {
644 return '</div></div>'; // fieldset
645 }
646
647 public static function startrepeatable( $data ): string {
648 if ( ! $data = self::checkData( $data ) ) {
649 return '';
650 }
651
652 $addRepeat = '<a href="#" class="' . self::prefix . 'add-repeatable" data-position="start"><i class="wppd-icon-plus-circle"></i></a>';
653
654 return '<div class="' . self::prefix . 'repeatable ' . ( ! empty( $data['class'] ) ? ' ' . $data['class'] : '' ) . '" ' . self::getAttributes( $data ) . '>' .
655 '<div class="' . self::prefix . 'title">' . $data['title'] . $addRepeat . '</div>' .
656 '<div class="' . self::prefix . 'repeatable-wrap">';
657 }
658
659 public static function endrepeatable( $data ): string {
660 if ( ! $data = self::checkData( $data ) ) {
661 return '';
662 }
663
664 $addText = ! empty( $data['add_text'] ) ? ' ' . $data['add_text'] : '';
665 $addRepeat = '<a href="#" class="' . self::prefix . 'add-repeatable" data-position="end"><i class="wppd-icon-plus-circle"></i>' . $addText . '</a>';
666
667 return '</div>' . $addRepeat . '</div>';
668 }
669
670 public static function startrepeatableelements( $data ): string {
671 if ( ! $data = self::checkData( $data ) ) {
672 return '';
673 }
674
675 $data = wp_parse_args( $data, [ 'move_action' => true ] );
676 $moveUpRepeat = $moveDownRepeat = '';
677
678 if ( $data['move_action'] ) {
679 $moveUpRepeat = '<a href="#" class="' . self::prefix . 'move-up-repeatable"><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
680 <path d="M6 15L12 9L18 15" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
681 </svg></a>';
682 $moveDownRepeat = '<a href="#" class="' . self::prefix . 'move-down-repeatable"><svg width="24px" height="24px" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
683 <path d="M6 9L12 15L18 9" stroke="#000000" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
684 </svg></a>';
685 }
686
687 $removeRepeat = '<a href="#" class="' . self::prefix . 'remove-repeatable"><svg width="24px" height="24px" viewBox="0 0 32 32" version="1.1" xmlns="http://www.w3.org/2000/svg">
688 <g id="Page-1" stroke="none" stroke-width="1" fill-rule="evenodd">
689 <g transform="translate(-516.000000, -1087.000000)">
690 <path d="M532,1117 C524.268,1117 518,1110.73 518,1103 C518,1095.27 524.268,1089 532,1089 C539.732,1089 546,1095.27 546,1103 C546,1110.73 539.732,1117 532,1117 L532,1117 Z M532,1087 C523.163,1087 516,1094.16 516,1103 C516,1111.84 523.163,1119 532,1119 C540.837,1119 548,1111.84 548,1103 C548,1094.16 540.837,1087 532,1087 L532,1087 Z M538,1102 L526,1102 C525.447,1102 525,1102.45 525,1103 C525,1103.55 525.447,1104 526,1104 L538,1104 C538.553,1104 539,1103.55 539,1103 C539,1102.45 538.553,1102 538,1102 L538,1102 Z">
691 </path>
692 </g>
693 </g>
694 </svg></a>';
695
696 return '<div class="' . self::prefix . 'repeatable-fields-wrap" data-repeat-title="' . ( $data['title'] ?? '' ) . '">' .
697 '<div class="' . self::prefix . 'repeatable-actions">' . $moveUpRepeat . $moveDownRepeat . $removeRepeat . '</div>';
698 }
699
700 public static function endrepeatableelements( $data ): string {
701 return '</div>';
702 }
703
704 public static function startgrid( $data ): string {
705 if ( ! isset( $data['cols'] ) ) {
706 $data['cols'] = 2;
707 }
708
709 return '<div class="' . self::prefix . 'grid ' . self::prefix . 'grid-cols-' . $data['cols'] . ( ! empty( $data['class'] ) ? ' ' . $data['class'] : '' ) . '">' .
710 '<div class="' . self::prefix . 'title">' . $data['title'] . '</div>' .
711 '<div class="' . self::prefix . 'fields-wrap">';
712 }
713
714 public static function endgrid( $data ): string {
715 return '</div></div>';
716 }
717
718 public static function h2( $data ): string {
719 return '<h2 class="' . self::prefix . 'heading-2">' . $data['title'] . '</h2>';
720 }
721
722 public static function tinyaddon( $data ): string {
723 if ( ! $data = self::checkData( $data ) ) {
724 return '';
725 }
726
727 $canActivate = isset( $data['can_activate'] ) && $data['can_activate'];
728 $class = self::getclass( $data );
729 if ( ! $canActivate ) {
730 $class .= ' ' . self::prefix . 'addon-inactive';
731 }
732
733 $addon = '<div class="' . self::prefix . 'tiny-addon-wrap' . $class . '" title="' . $data['desc'] . '"><div class="' . self::prefix . 'title-image">';
734
735 if ( ! empty( $data['icon'] ) ) {
736 if ( ! empty( $data['image_link'] ) ) {
737 $addon .= '<a href="' . $data['image_link'] . '" target="_blank" class="' . self::prefix . 'image-link ' . self::prefix . 'image-wrap">' . $data['icon'] . '</a>';
738 } else {
739 $addon .= '<div class="' . self::prefix . 'image-wrap">' . $data['icon'] . '</div>';
740 }
741 }
742
743 $addon .= '<span class="' . self::prefix . 'title">' . $data['title'] . '</span></div>';
744
745 if ( $canActivate ) {
746 $addon .= self::toggle( array(
747 'id' => $data['id'],
748 'type' => 'toggle',
749 'title' => '',
750 'value' => $data['force_enable'] ?: $data['value'],
751 'setting_value' => $data['force_enable'] ?: $data['setting_value'],
752 'attributes' => $data['force_enable'] ? [ 'disabled' => 'disabled' ] : [],
753 ) );
754
755 } elseif ( ! empty( $data['action_link'] ) ) {
756 $addon .= '<a href="' . $data['action_link'] . '" ' . ( $data['action_link_external'] ? 'target="_blank"' : '' ) . ' class="' . self::prefix . 'action-link ' . self::prefix . 'button ' . self::prefix . 'button-secondary">' . $data['action_title'] . '</a>';
757
758 }
759
760 $addon .= '</div>';
761
762 return $addon;
763 }
764
765 public static function addon( $data ): string {
766 if ( ! $data = self::checkData( $data ) ) {
767 return '';
768 }
769
770 $canActivate = isset( $data['can_activate'] ) && $data['can_activate'];
771 $class = self::getclass( $data );
772 if ( ! $canActivate ) {
773 $class .= ' ' . self::prefix . 'addon-inactive';
774 }
775
776 $addon = '<div class="' . self::prefix . 'addon-wrap' . $class . '">' .
777 '<div class="' . self::prefix . 'image-wrap">';
778
779 if ( is_array( $data['tags'] ) && ! empty( $data['tags'] ) && is_string( $data['tags'][0] ) ) {
780 $addon .= '<span class="' . self::prefix . 'tag">' . $data['tags'][0] . '</span>';
781 }
782
783 $image = '';
784 if ( ! empty( $data['icon'] ) ) {
785 $image = $data['icon'];
786 } elseif ( ! empty( $data['image'] ) ) {
787 $image = self::image( [ 'src' => $data['image'] ] );
788 }
789
790 if ( ! empty( $image ) ) {
791 if ( ! empty( $data['image_link'] ) ) {
792 $addon .= '<a href="' . $data['image_link'] . '" target="_blank" class="' . self::prefix . 'image-link">' . $image . '</a>';
793 } else {
794 $addon .= $image;
795 }
796 }
797
798 $addon .= '</div><div class="' . self::prefix . 'title-desc"><strong class="' . self::prefix . 'title">' . $data['title'] . '</strong>' .
799 ( ! empty( $data['desc'] ) ? '<p class="' . self::prefix . 'desc">' . $data['desc'] . '</p>' : '' ) .
800 ( ! empty( $data['more_info_link'] ) ? '<a href="' . $data['more_info_link'] . '" target="_blank" class="' . self::prefix . 'more-info-link"><i class="wppd-icon-chevron-right"></i><span>' . esc_html__( 'More info',
801 'wp-parsidate' ) . '</span></a>' : '' ) .
802 '</div><div class="' . self::prefix . 'action-wrap">';
803
804 if ( $canActivate ) {
805 $addon .= self::toggle( array(
806 'id' => $data['id'],
807 'type' => 'toggle',
808 'title' => $data['action_title'],
809 'value' => $data['force_enable'] ?: $data['value'],
810 'setting_value' => $data['force_enable'] ?: $data['setting_value'],
811 'attributes' => $data['force_enable'] ? [ 'disabled' => 'disabled' ] : [],
812 ) );
813
814 } elseif ( ! empty( $data['action_link'] ) ) {
815 $addon .= '<a href="' . $data['action_link'] . '" ' . ( $data['action_link_external'] ? 'target="_blank"' : '' ) . ' class="' . self::prefix . 'action-link">' . $data['action_title'] . '</a>';
816
817 }
818
819 $addon .= '</div></div>';
820
821 return $addon;
822 }
823
824 public static function startaddons( $data ): string {
825 return '<div class="' . self::prefix . 'addons-wrap' . ( ! empty( $data['class'] ) ? ' ' . $data['class'] : '' ) . '">' . self::h2( $data ) . '<div class="' . self::prefix . 'addons-grid">';
826 }
827
828 public static function endaddons( $data ): string {
829 return '</div></div>';
830 }
831
832 public static function notice( $data ): string {
833 if ( ! $data = self::checkData( $data ) ) {
834 return '';
835 }
836
837 $key = 'notice_element_' . $data['id'];
838
839 return Notice::addAndDisplay( $key, $data['notices'], false );
840 }
841
842 public static function table( $data ): string {
843 if ( ! $data = self::checkData( $data ) ) {
844 return '';
845 }
846
847 // WP table class: widefat, fixed, striped
848 $tableClass = ( $data['table_class'] ?? '' ) . ' widefat';
849 $class = self::getClass( $data, self::prefix . 'table-wrap' );
850 $tableHead = $data['head'] ?? [];
851 $tableBody = $data['body'] ?? [];
852 $tableFooter = $data['footer'] ?? [];
853 $noEntries = $data['no_entries'] ?? esc_html__( 'No entries!', 'wp-parsidate' );
854
855 if ( empty( $tableHead ) ) {
856 return '';
857 }
858
859 $id = self::prefix . $data['type'] . '-' . $data['id'];
860 $table = '<div class="' . $class . '" id="' . $id . '">';
861
862 if ( ! empty( $data['title'] ) ) {
863 $table .= '<div class="' . self::prefix . 'table-title">' . $data['title'] . '</div>';
864 }
865
866 $table .= '<table class="' . $tableClass . '">';
867 if ( $data['mode'] === 'vertical' ) {
868 $table .= '<thead><tr>';
869 foreach ( $tableHead as $head ) {
870 $table .= "<th>$head</th>";
871 }
872 $table .= '</tr></thead>';
873 }
874
875 if ( empty( $tableBody ) ) {
876 $table .= '<tr><td colspan="100%">' . $noEntries . '</td></tr>';
877
878 } else {
879 foreach ( $tableBody as $index => $body ) {
880 $table .= '<tr>';
881
882 if ( $data['mode'] === 'horizontal' ) {
883 $table .= '<th>' . $tableHead[ $index ] . '</th>';
884 }
885
886 foreach ( $body as $value ) {
887 $table .= '<td>' . $value . '</td>';
888 }
889
890 $table .= '</tr>';
891 }
892 }
893
894 if ( $data['mode'] === 'vertical' && ! empty( $tableFooter ) ) {
895 $table .= '<tfoot><tr>';
896 foreach ( $tableFooter as $foot ) {
897 $table .= "<th>$foot</th>";
898 }
899 $table .= '</tr></tfoot>';
900 }
901
902 $table .= '</table>';
903
904 if ( ! empty( $data['desc'] ) ) {
905 $table .= '<p class="' . self::prefix . 'description">' . $data['desc'] . '</p>';
906 }
907
908 $table .= '</div>';
909
910 return $table;
911 }
912
913 public static function paragraph( $data ): string {
914 if ( ! $data = self::checkData( $data ) ) {
915 return '';
916 }
917
918 $class = self::getClass( $data, self::prefix . 'paragraph-wrap' );
919
920 return '<p class="' . $class . '">' . $data['text'] . '</p>';
921 }
922
923 public static function image( $data ): string {
924 if ( ! $data = self::checkData( $data ) ) {
925 return '';
926 }
927
928 return '<img src="' . $data['src'] . '" class="' . self::getClass( $data,
929 self::prefix . 'image' ) . '" ' . self::getAttributes( $data ) . '>';
930 }
931
932 public static function gradientcolorpicker( $data ): string {
933 if ( ! $data = self::checkData( $data ) ) {
934 return '';
935 }
936
937 $field = '';
938 if ( ! empty( $data['title'] ) ) {
939 $field .= '<label class="' . self::prefix . 'input-label">' . $data['title'] . '</label>';
940 }
941
942 $id = self::prefix . $data['type'] . '-' . $data['id'];
943 $value = is_array( $data['setting_value'] ) ? $data['setting_value'] : [];
944 $function = $value['function'] = $value['function'] ?? 'linear-gradient';
945 $rotate = $value['rotate'] = $value['rotate'] ?? 90;
946 $shape = $value['shape'] = $value['shape'] ?? 'ellipse';
947 $colors = $value['colors'] = isset( $value['colors'] ) && is_array( $value['colors'] ) && count( $value['colors'] ) >= 2 ? $value['colors'] : $data['default']['colors'];
948 $gradientStyle = 'background: ' . Assets::cssGradient( $value, $data['default'] );
949 $jsonValue = str_replace( '"', "'", JSON::encode( $value ) );
950 $firstColor = false;
951
952 $field .= '<div id="' . $id . '" class="' . self::getClass( $data,
953 self::prefix . 'gradient-color-picker-wrap' ) . '" ' . self::getAttributes( $data ) . '>';
954 $field .= '<input type="hidden" name="' . self::prefixName . $data['id'] . '" class="' . self::prefix . 'gradient-color-picker-value" value="' . $jsonValue . '">';
955
956 $field .= '<div class="' . self::prefix . 'gradient-color-picker" style="' . $gradientStyle . '">';
957 $i = 0;
958 foreach ( $colors as $position => $color ) {
959 $pointID = $id . '-' . $i;
960 $field .= '<div id="' . $pointID . '" class="' . self::prefix . 'gradient-color-point ' . ( ! $firstColor ? 'is-active' : '' ) . '" data-color="' . $color . '" data-position="' . $position . '" data-index="' . $i . '" style="left:5px"><span style="background-color: ' . $color . '"></span></div>';
961 $i ++;
962 if ( ! $firstColor ) {
963 $firstColor = $color;
964 }
965 }
966 $field .= '</div>';
967
968 $field .= self::wpcolorpicker( array(
969 'id' => $data['id'] . '_color_picker',
970 'title' => esc_html__( 'Color', 'wp-parsidate' ),
971 'type' => 'wpcolorpicker',
972 'class' => 'wppd-gradient-select-color',
973 'setting_value' => $firstColor,
974 ) );
975
976 $field .= self::radioinline( array(
977 'id' => $data['id'] . '_type',
978 'title' => esc_html__( 'Type', 'wp-parsidate' ),
979 'type' => 'radioinline',
980 'setting_value' => $function,
981 'not_equal' => true,
982 'class' => 'wppd-gradient-color-type',
983 'options' => array(
984 'linear-gradient' => esc_html__( 'Linear', 'wp-parsidate' ),
985 'radial-gradient' => esc_html__( 'Radial', 'wp-parsidate' ),
986 )
987 ) );
988
989 $field .= self::radioinline( array(
990 'id' => $data['id'] . '_shape',
991 'title' => esc_html__( 'Shape', 'wp-parsidate' ),
992 'type' => 'radioinline',
993 'setting_value' => $shape,
994 'class' => 'wppd-gradient-color-shape wppd-gradient-color-variant',
995 'wrap_style' => $function !== 'radial-gradient' ? 'display:none' : '',
996 'options' => array(
997 'ellipse' => esc_html__( 'Ellipse', 'wp-parsidate' ),
998 'circle' => esc_html__( 'Circle', 'wp-parsidate' ),
999 )
1000 ) );
1001
1002 $field .= self::range( array(
1003 'id' => $data['id'] . '_range',
1004 'title' => esc_html__( 'Rotation °', 'wp-parsidate' ),
1005 'type' => 'range',
1006 'setting_value' => $rotate,
1007 'display_value' => true,
1008 'class' => 'wppd-gradient-color-rotation wppd-gradient-color-variant',
1009 'wrap_style' => $function !== 'linear-gradient' ? 'display:none' : '',
1010 'attributes' => array(
1011 'min' => 0,
1012 'max' => 360,
1013 ),
1014 ) );
1015
1016 $field .= '</div>';
1017
1018 return self::wrap( $field, $data );
1019 }
1020
1021 public static function colorpalette( $data ) {
1022 if ( ! $data = self::checkData( $data ) ) {
1023 return '';
1024 }
1025
1026 $field = '';
1027 if ( ! empty( $data['title'] ) ) {
1028 $field .= '<label class="' . self::prefix . 'input-label">' . $data['title'] . '</label>';
1029 }
1030
1031 $colors = is_array( $data['setting_value'] ) ? $data['setting_value'] : [];
1032
1033 $field .= '<div class="' . self::getClass( $data,
1034 self::prefix . 'color-palette ' . self::prefix . 'color-palette-' . $data['mode'] ) . '" ' . self::getAttributes( $data ) . '>';
1035 if ( count( $colors ) ) {
1036 $field .= '<div class="' . self::prefix . 'color-palette-items' . '">';
1037 foreach ( $colors as $i => $color ) {
1038 $field .= self::wpcolorpicker( array(
1039 'id' => $data['id'],
1040 'type' => 'wpcolorpicker',
1041 'default' => '#ffffff',
1042 'setting_value' => $color,
1043 'is_multiple' => $i,
1044 'wrap' => false
1045 ) );
1046 }
1047 $field .= '</div>';
1048 }
1049
1050 if ( $data['addable'] ) {
1051 $addText = ! empty( $data['add_text'] ) ? ' ' . $data['add_text'] : '';
1052 $field .= '<div class="' . self::prefix . 'add-color-wrap"><a href="#" class="' . self::prefix . 'add-color" ' . ( count( $colors ) >= $data['max_items'] ? 'disable="true"' : '' ) . '><i class="wppd-icon-plus-circle"></i>' . $addText . '</a></div>';
1053 }
1054
1055 $field .= '</div>';
1056
1057 return self::wrap( $field, $data );
1058 }
1059
1060 public static function datatable( $data ) {
1061 if ( ! $data = self::checkData( $data ) ) {
1062 return '';
1063 }
1064
1065 $dataTable = $data['data_table'];
1066 $dataTable['component_id'] = self::prefix . $data['type'] . '-' . $data['id'];
1067 $template = Templates::getPath( 'data-table/data_table.php' );
1068
1069 return Templates::load( $template, $dataTable, false, false );
1070 }
1071
1072 public static function printFields( $fields, $echo = true ) {
1073 if ( ! is_array( $fields ) ) {
1074 return '';
1075 }
1076
1077 $output = '';
1078 foreach ( $fields as $field ) {
1079 if ( ! empty( $field['type'] ) && method_exists( self::class, strtolower( $field['type'] ) ) ) {
1080 $field['type'] = strtolower( $field['type'] );
1081 $output .= self::{$field['type']}( $field );
1082 }
1083 }
1084
1085 if ( $echo ) {
1086 // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
1087 echo $output;
1088 } else {
1089 return $output;
1090 }
1091 }
1092
1093 /**
1094 * Check input data
1095 *
1096 * @param array $data
1097 *
1098 * @return bool|array
1099 */
1100 private static function checkData( array $data ) {
1101 if ( ! isset( $data['class'] ) ) {
1102 $data['class'] = [];
1103 } else {
1104 $data['class'] = is_array( $data['class'] ) ? $data['class'] : [ $data['class'] ];
1105 }
1106
1107 $data['required_text'] = $data['required_text'] ?? '';
1108 if ( $data['required_text'] ) {
1109 $requiredText = '*';
1110 if ( is_string( $data['required_text'] ) ) {
1111 $requiredText = $data['required_text'];
1112 }
1113
1114 $data['required_text'] = ' <abbr class="required" title="' . esc_html__( 'Required',
1115 'wp-parsidate' ) . '">' . $requiredText . '</abbr>';
1116 }
1117
1118 $attributes = empty( $data['attributes'] ) || ! is_array( $data['attributes'] ) ? [] : $data['attributes'];
1119
1120 if ( isset( $data['type'] ) && ! in_array( $data['type'], self::saveFields, true ) ) {
1121 if ( $data['type'] === 'image' && filter_var( $data['src'], FILTER_VALIDATE_URL ) ) {
1122 return false;
1123 }
1124 if ( $data['type'] === 'notice' && ( empty( $data['id'] ) || empty( $data['notices'] ) || ! is_array( $data['notices'] ) ) ) {
1125 return false;
1126 }
1127 if ( $data['type'] === 'startrepeatable' ) {
1128 if ( ! empty( $data['max_repeat'] ) ) {
1129 $attributes['data-max-repeat'] = (int) $data['max_repeat'];
1130 }
1131 }
1132 if ( $data['type'] === 'startrepeatableelements' ) {
1133 if ( isset( $data['move_action'] ) ) {
1134 $data['move_action'] = Sanitizing::bool( $data['move_action'] );
1135 }
1136 }
1137
1138 if ( $data['type'] === 'space' ) {
1139 if ( ! isset( $data['size'] ) ) {
1140 $data['size'] = 20;
1141 }
1142 }
1143
1144 if ( $data['type'] === 'button' ) {
1145 if ( isset( $data['button_theme'] ) ) {
1146 $data['class'][] = 'wppd-button-' . $data['button_theme'];
1147 }
1148 }
1149
1150 $data['attributes'] = $attributes;
1151
1152 return $data;
1153 }
1154
1155 if ( ! isset( $data['wrap'] ) ) {
1156 $data['wrap'] = true;
1157 }
1158
1159 if ( empty( $data['id'] ) && in_array( $data['type'], self::saveFields, true ) ) {
1160 return false;
1161 }
1162 $default = $data['default'] ?? '';
1163 if ( is_array( $default ) ) {
1164 $default = str_replace( '"', "'", JSON::encode( $default ) );
1165 }
1166 $attributes['data-default'] = $default;
1167
1168 if ( isset( $data['setting_value'] ) && ( is_string( $data['setting_value'] ) || is_numeric( $data['setting_value'] ) ) ) {
1169 $settingValue = html_entity_decode( $data['setting_value'] );
1170 if ( mb_strlen( $settingValue ) !== mb_strlen( $data['setting_value'] ) ) {
1171 $data['setting_value'] = $settingValue;
1172 }
1173 }
1174 if ( ! isset( $data['setting_value'] ) ) {
1175 $data['setting_value'] = null;
1176 }
1177 if ( isset( $data['multiple'] ) && $data['multiple'] ) {
1178 $attributes['multiple'] = 'multiple';
1179 }
1180 if ( isset( $data['disabled'] ) && $data['disabled'] ) {
1181 $attributes['disabled'] = 'disabled';
1182 }
1183 if ( isset( $data['readonly'] ) && $data['readonly'] ) {
1184 $attributes['readonly'] = 'readonly';
1185 }
1186 if ( isset( $data['required'] ) && $data['required'] ) {
1187 $attributes['required'] = 'required';
1188 }
1189 if ( ! empty( $data['placeholder'] ) ) {
1190 $attributes['placeholder'] = $data['placeholder'];
1191 }
1192 if ( $data['type'] === 'range' && isset( $data['display_value'] ) && $data['display_value'] ) {
1193 $attributes['oninput'] = 'this.nextElementSibling.value = this.value';
1194 }
1195 if ( ! empty( $data['option_none'] ) && ! isset( $data['option_none_value'] ) ) {
1196 $data['option_none_value'] = '';
1197 }
1198 if ( in_array( $data['type'], [ 'select', 'radioinline', 'checkboxinline', 'colorpalette' ] )
1199 && ( ! isset( $data['options'] ) || ! is_array( $data['options'] ) ) ) {
1200 $data['options'] = array();
1201 }
1202
1203 if ( in_array( $data['type'], [ 'checkbox', 'toggle' ] ) ) {
1204 if ( ! isset( $data['value'] ) ) {
1205 $data['value'] = 1;
1206 }
1207 if ( ! isset( $data['unchecked_value'] ) ) {
1208 $data['unchecked_value'] = 0;
1209 }
1210 }
1211
1212 if ( $data['type'] === 'colorpalette' ) {
1213 if ( ! isset( $data['addable'] ) ) {
1214 $data['addable'] = false;
1215 }
1216
1217 if ( ! isset( $data['removable'] ) ) {
1218 $data['removable'] = $data['addable'];
1219 }
1220
1221 if ( ! isset( $data['mode'] ) || ! in_array( $data['mode'], [ 'vertical', 'horizontal' ], true ) ) {
1222 $data['mode'] = 'horizontal';
1223 }
1224
1225 $attributes['data-addable'] = (int) $data['addable'];
1226 $attributes['data-removable'] = (int) $data['removable'];
1227 $attributes['data-mode'] = $data['mode'];
1228
1229 if ( ! isset( $data['max_items'] ) ) {
1230 $data['max_items'] = 20;
1231 }
1232
1233 if ( ! empty( $data['max_items'] ) ) {
1234 $attributes['data-max-items'] = (int) $data['max_items'];
1235 }
1236 }
1237
1238 if ( $data['type'] === 'gradientcolorpicker' ) {
1239 if ( ! isset( $data['max_colors'] ) ) {
1240 $data['max_colors'] = 4;
1241 }
1242
1243 $attributes['data-max-colors'] = (int) $data['max_colors'];
1244 }
1245
1246 if ( $data['type'] === 'media' ) {
1247 if ( ! isset( $data['media_max_number'] ) ) {
1248 $data['media_max_number'] = 1;
1249 }
1250 $data['media_max_number'] = (int) $data['media_max_number'];
1251 $data['media_max_number'] = max( 1, $data['media_max_number'] );
1252 $data['media_max_number'] = min( 18, $data['media_max_number'] );
1253
1254 $attributes['data-max-number'] = $data['media_max_number'];
1255 }
1256
1257 if ( in_array( $data['type'], [
1258 'userselect',
1259 'userroleselect',
1260 'posttypeselect',
1261 'postselect',
1262 'taxonomyselect',
1263 'termselect',
1264 'menuselect',
1265 ] ) && ( ! isset( $data['args'] ) || ! is_array( $data['args'] ) ) ) {
1266 $data['args'] = array();
1267 }
1268
1269 if ( $data['type'] === 'wpcolorpicker' ) {
1270 $data['class'] = self::getClass( $data, self::prefix . 'wp-color-picker' );
1271 $data['type'] = 'text';
1272 }
1273 $data['attributes'] = $attributes;
1274
1275 return $data;
1276 }
1277
1278 public static function getAttributes( $data, $default = [] ): string {
1279 $attributes = '';
1280
1281 if ( is_array( $data['attributes'] ) && is_array( $default ) ) {
1282 $data['attributes'] = array_merge( $default, $data['attributes'] );
1283 }
1284
1285 if ( ! empty( $data['attributes'] ) && is_array( $data['attributes'] ) ) {
1286 foreach ( $data['attributes'] as $key => $value ) {
1287 $attributes .= ' ' . esc_attr( $key ) . '="' . esc_attr( $value ) . '"';
1288 }
1289 }
1290
1291 return $attributes;
1292 }
1293
1294 private static function getClass( $data, $default = '' ): string {
1295 $class = $default;
1296
1297 if ( ! empty( $data['class'] ) ) {
1298 $class .= ' ' . ( is_array( $data['class'] ) ? implode( ' ', $data['class'] ) : $data['class'] );
1299 }
1300
1301 return esc_attr( $class );
1302 }
1303 }
1304