PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.1
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.1
5.6.7 5.6.6 5.6.5 5.6.4 5.6.3 5.6.2 5.6.1 5.6.0 5.5.2 5.5.1 5.5.0 5.4.2 trunk 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.1.91 5.1.92 5.1.93 5.1.94 5.2.0 5.2.1 5.2.10 5.2.11 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.0 5.3.1 5.3.2 5.4.0 5.4.1
latepoint / lib / helpers / form_helper.php
latepoint / lib / helpers Last commit date
activities_helper.php 1 year ago agent_helper.php 1 year ago auth_helper.php 9 months ago blocks_helper.php 1 year ago booking_helper.php 1 year ago bricks_helper.php 1 year ago bundles_helper.php 1 year ago calendar_helper.php 9 months ago carts_helper.php 1 year ago connector_helper.php 1 year ago csv_helper.php 9 months ago customer_helper.php 9 months ago customer_import_helper.php 9 months ago database_helper.php 9 months ago debug_helper.php 1 year ago defaults_helper.php 1 year ago elementor_helper.php 1 year ago email_helper.php 9 months ago encrypt_helper.php 1 year ago events_helper.php 1 year ago form_helper.php 9 months ago icalendar_helper.php 1 year ago image_helper.php 1 year ago invoices_helper.php 9 months ago license_helper.php 1 year ago location_helper.php 1 year ago marketing_systems_helper.php 1 year ago meeting_systems_helper.php 1 year ago menu_helper.php 9 months ago meta_helper.php 1 year ago migrations_helper.php 1 year ago money_helper.php 1 year ago notifications_helper.php 9 months ago order_intent_helper.php 9 months ago orders_helper.php 1 year ago otp_helper.php 9 months ago pages_helper.php 1 year ago params_helper.php 1 year ago payments_helper.php 1 year ago price_breakdown_helper.php 1 year ago process_jobs_helper.php 1 year ago processes_helper.php 1 year ago replacer_helper.php 1 year ago resource_helper.php 1 year ago roles_helper.php 9 months ago router_helper.php 1 year ago service_helper.php 1 year ago sessions_helper.php 1 year ago settings_helper.php 9 months ago short_links_systems_helper.php 9 months ago shortcodes_helper.php 9 months ago sms_helper.php 1 year ago steps_helper.php 9 months ago stripe_connect_helper.php 9 months ago styles_helper.php 9 months ago support_topics_helper.php 1 year ago time_helper.php 9 months ago timeline_helper.php 9 months ago transaction_helper.php 1 year ago transaction_intent_helper.php 1 year ago util_helper.php 9 months ago version_specific_updates_helper.php 9 months ago whatsapp_helper.php 1 year ago work_periods_helper.php 1 year ago wp_datetime.php 1 year ago wp_user_helper.php 1 year ago
form_helper.php
949 lines
1 <?php
2
3 class OsFormHelper {
4
5
6 public static function get_hidden_fields_for_array( array $array, string $prefix = '' ): string {
7 $inputs = '';
8 foreach ( $array as $key => $value ) {
9 $fieldName = $prefix ? $prefix . "[" . $key . "]" : $key;
10
11 if ( is_array( $value ) ) {
12 $inputs .= self::get_hidden_fields_for_array( $value, $fieldName );
13 } else {
14 $inputs .= OsFormHelper::hidden_field( $fieldName, $value );
15 }
16 }
17
18 return $inputs;
19 }
20
21 public static function atts_string_from_array( $atts = array(), $join_atts = array() ) {
22 $atts_str = '';
23 if ( ! empty( $atts ) ) {
24 if ( isset( $atts['add_string_to_id'] ) ) {
25 unset( $atts['add_string_to_id'] );
26 }
27 if ( isset( $atts['skip_id'] ) ) {
28 unset( $atts['skip_id'] );
29 }
30 foreach ( $atts as $key => $value ) {
31 if ( isset( $join_atts[ $key ] ) ) {
32 $value .= ' ' . $join_atts[ $key ];
33 unset( $join_atts[ $key ] );
34 }
35 if ( ! is_array( $value ) ) {
36 $atts_str .= esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
37 }
38 }
39 }
40 if ( ! empty( $join_atts ) ) {
41 foreach ( $join_atts as $key => $value ) {
42 $atts_str .= esc_attr( $key ) . '="' . esc_attr( $value ) . '" ';
43 }
44 }
45
46 return $atts_str;
47 }
48
49
50 /**
51 * @param string $name
52 * @param string $label
53 * @param bool $is_active
54 * @param $controlledToggleId
55 * @param $size
56 *
57 * @return string
58 */
59 public static function toggler_radio_field( string $name, string $label, string $value, bool $is_active, $controlledToggleId = false, $size = false, $atts = [] ): string {
60 if ( ! $size ) {
61 $size = 'normal';
62 }
63 $status = $is_active ? 'on' : 'off';
64 $controlledToggleHtml = $controlledToggleId ? 'data-controlled-toggle-id="' . $controlledToggleId . '"' : '';
65 $html = '';
66 $id = self::name_to_id( $name . '_' . $value );
67 $extra = ( empty( $atts['sub_label'] ) ) ? '' : ' with-sub-label';
68 if ( $label ) {
69 $html .= '<div class="os-form-group os-form-toggler-group ' . $extra . ' size-' . $size . '">';
70 }
71 $html .= OsFormHelper::radio_field( $name, $value, $is_active, [ 'id' => $id ] );
72 $html .= '<div ' . $controlledToggleHtml . ' class="os-toggler os-toggler-radio ' . $status . ' size-' . $size . '" data-is-string-value="true" data-for="' . $id . '"><div class="toggler-rail"><div class="toggler-pill"></div></div></div>';
73 if ( $label ) {
74 $html .= '<div class="os-toggler-label-w">';
75 $html .= '<label>' . esc_html( $label ) . '</label>';
76 if ( ! empty( $atts['sub_label'] ) ) {
77 $html .= '<span>' . esc_html( $atts['sub_label'] ) . '</span>';
78 }
79 $html .= '</div>';
80 }
81 if ( $label ) {
82 $html .= '</div>';
83 }
84
85 return $html;
86 }
87
88 /**
89 * @param string $name
90 * @param string $label
91 * @param bool $is_active
92 * @param $controlledToggleId
93 * @param $size
94 *
95 * @return string
96 */
97 public static function toggler_field( string $name, string $label, bool $is_active, $controlledToggleId = false, $size = false, $atts = [] ): string {
98 if ( ! $size ) {
99 $size = 'normal';
100 }
101 $status = $is_active ? 'on' : 'off';
102 $value = $is_active ? 'on' : 'off';
103 if($controlledToggleId){
104 $controlledToggleHtml = str_starts_with($controlledToggleId, '-') ? 'data-negative-controlled-toggle-id="' . substr($controlledToggleId, 1) . '"' : 'data-controlled-toggle-id="' . $controlledToggleId . '"';
105 }else{
106 $controlledToggleHtml = '';
107 }
108 $html = '';
109 $id = self::name_to_id( $name );
110 $extra = ( empty( $atts['sub_label'] ) ) ? '' : ' with-sub-label';
111 if ( $label ) {
112 $html .= '<div class="os-form-group os-form-toggler-group ' . $extra . ' size-' . $size . '">';
113 }
114 $html .= OsFormHelper::hidden_field( $name, $value, [ 'id' => $id ] );
115 $instant_update = ! empty( $atts['instant_update_route'] ) ? 'data-os-instant-update="' . esc_attr( $atts['instant_update_route'] ) . '"' : '';
116 $instant_update .= empty( $atts['nonce'] ) ? '' : ' data-nonce="' . esc_attr( $atts['nonce'] ) . '"';
117 $html .= '<div ' . $controlledToggleHtml . ' class="os-toggler ' . $status . ' size-' . $size . '" data-is-string-value="true" data-for="' . $id . '" ' . $instant_update . '><div class="toggler-rail"><div class="toggler-pill"></div></div></div>';
118 if ( $label ) {
119 $html .= '<div class="os-toggler-label-w">';
120 $html .= '<label>' . esc_html( $label ) . '</label>';
121 if ( ! empty( $atts['sub_label'] ) ) {
122 $html .= '<span>' . esc_html( $atts['sub_label'] ) . '</span>';
123 }
124 $html .= '</div>';
125 }
126 if ( $label ) {
127 $html .= '</div>';
128 }
129
130 return $html;
131 }
132
133
134 public static function media_uploader_field( $name, $post_id = 0, $label_set_str = '', $label_remove_str = '', $value_image_id = false, $atts = array(), $wrapper_atts = array(), $is_avatar = false, $is_compact = false, $default_image_html = '' ) {
135 $upload_link = esc_url( get_upload_iframe_src( 'image', $post_id ) );
136 $img_html = '';
137 $has_image_class = '';
138 $label_str = $label_set_str;
139
140 // Image is set
141 if ( $value_image_id ) {
142 $image_url = esc_url( OsImageHelper::get_image_url_by_id( $value_image_id ) );
143 $img_html = $is_avatar ? '<div class="image-self" style="background-image: url(' . $image_url . ')"></div>' : '<img src="' . $image_url . '"/>';
144 $has_image_class = 'has-image';
145 $label_str = $label_remove_str;
146 } else {
147 $img_html = '<div class="os-placeholder"></div>';
148 }
149
150 $is_avatar_class = $is_avatar ? ' is-avatar ' : '';
151 $is_compact_class = $is_compact ? ' is-compact ' : '';
152 $html = '';
153 $html .= '<div class="os-image-selector-w ' . $is_avatar_class . ' ' . $is_compact_class . ' ' . $has_image_class . '">';
154 $html .= '<a href="' . $upload_link . '" data-label-remove-str="' . esc_attr( $label_remove_str ) . '" data-label-set-str="' . esc_attr( $label_set_str ) . '"' . self::atts_string_from_array( $wrapper_atts, [ 'class' => "os-image-selector-trigger" ] ) . '>';
155 $html .= '<div class="os-image-container">' . $img_html . '</div>';
156 if ( $default_image_html ) {
157 $html .= '<div class="os-default-image-wrapper">' . $default_image_html . '</div>';
158 }
159 $html .= '<div class="os-image-selector-text"><span class="os-text-holder">' . esc_html( $label_str ) . '</span></div>';
160 $html .= '</a>';
161 $html .= '<input type="hidden" name="' . $name . '" value="' . esc_attr( $value_image_id ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-image-id-holder' ] ) . '/>';
162 $html .= '</div>';
163
164 return $html;
165 }
166
167
168 public static function multiple_files_uploader_field($name, $label_add_str = '', $label_remove_str = '', $value_file_ids = array(), $wrapper_atts = array()): string {
169
170 $html = '<div class="os-multiple-files-uploader" '.OsFormHelper::atts_string_from_array($wrapper_atts).'>';
171
172 // Current files display
173 $html .= '<div class="os-uploaded-files-list" data-confirm-text="'. esc_attr__('Are you sure want to remove this file?', 'latepoint') . '">';
174 if (!empty($value_file_ids)) {
175 foreach ($value_file_ids as $file_id) {
176 $file_url = esc_url(wp_get_attachment_url($file_id));
177 $html .= '<div class="os-uploaded-file" data-file-id="'.esc_attr($file_id).'">';
178 $html .= '<a class="os-file-link" href="'.$file_url.'" target="_blank">'.esc_html(basename($file_url)).'</a>';
179 $html .= '<a href="#" class="os-remove-file" title="'.esc_attr($label_remove_str).'"><i class="latepoint-icon latepoint-icon-cross"></i></a>';
180 $html .= '</div>';
181 }
182 }
183 $html .= '</div>';
184
185 // Add more files button
186 $html .= '<span class="os-file-selector-text">' . esc_html($label_add_str) . '</span>';
187 $html .= '<input type="hidden" name="'.esc_attr($name).'" value="'.esc_attr(implode(',', $value_file_ids)).'" class="os-file-ids-holder" />';
188 $html .= '</div>';
189
190 return $html;
191 }
192
193 public static function file_upload_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $accepted_formats = '' ) {
194 if ( empty($accepted_formats) ) {
195 $accepted_formats = '.jpg,.jpeg,.png,.gif,.ico,.pdf,.doc,.docx,.ppt,.pptx,.pps,.ppsx,.odt,.xls,.xlsx,.PSD,.mp3,.m4a,.ogg,.wav,.mp4,.m4v,.mov,.wmv,.avi,.mpg,.ogv,.3gp,.3g2';
196 }
197 // generate id if not set
198 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
199 $atts['id'] = self::name_to_id( $name, $atts );
200 }
201 $html = '';
202 if ( ! empty( $wrapper_atts ) ) {
203 $html .= '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
204 }
205 $html .= '<div class="os-form-group os-form-file-upload-group">';
206 if ( $label ) {
207 $html .= '<label for="' . esc_attr( $name ) . '">' . $label . '</label>';
208 }
209 $html .= '<a target="_blank" href="' . esc_url( $value ) . '" class="os-uploaded-file-info ' . ( ! empty( $value ) ? 'is-uploaded' : '' ) . '" style="' . ( empty( $value ) ? 'display: none' : '' ) . '">
210 <div class="uf-icon"><i class="latepoint-icon latepoint-icon-file-text"></i></div>
211 <div class="uf-data">
212 <div class="uf-name">' . ( ! empty( $value ) ? basename( $value ) : '' ) . '</div>
213 </div>
214 <div class="uf-remove"><i class="latepoint-icon latepoint-icon-cross"></i></div>
215 </a>';
216 $html .= '<div class="os-upload-file-input-w" style="' . ( $value ? 'display: none' : '' ) . '">';
217 $html .= '<input type="file" accept="' . $accepted_formats . '" name="' . esc_attr( $name ) . '" multiple="false" ' . self::atts_string_from_array( $atts ) . '/>';
218 if ( $value ) {
219 $html .= self::hidden_field( $name, $value );
220 }
221 $html .= '</div>';
222 $html .= '</div>';
223 if ( ! empty( $wrapper_atts ) ) {
224 $html .= '</div>';
225 }
226
227 return $html;
228 }
229
230 public static function generate_select_options_from_custom_field( $options ) {
231 if ( ! empty( $options ) ) {
232 return preg_split( '/\r\n|\r|\n/', $options );
233 } else {
234 return [];
235 }
236 }
237
238 /**
239 * @param $name
240 * @param $id
241 * @param $label
242 * @param $content
243 * @param $atts
244 *
245 * @return string
246 *
247 * Same as wp_editor_field but returns the html instead of echoing it
248 */
249 public static function wp_editor_field_return( $name, $id, $label, $content, $atts = array() ) {
250 ob_start();
251
252 self::wp_editor_field( $name, $id, $label, $content, $atts );
253
254 $html = ob_get_clean();
255
256 return $html;
257 }
258
259 public static function wp_editor_field( $name, $id, $label, $content, $atts = array() ) {
260 $editor_height = isset( $atts['editor_height'] ) ? $atts['editor_height'] : 300;
261 echo '<div class="os-form-group os-form-control-wp-editor-group">';
262 echo '<label for="' . esc_attr( $name ) . '">' . esc_html( $label ) . '</label>';
263 wp_editor( $content, $id, [
264 'textarea_name' => $name,
265 'media_buttons' => false,
266 'editor_height' => $editor_height
267 ] );
268 echo '</div>';
269 }
270
271
272 public static function textarea_field( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
273 $extra_class = ' os-form-group-transparent';
274 if ( isset( $atts['theme'] ) ) {
275 switch ( $atts['theme'] ) {
276 case 'bordered':
277 $extra_class = ' os-form-group-bordered';
278 break;
279 case 'right-aligned':
280 $extra_class = ' os-form-group-right-aligned';
281 break;
282 case 'simple':
283 $extra_class = ' os-form-group-simple';
284 unset( $atts['theme'] );
285 break;
286 }
287 }
288 // generate id if not set
289 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
290 $atts['id'] = self::name_to_id( $name, $atts );
291 }
292 if ( $value ) {
293 $extra_class .= ' has-value';
294 }
295 if ( empty( $label ) ) {
296 $extra_class .= ' no-label';
297 }
298
299 // validations
300 if ( ! empty( $atts['validate'] ) ) {
301 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
302 } else {
303 $validate_html = '';
304 }
305 unset( $atts['validate'] );
306 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
307 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-textfield-group os-form-textarea-group' . $extra_class ) ) . '>';
308 if ( $label ) {
309 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . $label . '</label>';
310 }
311 $placeholder = ( ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
312 $html .= '<textarea ' . $validate_html . ' type="text" placeholder="' . esc_attr( $placeholder ) . '" name="' . esc_attr( $name ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . '>' . esc_textarea( $value ?? '' ) . '</textarea>';
313 $html .= '</div>';
314 $html .= '</div>';
315
316 return $html;
317 }
318
319 public static function service_selector_adder_field( $name, $label, $add_label, $options = array(), $value = '', $atts = array(), $wrapper_atts = array() ) {
320 $html = '<div ' . self::atts_string_from_array( $wrapper_atts, [ 'class' => 'os-form-group os-form-select-group os-form-group-transparent service-selector-adder-field-w' ] ) . '>';
321 if ( $label ) {
322 $html .= '<label for="' . $name . '">' . $label . '</label>';
323 }
324 $html .= '<div class="selector-adder-w">';
325 $html .= '<select name="' . $name . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . ' data-select-source="' . esc_attr( OsRouterHelper::build_route_name( 'service_categories', 'list_for_select' ) ) . '">';
326 foreach ( $options as $option ) {
327 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
328 $selected = ( $value == $option['value'] ) ? 'selected' : '';
329 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
330 }
331 }
332 $html .= '</select>';
333 $html .= '<button class="latepoint-btn latepoint-btn-secondary" data-os-action="' . esc_attr( OsRouterHelper::build_route_name( 'service_categories', 'new_form' ) ) . '" data-os-output-target="lightbox"><i class="latepoint-icon latepoint-icon-plus"></i> <span>' . esc_html( $add_label ) . '</span></button>';
334 $html .= '</div>';
335 $html .= '</div>';
336
337 return $html;
338 }
339
340 public static function location_selector_adder_field( $name, $label, $add_label, $options = array(), $value = '', $atts = array(), $wrapper_atts = array() ) {
341 $html = '<div ' . self::atts_string_from_array( $wrapper_atts, [ 'class' => 'os-form-group os-form-select-group os-form-group-transparent location-selector-adder-field-w' ] ) . '>';
342 if ( $label ) {
343 $html .= '<label for="' . $name . '">' . $label . '</label>';
344 }
345 $html .= '<div class="selector-adder-w">';
346 $html .= '<select name="' . $name . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . ' data-select-source="' . esc_attr( OsRouterHelper::build_route_name( 'location_categories', 'list_for_select' ) ) . '">';
347 foreach ( $options as $option ) {
348 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
349 $selected = ( $value == $option['value'] ) ? 'selected' : '';
350 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
351 }
352 }
353 $html .= '</select>';
354 $html .= '<button class="latepoint-btn latepoint-btn-primary" data-os-action="' . esc_attr( OsRouterHelper::build_route_name( 'location_categories', 'new_form' ) ) . '" data-os-output-target="lightbox"><i class="latepoint-icon latepoint-icon-plus"></i> <span>' . esc_html( $add_label ) . '</span></button>';
355 $html .= '</div>';
356 $html .= '</div>';
357
358 return $html;
359 }
360
361 public static function model_options_for_multi_select( $model_name ) {
362 $options = [];
363 switch ( $model_name ) {
364 case 'service':
365 case 'OsServiceModel':
366 $service = new OsServiceModel;
367 $services = $service->get_results_as_models();
368 if ( $services ) {
369 foreach ( $services as $service ) {
370 $options[] = [ 'value' => $service->id, 'label' => $service->name ];
371 }
372 }
373 break;
374 case 'agent':
375 case 'OsAgentModel':
376 $agent = new OsAgentModel;
377 $agents = $agent->get_results_as_models();
378 if ( $agents ) {
379 foreach ( $agents as $agent ) {
380 $options[] = [ 'value' => $agent->id, 'label' => $agent->full_name ];
381 }
382 }
383 break;
384 case 'customer':
385 case 'OsCustomerModel':
386 $customer = new OsCustomerModel;
387 $customers = $customer->get_results_as_models();
388 if ( $customers ) {
389 foreach ( $customers as $customer ) {
390 $options[] = [ 'value' => $customer->id, 'label' => $customer->full_name ];
391 }
392 }
393 break;
394
395 case 'bundle':
396 case 'OsBundleModel':
397 if ( $bundles = ( new OsBundleModel() )->get_results_as_models() ) {
398 foreach ( $bundles as $bundle ) {
399 $options[] = [ 'value' => $bundle->id, 'label' => $bundle->name ];
400 }
401 }
402
403 break;
404 }
405
406 /**
407 * Returns an array of options based on model name/mnemonic, formatted for multi-select fields
408 *
409 * @param {array} $options Array of model options to filter
410 * @param {string} $model_name Class name or mnemonic used to determine resultant options
411 *
412 * @returns {array} Filtered array of model options
413 * @since 4.4.0
414 * @hook latepoint_model_options_for_multi_select
415 *
416 */
417 return apply_filters( 'latepoint_model_options_for_multi_select', $options, $model_name );
418 }
419
420 public static function date_picker_field( string $name, string $formatted_value = '', string $raw_value = '', array $atts = [] ): string {
421 $html = '<div data-single-date="yes" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-date-range-picker' ] ) . '>
422 <span class="range-picker-value">' . esc_html( $formatted_value ) . '</span>
423 <i class="latepoint-icon latepoint-icon-chevron-down"></i>
424 <input class="os-datepicker-date-from" type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $raw_value ) . '"/>
425 </div>';
426
427 return $html;
428 }
429
430 public static function multi_select_field( $name, $label = false, $options = [], $selected_values = [], $atts = [], $wrapper_atts = [] ) {
431 $html = '';
432 if ( ! $selected_values ) {
433 $selected_values = [];
434 }
435 // generate id if not set
436 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
437 $atts['id'] = self::name_to_id( $name, $atts );
438 }
439 if ( ! empty( $wrapper_atts ) ) {
440 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
441 }
442 $html .= '<div class="os-form-group os-form-select-group os-form-group-transparent">';
443 if ( $label ) {
444 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
445 }
446 $html .= '<select " ' . self::atts_string_from_array( $atts, [ 'class' => 'os-late-select' ] ) . ' data-placeholder="' . esc_attr__( 'Click to select...', 'latepoint' ) . '" multiple>';
447 foreach ( $options as $key => $option ) {
448 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
449 $selected = ( $selected_values && is_array( $selected_values ) && in_array( $option['value'], $selected_values ) ) ? 'selected="selected"' : '';
450 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
451 } else {
452 $value = ( is_string( $key ) ) ? $key : $option;
453 $selected = ( $selected_values && in_array( $value, $selected_values ) ) ? 'selected' : '';
454 $html .= '<option value="' . esc_attr( $value ) . '" ' . $selected . '>' . esc_html( $option ) . '</option>';
455 }
456 }
457 $html .= '</select>';
458 $html .= OsFormHelper::hidden_field( $name, is_array( $selected_values ) ? implode( ',', $selected_values ) : $selected_values, [ 'skip_id' => true ] );
459 $html .= '</div>';
460 if ( ! empty( $wrapper_atts ) ) {
461 $html .= '</div>';
462 }
463
464 return $html;
465 }
466
467
468 public static function multi_checkbox_field( $name, $label = false, $options = [], $selected_values = [], $atts = [], $wrapper_atts = [] ) {
469 $html = '';
470
471 if ( ! empty( $wrapper_atts ) ) {
472 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
473 }
474
475 $html .= '<div class="os-form-group os-form-multiselect-group os-form-group-transparent">';
476
477 if ( $label ) {
478 $html .= '<label>' . esc_html( $label ) . '</label>';
479 }
480
481 foreach ( $options as $key => $option ) {
482 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
483 $value = $option['value'];
484 $option_label = $option['label'];
485 } else {
486 $value = ( is_string( $key ) ) ? $key : $option;
487 $option_label = $option;
488 }
489
490 $checkbox_id = self::name_to_id( $name . '_' . $value );
491 $is_checked = in_array( $value, $selected_values );
492
493 $html .= self::checkbox_field(
494 $name . '[]',
495 $option_label,
496 $value,
497 $is_checked,
498 [ 'id' => $checkbox_id ] + $atts,
499 [ 'class' => 'checkbox-option-wrapper' ],
500 ''
501 );
502 }
503
504 $html .= '</div>';
505
506 if ( ! empty( $wrapper_atts ) ) {
507 $html .= '</div>';
508 }
509
510 return $html;
511 }
512
513 public static function select_field( $name, $label, $options = array(), $selected_value = '', $atts = array(), $wrapper_atts = array(), $add_value_if_not_present = false ) {
514 $extra_class = ' os-form-group-transparent';
515 if ( isset( $atts['theme'] ) ) {
516 switch ( $atts['theme'] ) {
517 case 'bordered':
518 $extra_class = ' os-form-group-bordered';
519 break;
520 case 'right-aligned':
521 $extra_class = ' os-form-group-right-aligned';
522 break;
523 case 'simple':
524 $extra_class = ' os-form-group-simple';
525 unset( $atts['theme'] );
526 break;
527 }
528 }
529 $html = '';
530 // generate id if not set
531 if ( ! $atts ) {
532 $atts = [];
533 }
534 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
535 $atts['id'] = self::name_to_id( $name, $atts );
536 }
537
538 // validations
539 if ( ! empty( $atts['validate'] ) ) {
540 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
541 } else {
542 $validate_html = '';
543 }
544
545 if ( ! empty( $wrapper_atts ) ) {
546 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
547 }
548 $html .= '<div class="os-form-group os-form-select-group ' . esc_attr( $extra_class ) . '">';
549 if ( $label ) {
550 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
551 }
552 $html .= '<select ' . $validate_html . ' name="' . esc_attr( $name ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . '>';
553 if ( isset( $atts['placeholder'] ) && ! empty( $atts['placeholder'] ) ) {
554 $html .= '<option value="">' . esc_html( $atts['placeholder'] ) . '</option>';
555 }
556 if ( is_array( $options ) ) {
557 foreach ( $options as $key => $option ) {
558 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
559 $selected = ( $selected_value == $option['value'] ) ? 'selected' : '';
560 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
561 } else {
562 $value = ( is_string( $key ) ) ? $key : $option;
563 $selected = ( $selected_value == $value ) ? 'selected' : '';
564 $html .= '<option value="' . esc_attr( $value ) . '" ' . $selected . '>' . esc_html( $option ) . '</option>';
565 }
566 }
567 } else {
568 $html .= $options;
569 }
570 if ( $add_value_if_not_present && ! isset( $options[ $selected_value ] ) ) {
571 $html .= '<option value="' . esc_attr( $selected_value ) . '">' . esc_html( $selected_value ) . '</option>';
572 }
573 $html .= '</select>';
574 $html .= '</div>';
575 if ( ! empty( $wrapper_atts ) ) {
576 $html .= '</div>';
577 }
578
579 return $html;
580 }
581
582 public static function time_field( $name, $label, $value = '', $as_period = false ) {
583 if ( strpos( $value, ':' ) === false ) {
584 $formatted_value = OsTimeHelper::minutes_to_hours_and_minutes( $value, false, false );
585 }
586
587 $extra_class = '';
588 if ( $as_period ) {
589 $extra_class = 'as-period';
590 }
591
592 $html = '<div class="os-time-group os-time-input-w ' . $extra_class . '">';
593 if ( $label ) {
594 $html .= '<label for="' . esc_attr( $name ) . '[formatted_value]">' . esc_html( $label ) . '</label>';
595 }
596 $html .= '<div class="os-time-input-fields">';
597 $html .= '<input type="text" placeholder="HH:MM" name="' . esc_attr( $name ) . '[formatted_value]" value="' . esc_attr( $formatted_value ) . '" class="os-form-control os-mask-time"/>';
598
599 // am-pm toggler switch
600 if ( ! OsTimeHelper::is_army_clock() ) {
601 $is_am = ( OsTimeHelper::am_or_pm( $value ) == 'am' );
602 $am_active = ( $is_am ) ? 'active' : '';
603 $pm_active = ( ! $is_am ) ? 'active' : '';
604 $html .= '<input type="hidden" name="' . esc_attr( $name ) . '[ampm]" value="' . esc_attr( OsTimeHelper::am_or_pm( $value ) ) . '" class="ampm-value-hidden-holder"/>';
605 $html .= '<div class="time-ampm-w"><div class="time-ampm-select time-am ' . $am_active . '" data-ampm-value="am">' . esc_html__( 'am', 'latepoint' ) . '</div><div class="time-ampm-select time-pm ' . $pm_active . '" data-ampm-value="pm">' . esc_html__( 'pm', 'latepoint' ) . '</div></div>';
606 }
607
608 $html .= '</div>';
609 $html .= '</div>';
610
611 return $html;
612 }
613
614
615 public static function color_picker( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
616 $extra_class = '';
617 if ( $value != '' ) {
618 $extra_class = ' has-value';
619 }
620 $html = '';
621 if ( ! empty( $wrapper_atts ) ) {
622 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
623 }
624 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-group-transparent os-form-color-picker-group' . $extra_class ) ) . '>';
625 if ( $label ) {
626 $html .= '<label for="' . esc_attr( $name ) . '">' . esc_html( $label ) . '</label>';
627 }
628 $html .= '<div class="latepoint-color-picker-w">';
629 $html .= '<div class="latepoint-color-picker" data-color="' . esc_attr( $value ) . '"></div>';
630 $html .= '<input maxlength="7" type="text" name="' . esc_attr( $name ) . '" placeholder="' . esc_attr__( 'Pick a color', 'latepoint' ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . '/>';
631 $html .= '</div>';
632 $html .= '</div>';
633 if ( ! empty( $wrapper_atts ) ) {
634 $html .= '</div>';
635 }
636
637 return $html;
638 }
639
640 public static function name_to_id( $name, $atts = [] ) {
641 $name = strtolower( preg_replace( '/[^0-9a-zA-Z_]/', '_', $name ) );
642 $name = preg_replace( '/__+/', '_', $name );
643 $name = rtrim( $name, '_' );
644 if ( isset( $atts['add_unique_id'] ) && $atts['add_unique_id'] ) {
645 $name .= '_' . OsUtilHelper::random_text( 'hexdec', 8 );
646 }
647 if ( isset( $atts['add_string_to_id'] ) && $atts['add_string_to_id'] ) {
648 $name .= $atts['add_string_to_id'];
649 }
650
651 return $name;
652 }
653
654
655 // Value: on
656 public static function checkbox_field( $name, $label, $value = '', $is_checked = false, $atts = array(), $wrapper_atts = array(), $off_value = 'off' ) {
657 $html = '';
658 // generate id if not set
659 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
660 $atts['id'] = self::name_to_id( $name, $atts );
661 }
662 if ( ! empty( $wrapper_atts ) ) {
663 $html .= '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
664 }
665 $checked_class = $is_checked ? 'is-checked' : '';
666 if ( isset( $atts['data-toggle-element'] ) ) {
667 $checked_class .= ' has-toggle-element';
668 }
669 if ( isset( $atts['data-inverse-toggle'] ) ) {
670 $checked_class .= ' inverse-toggle';
671 }
672
673 // validations
674 if ( ! empty( $atts['validate'] ) ) {
675 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
676 } else {
677 $validate_html = '';
678 }
679 unset( $atts['validate'] );
680
681 $checked_attr = $is_checked ? 'checked' : '';
682 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-checkbox-group ' . $checked_class ) ) . '>';
683 if ( $label ) {
684 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">';
685 }
686 if ( $off_value !== false ) {
687 $html .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $off_value ) . '"/>';
688 }
689 $html .= '<input type="checkbox" ' . $validate_html . ' name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . $checked_attr . ' ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-checkbox' ] ) . '/>';
690 if ( $label ) {
691 $html .= '<div>' . wp_kses_post( $label ) . '</div>' . '</label>';
692 }
693 $html .= '</div>';
694 if ( ! empty( $wrapper_atts ) ) {
695 $html .= '</div>';
696 }
697
698 return $html;
699 }
700
701 /**
702 * @param string $name
703 * @param string $label
704 * @param string $value
705 * @param array $atts
706 * @param array $wrapper_atts
707 * @param array $form_group_atts
708 *
709 * @return string
710 */
711 public static function money_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
712 $input_class = 'os-mask-money';
713 if ( isset( $atts['class'] ) ) {
714 $input_class .= ' ' . $atts['class'];
715 }
716 $atts = array_merge( $atts, [ 'class' => $input_class, 'inputmode' => 'decimal' ] );
717 $value = OsMoneyHelper::to_money_field_format( $value );
718
719 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
720 }
721
722 /**
723 * @param string $name
724 * @param string $label
725 * @param string $value
726 * @param array $atts
727 * @param array $wrapper_atts
728 *
729 * @return string
730 *
731 * Generates a text input field
732 */
733 public static function text_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
734 $extra_class = ' os-form-group-transparent';
735 if ( isset( $atts['theme'] ) ) {
736 switch ( $atts['theme'] ) {
737 case 'bordered':
738 $extra_class = ' os-form-group-bordered';
739 break;
740 case 'right-aligned':
741 $extra_class = ' os-form-group-right-aligned';
742 break;
743 case 'simple':
744 $extra_class = ' os-form-group-simple';
745 unset( $atts['theme'] );
746 break;
747 }
748 }
749 if ( isset( $form_group_atts['class'] ) ) {
750 $extra_class .= ' ' . $form_group_atts['class'] . ' ';
751 unset( $form_group_atts['class'] );
752 }
753 // generate id if not set
754 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
755 $atts['id'] = self::name_to_id( $name, $atts );
756 }
757 if ( $value != '' ) {
758 $extra_class .= ' has-value';
759 }
760 if ( empty( $label ) ) {
761 $extra_class .= ' no-label';
762 }
763
764 // validations
765 if ( ! empty( $atts['validate'] ) ) {
766 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
767 } else {
768 $validate_html = '';
769 }
770 unset( $atts['validate'] );
771 $html = '';
772 if ( ! empty( $wrapper_atts ) ) {
773 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
774 }
775 $html .= '<div class ="os-form-group os-form-textfield-group' . esc_attr( $extra_class ) . '" ' . self::atts_string_from_array( $form_group_atts ) . '>';
776 $placeholder = ( ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
777 if ( $label ) {
778 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
779 }
780 $input_class = 'os-form-control';
781 $html .= '<input ' . $validate_html . ' type="' . esc_attr( ( $atts['type'] ?? 'text' ) ) . '" placeholder="' . esc_attr( $placeholder ) . '" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => $input_class ] ) . '/>';
782 $html .= '</div>';
783 if ( ! empty( $wrapper_atts ) ) {
784 $html .= '</div>';
785 }
786
787 return $html;
788 }
789
790 /**
791 * @param string $name
792 * @param string $label
793 * @param string $value
794 * @param array $atts
795 * @param array $wrapper_atts
796 *
797 * @return string
798 *
799 * Generates a telephone text input field
800 */
801 public static function phone_number_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
802 // Remain standards compliant
803 $atts['type'] = 'tel';
804 $atts['format'] = '[0-9]*';
805
806 $atts['class'] = $atts['class'] ?? '';
807 if ( strpos( $atts['class'], 'os-mask-phone' ) === false ) {
808 $atts['class'] .= ' os-mask-phone';
809 }
810 $form_group_atts['class'] = ( $form_group_atts['class'] ?? '' ) . ' os-form-phonefield-group';
811
812 $atts['validate'] = empty( $atts['validate'] ) ? [] : $atts['validate'];
813 if ( OsSettingsHelper::is_on( 'validate_phone_number' ) && in_array( 'presence', $atts['validate'] ) ) {
814 // validate phone if the field is required
815 $atts['validate'][] = 'phone';
816 }
817
818 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
819 }
820
821
822 /**
823 * @param string $name
824 * @param string $placeholder
825 * @param string $value
826 *
827 * @return string
828 *
829 * Generates quantity input field
830 */
831 public static function quantity_field( $name, $placeholder, $value = '' ): string {
832 return '<div class="item-quantity-selector-w">
833 <div class="item-quantity-selector item-quantity-selector-minus" data-sign="minus"></div>
834 <input type="text" name="' . esc_attr( $name ) . '" class="item-quantity-selector-input" value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $placeholder ) . '">
835 <div class="item-quantity-selector item-quantity-selector-plus" data-sign="plus"></div>
836 </div>';
837 }
838
839 /**
840 * @param string $name
841 * @param string $label
842 * @param string $value
843 * @param int|float|null $min
844 * @param int|float|null $max
845 * @param array $atts
846 * @param array $wrapper_atts
847 *
848 * @return string
849 *
850 * Generates a numeric text input field
851 */
852 public static function number_field( $name, $label, $value = '', $min = null, $max = null, $atts = [], $wrapper_atts = [], $form_group_atts = [] ): string {
853 $atts['type'] = 'number';
854 if ( is_numeric( $min ) ) {
855 $atts['min'] = $min;
856 }
857 if ( is_numeric( $max ) && ( ! is_numeric( $min ) || $max >= $min ) ) {
858 $atts['max'] = $max;
859 }
860
861 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
862 }
863
864 public static function password_field( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
865 $extra_class = ' os-form-group-transparent';
866 if ( isset( $atts['theme'] ) ) {
867 switch ( $atts['theme'] ) {
868 case 'bordered':
869 $extra_class = ' os-form-group-bordered';
870 break;
871 case 'right-aligned':
872 $extra_class = ' os-form-group-right-aligned';
873 break;
874 case 'simple':
875 $extra_class = ' os-form-group-simple';
876 unset( $atts['theme'] );
877 break;
878 }
879 }
880 // generate id if not set
881 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
882 $atts['id'] = self::name_to_id( $name, $atts );
883 }
884 if ( $value != '' ) {
885 $extra_class .= ' has-value';
886 }
887 if ( empty( $label ) ) {
888 $extra_class .= ' no-label';
889 }
890 $html = '';
891 if ( ! empty( $wrapper_atts ) ) {
892 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
893 }
894 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-textfield-group' . $extra_class ) ) . '>';
895 $placeholder = ( isset( $atts['placeholder'] ) && ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
896 if ( $label ) {
897 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
898 }
899 $html .= '<input type="password" placeholder="' . esc_attr( $placeholder ) . '" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . '/>';
900 $html .= '</div>';
901 if ( ! empty( $wrapper_atts ) ) {
902 $html .= '</div>';
903 }
904
905 return $html;
906 }
907
908 public static function hidden_field( $name, $value, $atts = array() ) {
909 // generate id if not set
910 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
911 $atts['id'] = self::name_to_id( $name, $atts );
912 }
913 $html = '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts ) . '/>';
914
915 return $html;
916 }
917
918
919 public static function radio_field( $name, $value, $checked = false, $atts = array() ) {
920 // generate id if not set
921 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
922 $atts['id'] = self::name_to_id( $name, $atts );
923 }
924 $checked_html = $checked ? 'checked' : '';
925 $html = '<input ' . $checked_html . ' type="radio" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts ) . '/>';
926
927 return $html;
928 }
929
930
931 public static function button( $name, $label, $type = 'button', $atts = array(), $icon = false ) {
932 // generate id if not set
933 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
934 $atts['id'] = self::name_to_id( $name, $atts );
935 }
936 $html = '<div class="os-form-group">';
937 if ( $icon ) {
938 $label = '<i class="latepoint-icon ' . esc_attr( $icon ) . '"></i><span>' . $label . '</span>';
939 }
940 $html .= '<button type="' . esc_attr( $type ) . '" name="' . esc_attr( $name ) . '" ' . self::atts_string_from_array( $atts ) . '>' . esc_html( $label ) . '</button>';
941 $html .= '</div>';
942
943 return $html;
944 }
945
946 public static function otp_code_field( string $name ) : string {
947 return self::text_field($name, '', '', ['class' => 'os-otp-code-field required','autocomplete' => 'one-time-code', 'inputmode' => 'numeric', 'pattern' => '[0-9]*', 'maxlength' => '6', 'theme' => 'simple', 'placeholder' => __('Code', 'latepoint')]);
948 }
949 }