PluginProbe ʕ •ᴥ•ʔ
LatePoint – Calendar Booking Plugin for Appointments and Events / 5.2.11
LatePoint – Calendar Booking Plugin for Appointments and Events v5.2.11
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 3 months ago agent_helper.php 3 months ago analytics_helper.php 4 months ago auth_helper.php 3 months ago blocks_helper.php 3 months ago booking_helper.php 3 months ago bricks_helper.php 3 months ago bundles_helper.php 3 months ago calendar_helper.php 3 months ago carts_helper.php 3 months ago connector_helper.php 3 months ago csv_helper.php 3 months ago customer_helper.php 3 months ago customer_import_helper.php 3 months ago database_helper.php 3 months ago debug_helper.php 3 months ago defaults_helper.php 3 months ago elementor_helper.php 3 months ago email_helper.php 3 months ago encrypt_helper.php 3 months ago events_helper.php 3 months ago form_helper.php 3 months ago icalendar_helper.php 3 months ago image_helper.php 3 months ago invoices_helper.php 3 months ago license_helper.php 3 months ago location_helper.php 3 months ago marketing_systems_helper.php 3 months ago meeting_systems_helper.php 3 months ago menu_helper.php 3 months ago meta_helper.php 3 months ago migrations_helper.php 3 months ago money_helper.php 3 months ago notifications_helper.php 3 months ago nps_survey_helper.php 3 months ago order_intent_helper.php 3 months ago orders_helper.php 3 months ago otp_helper.php 3 months ago pages_helper.php 3 months ago params_helper.php 3 months ago payments_helper.php 3 months ago price_breakdown_helper.php 3 months ago process_jobs_helper.php 3 months ago processes_helper.php 3 months ago replacer_helper.php 3 months ago resource_helper.php 3 months ago roles_helper.php 3 months ago router_helper.php 3 months ago service_helper.php 3 months ago sessions_helper.php 3 months ago settings_helper.php 3 months ago short_links_systems_helper.php 3 months ago shortcodes_helper.php 3 months ago sms_helper.php 3 months ago steps_helper.php 3 months ago stripe_connect_helper.php 3 months ago styles_helper.php 3 months ago support_topics_helper.php 3 months ago time_helper.php 3 months ago timeline_helper.php 3 months ago transaction_helper.php 3 months ago transaction_intent_helper.php 3 months ago util_helper.php 3 months ago version_specific_updates_helper.php 3 months ago whatsapp_helper.php 3 months ago work_periods_helper.php 3 months ago wp_datetime.php 3 months ago wp_user_helper.php 3 months ago
form_helper.php
986 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>' . wp_kses_post( $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(
264 $content,
265 $id,
266 [
267 'textarea_name' => $name,
268 'media_buttons' => false,
269 'editor_height' => $editor_height,
270 ]
271 );
272 echo '</div>';
273 }
274
275
276 public static function textarea_field( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
277 $extra_class = ' os-form-group-transparent';
278 if ( isset( $atts['theme'] ) ) {
279 switch ( $atts['theme'] ) {
280 case 'bordered':
281 $extra_class = ' os-form-group-bordered';
282 break;
283 case 'right-aligned':
284 $extra_class = ' os-form-group-right-aligned';
285 break;
286 case 'simple':
287 $extra_class = ' os-form-group-simple';
288 unset( $atts['theme'] );
289 break;
290 }
291 }
292 // generate id if not set
293 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
294 $atts['id'] = self::name_to_id( $name, $atts );
295 }
296 if ( $value ) {
297 $extra_class .= ' has-value';
298 }
299 if ( empty( $label ) ) {
300 $extra_class .= ' no-label';
301 }
302
303 // validations
304 if ( ! empty( $atts['validate'] ) ) {
305 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
306 } else {
307 $validate_html = '';
308 }
309 unset( $atts['validate'] );
310 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
311 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-textfield-group os-form-textarea-group' . $extra_class ) ) . '>';
312 if ( $label ) {
313 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . $label . '</label>';
314 }
315 $placeholder = ( ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
316 $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>';
317 $html .= '</div>';
318 $html .= '</div>';
319
320 return $html;
321 }
322
323 public static function service_selector_adder_field( $name, $label, $add_label, $options = array(), $value = '', $atts = array(), $wrapper_atts = array() ) {
324 $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' ] ) . '>';
325 if ( $label ) {
326 $html .= '<label for="' . $name . '">' . $label . '</label>';
327 }
328 $html .= '<div class="selector-adder-w">';
329 $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' ) ) . '">';
330 foreach ( $options as $option ) {
331 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
332 $selected = ( $value == $option['value'] ) ? 'selected' : '';
333 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
334 }
335 }
336 $html .= '</select>';
337 $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>';
338 $html .= '</div>';
339 $html .= '</div>';
340
341 return $html;
342 }
343
344 public static function location_selector_adder_field( $name, $label, $add_label, $options = array(), $value = '', $atts = array(), $wrapper_atts = array() ) {
345 $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' ] ) . '>';
346 if ( $label ) {
347 $html .= '<label for="' . $name . '">' . $label . '</label>';
348 }
349 $html .= '<div class="selector-adder-w">';
350 $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' ) ) . '">';
351 foreach ( $options as $option ) {
352 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
353 $selected = ( $value == $option['value'] ) ? 'selected' : '';
354 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
355 }
356 }
357 $html .= '</select>';
358 $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>';
359 $html .= '</div>';
360 $html .= '</div>';
361
362 return $html;
363 }
364
365 public static function model_options_for_multi_select( $model_name ) {
366 $options = [];
367 switch ( $model_name ) {
368 case 'service':
369 case 'OsServiceModel':
370 $service = new OsServiceModel();
371 $services = $service->get_results_as_models();
372 if ( $services ) {
373 foreach ( $services as $service ) {
374 $options[] = [
375 'value' => $service->id,
376 'label' => $service->name,
377 ];
378 }
379 }
380 break;
381 case 'agent':
382 case 'OsAgentModel':
383 $agent = new OsAgentModel();
384 $agents = $agent->get_results_as_models();
385 if ( $agents ) {
386 foreach ( $agents as $agent ) {
387 $options[] = [
388 'value' => $agent->id,
389 'label' => $agent->full_name,
390 ];
391 }
392 }
393 break;
394 case 'customer':
395 case 'OsCustomerModel':
396 $customer = new OsCustomerModel();
397 $customers = $customer->get_results_as_models();
398 if ( $customers ) {
399 foreach ( $customers as $customer ) {
400 $options[] = [
401 'value' => $customer->id,
402 'label' => $customer->full_name,
403 ];
404 }
405 }
406 break;
407
408 case 'bundle':
409 case 'OsBundleModel':
410 if ( $bundles = ( new OsBundleModel() )->get_results_as_models() ) {
411 foreach ( $bundles as $bundle ) {
412 $options[] = [
413 'value' => $bundle->id,
414 'label' => $bundle->name,
415 ];
416 }
417 }
418
419 break;
420 }
421
422 /**
423 * Returns an array of options based on model name/mnemonic, formatted for multi-select fields
424 *
425 * @param {array} $options Array of model options to filter
426 * @param {string} $model_name Class name or mnemonic used to determine resultant options
427 *
428 * @returns {array} Filtered array of model options
429 * @since 4.4.0
430 * @hook latepoint_model_options_for_multi_select
431 *
432 */
433 return apply_filters( 'latepoint_model_options_for_multi_select', $options, $model_name );
434 }
435
436 public static function date_picker_field( string $name, string $formatted_value = '', string $raw_value = '', array $atts = [] ): string {
437 $html = '<div data-single-date="yes" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-date-range-picker' ] ) . '>
438 <span class="range-picker-value">' . esc_html( $formatted_value ) . '</span>
439 <i class="latepoint-icon latepoint-icon-chevron-down"></i>
440 <input class="os-datepicker-date-from" type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $raw_value ) . '"/>
441 </div>';
442
443 return $html;
444 }
445
446 public static function multi_select_field( $name, $label = false, $options = [], $selected_values = [], $atts = [], $wrapper_atts = [] ) {
447 $html = '';
448 if ( ! $selected_values ) {
449 $selected_values = [];
450 }
451 // generate id if not set
452 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
453 $atts['id'] = self::name_to_id( $name, $atts );
454 }
455 if ( ! empty( $wrapper_atts ) ) {
456 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
457 }
458 $html .= '<div class="os-form-group os-form-select-group os-form-group-transparent">';
459 if ( $label ) {
460 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
461 }
462 $html .= '<select " ' . self::atts_string_from_array( $atts, [ 'class' => 'os-late-select' ] ) . ' data-placeholder="' . esc_attr__( 'Click to select...', 'latepoint' ) . '" multiple>';
463 foreach ( $options as $key => $option ) {
464 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
465 $selected = ( $selected_values && is_array( $selected_values ) && in_array( $option['value'], $selected_values ) ) ? 'selected="selected"' : '';
466 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
467 } else {
468 $value = ( is_string( $key ) ) ? $key : $option;
469 $selected = ( $selected_values && in_array( $value, $selected_values ) ) ? 'selected' : '';
470 $html .= '<option value="' . esc_attr( $value ) . '" ' . $selected . '>' . esc_html( $option ) . '</option>';
471 }
472 }
473 $html .= '</select>';
474 $html .= OsFormHelper::hidden_field( $name, is_array( $selected_values ) ? implode( ',', $selected_values ) : $selected_values, [ 'skip_id' => true ] );
475 $html .= '</div>';
476 if ( ! empty( $wrapper_atts ) ) {
477 $html .= '</div>';
478 }
479
480 return $html;
481 }
482
483
484 public static function multi_checkbox_field( $name, $label = false, $options = [], $selected_values = [], $atts = [], $wrapper_atts = [] ) {
485 $html = '';
486
487 if ( ! empty( $wrapper_atts ) ) {
488 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
489 }
490
491 $html .= '<div class="os-form-group os-form-multiselect-group os-form-group-transparent">';
492
493 if ( $label ) {
494 $html .= '<label>' . esc_html( $label ) . '</label>';
495 }
496
497 foreach ( $options as $key => $option ) {
498 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
499 $value = $option['value'];
500 $option_label = $option['label'];
501 } else {
502 $value = ( is_string( $key ) ) ? $key : $option;
503 $option_label = $option;
504 }
505
506 $checkbox_id = self::name_to_id( $name . '_' . $value );
507 $is_checked = in_array( $value, $selected_values );
508
509 $html .= self::checkbox_field(
510 $name . '[]',
511 $option_label,
512 $value,
513 $is_checked,
514 [ 'id' => $checkbox_id ] + $atts,
515 [ 'class' => 'checkbox-option-wrapper' ],
516 ''
517 );
518 }
519
520 $html .= '</div>';
521
522 if ( ! empty( $wrapper_atts ) ) {
523 $html .= '</div>';
524 }
525
526 return $html;
527 }
528
529 public static function select_field( $name, $label, $options = array(), $selected_value = '', $atts = array(), $wrapper_atts = array(), $add_value_if_not_present = false ) {
530 $extra_class = ' os-form-group-transparent';
531 if ( isset( $atts['theme'] ) ) {
532 switch ( $atts['theme'] ) {
533 case 'bordered':
534 $extra_class = ' os-form-group-bordered';
535 break;
536 case 'right-aligned':
537 $extra_class = ' os-form-group-right-aligned';
538 break;
539 case 'simple':
540 $extra_class = ' os-form-group-simple';
541 unset( $atts['theme'] );
542 break;
543 }
544 }
545 $html = '';
546 // generate id if not set
547 if ( ! $atts ) {
548 $atts = [];
549 }
550 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
551 $atts['id'] = self::name_to_id( $name, $atts );
552 }
553
554 // validations
555 if ( ! empty( $atts['validate'] ) ) {
556 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
557 } else {
558 $validate_html = '';
559 }
560
561 if ( ! empty( $wrapper_atts ) ) {
562 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
563 }
564 $html .= '<div class="os-form-group os-form-select-group ' . esc_attr( $extra_class ) . '">';
565 if ( $label ) {
566 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
567 }
568 $html .= '<select ' . $validate_html . ' name="' . esc_attr( $name ) . '" ' . self::atts_string_from_array( $atts, [ 'class' => 'os-form-control' ] ) . '>';
569 if ( isset( $atts['placeholder'] ) && ! empty( $atts['placeholder'] ) ) {
570 $html .= '<option value="">' . esc_html( $atts['placeholder'] ) . '</option>';
571 }
572 if ( is_array( $options ) ) {
573 foreach ( $options as $key => $option ) {
574 if ( isset( $option['value'] ) && isset( $option['label'] ) ) {
575 $selected = ( $selected_value == $option['value'] ) ? 'selected' : '';
576 $html .= '<option value="' . esc_attr( $option['value'] ) . '" ' . $selected . '>' . esc_html( $option['label'] ) . '</option>';
577 } else {
578 $value = ( is_string( $key ) ) ? $key : $option;
579 $selected = ( $selected_value == $value ) ? 'selected' : '';
580 $html .= '<option value="' . esc_attr( $value ) . '" ' . $selected . '>' . esc_html( $option ) . '</option>';
581 }
582 }
583 } else {
584 $html .= $options;
585 }
586 if ( $add_value_if_not_present && ! isset( $options[ $selected_value ] ) ) {
587 $html .= '<option value="' . esc_attr( $selected_value ) . '">' . esc_html( $selected_value ) . '</option>';
588 }
589 $html .= '</select>';
590 $html .= '</div>';
591 if ( ! empty( $wrapper_atts ) ) {
592 $html .= '</div>';
593 }
594
595 return $html;
596 }
597
598 public static function time_field( $name, $label, $value = '', $as_period = false ) {
599 if ( strpos( $value, ':' ) === false ) {
600 $formatted_value = OsTimeHelper::minutes_to_hours_and_minutes( $value, false, false );
601 }
602
603 $extra_class = '';
604 if ( $as_period ) {
605 $extra_class = 'as-period';
606 }
607
608 $html = '<div class="os-time-group os-time-input-w ' . $extra_class . '">';
609 if ( $label ) {
610 $html .= '<label for="' . esc_attr( $name ) . '[formatted_value]">' . esc_html( $label ) . '</label>';
611 }
612 $html .= '<div class="os-time-input-fields">';
613 $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"/>';
614
615 // am-pm toggler switch
616 if ( ! OsTimeHelper::is_army_clock() ) {
617 $is_am = ( OsTimeHelper::am_or_pm( $value ) == 'am' );
618 $am_active = ( $is_am ) ? 'active' : '';
619 $pm_active = ( ! $is_am ) ? 'active' : '';
620 $html .= '<input type="hidden" name="' . esc_attr( $name ) . '[ampm]" value="' . esc_attr( OsTimeHelper::am_or_pm( $value ) ) . '" class="ampm-value-hidden-holder"/>';
621 $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>';
622 }
623
624 $html .= '</div>';
625 $html .= '</div>';
626
627 return $html;
628 }
629
630
631 public static function color_picker( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
632 $extra_class = '';
633 if ( $value != '' ) {
634 $extra_class = ' has-value';
635 }
636 $html = '';
637 if ( ! empty( $wrapper_atts ) ) {
638 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
639 }
640 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-group-transparent os-form-color-picker-group' . $extra_class ) ) . '>';
641 if ( $label ) {
642 $html .= '<label for="' . esc_attr( $name ) . '">' . esc_html( $label ) . '</label>';
643 }
644 $html .= '<div class="latepoint-color-picker-w">';
645 $html .= '<div class="latepoint-color-picker" data-color="' . esc_attr( $value ) . '"></div>';
646 $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' ] ) . '/>';
647 $html .= '</div>';
648 $html .= '</div>';
649 if ( ! empty( $wrapper_atts ) ) {
650 $html .= '</div>';
651 }
652
653 return $html;
654 }
655
656 public static function name_to_id( $name, $atts = [] ) {
657 $name = strtolower( preg_replace( '/[^0-9a-zA-Z_]/', '_', $name ) );
658 $name = preg_replace( '/__+/', '_', $name );
659 $name = rtrim( $name, '_' );
660 if ( isset( $atts['add_unique_id'] ) && $atts['add_unique_id'] ) {
661 $name .= '_' . OsUtilHelper::random_text( 'hexdec', 8 );
662 }
663 if ( isset( $atts['add_string_to_id'] ) && $atts['add_string_to_id'] ) {
664 $name .= $atts['add_string_to_id'];
665 }
666
667 return $name;
668 }
669
670
671 // Value: on
672 public static function checkbox_field( $name, $label, $value = '', $is_checked = false, $atts = array(), $wrapper_atts = array(), $off_value = 'off' ) {
673 $html = '';
674 // generate id if not set
675 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
676 $atts['id'] = self::name_to_id( $name, $atts );
677 }
678 if ( ! empty( $wrapper_atts ) ) {
679 $html .= '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
680 }
681 $checked_class = $is_checked ? 'is-checked' : '';
682 if ( isset( $atts['data-toggle-element'] ) ) {
683 $checked_class .= ' has-toggle-element';
684 }
685 if ( isset( $atts['data-inverse-toggle'] ) ) {
686 $checked_class .= ' inverse-toggle';
687 }
688
689 // validations
690 if ( ! empty( $atts['validate'] ) ) {
691 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
692 } else {
693 $validate_html = '';
694 }
695 unset( $atts['validate'] );
696
697 $checked_attr = $is_checked ? 'checked' : '';
698 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-checkbox-group ' . $checked_class ) ) . '>';
699 if ( $label ) {
700 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">';
701 }
702 if ( $off_value !== false ) {
703 $html .= '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $off_value ) . '"/>';
704 }
705 $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' ] ) . '/>';
706 if ( $label ) {
707 $html .= '<div>' . wp_kses_post( $label ) . '</div>';
708 $html .= '</label>';
709 }
710 $html .= '</div>';
711 if ( ! empty( $wrapper_atts ) ) {
712 $html .= '</div>';
713 }
714
715 return $html;
716 }
717
718 /**
719 * @param string $name
720 * @param string $label
721 * @param string $value
722 * @param array $atts
723 * @param array $wrapper_atts
724 * @param array $form_group_atts
725 *
726 * @return string
727 */
728 public static function money_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
729 $input_class = 'os-mask-money';
730 if ( isset( $atts['class'] ) ) {
731 $input_class .= ' ' . $atts['class'];
732 }
733 $atts = array_merge(
734 $atts,
735 [
736 'class' => $input_class,
737 'inputmode' => 'decimal',
738 ]
739 );
740 $value = OsMoneyHelper::to_money_field_format( $value );
741
742 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
743 }
744
745 /**
746 * @param string $name
747 * @param string $label
748 * @param string $value
749 * @param array $atts
750 * @param array $wrapper_atts
751 *
752 * @return string
753 *
754 * Generates a text input field
755 */
756 public static function text_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
757 $extra_class = ' os-form-group-transparent';
758 if ( isset( $atts['theme'] ) ) {
759 switch ( $atts['theme'] ) {
760 case 'bordered':
761 $extra_class = ' os-form-group-bordered';
762 break;
763 case 'right-aligned':
764 $extra_class = ' os-form-group-right-aligned';
765 break;
766 case 'simple':
767 $extra_class = ' os-form-group-simple';
768 unset( $atts['theme'] );
769 break;
770 }
771 }
772 if ( isset( $form_group_atts['class'] ) ) {
773 $extra_class .= ' ' . $form_group_atts['class'] . ' ';
774 unset( $form_group_atts['class'] );
775 }
776 // generate id if not set
777 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
778 $atts['id'] = self::name_to_id( $name, $atts );
779 }
780 if ( $value != '' ) {
781 $extra_class .= ' has-value';
782 }
783 if ( empty( $label ) ) {
784 $extra_class .= ' no-label';
785 }
786
787 // validations
788 if ( ! empty( $atts['validate'] ) ) {
789 $validate_html = 'data-os-validate="' . esc_attr( implode( ' ', $atts['validate'] ) ) . '"';
790 } else {
791 $validate_html = '';
792 }
793 unset( $atts['validate'] );
794 $html = '';
795 if ( ! empty( $wrapper_atts ) ) {
796 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
797 }
798 $html .= '<div class ="os-form-group os-form-textfield-group' . esc_attr( $extra_class ) . '" ' . self::atts_string_from_array( $form_group_atts ) . '>';
799 $placeholder = ( ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
800 if ( $label ) {
801 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
802 }
803 $input_class = 'os-form-control';
804 $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 ] ) . '/>';
805 $html .= '</div>';
806 if ( ! empty( $wrapper_atts ) ) {
807 $html .= '</div>';
808 }
809
810 return $html;
811 }
812
813 /**
814 * @param string $name
815 * @param string $label
816 * @param string $value
817 * @param array $atts
818 * @param array $wrapper_atts
819 *
820 * @return string
821 *
822 * Generates a telephone text input field
823 */
824 public static function phone_number_field( $name, $label, $value = '', $atts = [], $wrapper_atts = [], $form_group_atts = [] ) {
825 // Remain standards compliant
826 $atts['type'] = 'tel';
827 $atts['format'] = '[0-9]*';
828
829 $atts['class'] = $atts['class'] ?? '';
830 if ( strpos( $atts['class'], 'os-mask-phone' ) === false ) {
831 $atts['class'] .= ' os-mask-phone';
832 }
833 $form_group_atts['class'] = ( $form_group_atts['class'] ?? '' ) . ' os-form-phonefield-group';
834
835 $atts['validate'] = empty( $atts['validate'] ) ? [] : $atts['validate'];
836 if ( OsSettingsHelper::is_on( 'validate_phone_number' ) && in_array( 'presence', $atts['validate'] ) ) {
837 // validate phone if the field is required
838 $atts['validate'][] = 'phone';
839 }
840
841 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
842 }
843
844
845 /**
846 * @param string $name
847 * @param string $placeholder
848 * @param string $value
849 *
850 * @return string
851 *
852 * Generates quantity input field
853 */
854 public static function quantity_field( $name, $placeholder, $value = '' ): string {
855 return '<div class="item-quantity-selector-w">
856 <div class="item-quantity-selector item-quantity-selector-minus" data-sign="minus"></div>
857 <input type="text" name="' . esc_attr( $name ) . '" class="item-quantity-selector-input" value="' . esc_attr( $value ) . '" placeholder="' . esc_attr( $placeholder ) . '">
858 <div class="item-quantity-selector item-quantity-selector-plus" data-sign="plus"></div>
859 </div>';
860 }
861
862 /**
863 * @param string $name
864 * @param string $label
865 * @param string $value
866 * @param int|float|null $min
867 * @param int|float|null $max
868 * @param array $atts
869 * @param array $wrapper_atts
870 *
871 * @return string
872 *
873 * Generates a numeric text input field
874 */
875 public static function number_field( $name, $label, $value = '', $min = null, $max = null, $atts = [], $wrapper_atts = [], $form_group_atts = [] ): string {
876 $atts['type'] = 'number';
877 if ( is_numeric( $min ) ) {
878 $atts['min'] = $min;
879 }
880 if ( is_numeric( $max ) && ( ! is_numeric( $min ) || $max >= $min ) ) {
881 $atts['max'] = $max;
882 }
883
884 return self::text_field( $name, $label, $value, $atts, $wrapper_atts, $form_group_atts );
885 }
886
887 public static function password_field( $name, $label, $value = '', $atts = array(), $wrapper_atts = array() ) {
888 $extra_class = ' os-form-group-transparent';
889 if ( isset( $atts['theme'] ) ) {
890 switch ( $atts['theme'] ) {
891 case 'bordered':
892 $extra_class = ' os-form-group-bordered';
893 break;
894 case 'right-aligned':
895 $extra_class = ' os-form-group-right-aligned';
896 break;
897 case 'simple':
898 $extra_class = ' os-form-group-simple';
899 unset( $atts['theme'] );
900 break;
901 }
902 }
903 // generate id if not set
904 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
905 $atts['id'] = self::name_to_id( $name, $atts );
906 }
907 if ( $value != '' ) {
908 $extra_class .= ' has-value';
909 }
910 if ( empty( $label ) ) {
911 $extra_class .= ' no-label';
912 }
913 $html = '';
914 if ( ! empty( $wrapper_atts ) ) {
915 $html = '<div ' . self::atts_string_from_array( $wrapper_atts ) . '>';
916 }
917 $html .= '<div ' . self::atts_string_from_array( array( 'class' => 'os-form-group os-form-textfield-group' . $extra_class ) ) . '>';
918 $placeholder = ( isset( $atts['placeholder'] ) && ! empty( $atts['placeholder'] ) ) ? $atts['placeholder'] : $label;
919 if ( $label ) {
920 $html .= '<label for="' . esc_attr( $atts['id'] ) . '">' . esc_html( $label ) . '</label>';
921 }
922 $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' ] ) . '/>';
923 $html .= '</div>';
924 if ( ! empty( $wrapper_atts ) ) {
925 $html .= '</div>';
926 }
927
928 return $html;
929 }
930
931 public static function hidden_field( $name, $value, $atts = array() ) {
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 = '<input type="hidden" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts ) . '/>';
937
938 return $html;
939 }
940
941
942 public static function radio_field( $name, $value, $checked = false, $atts = array() ) {
943 // generate id if not set
944 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
945 $atts['id'] = self::name_to_id( $name, $atts );
946 }
947 $checked_html = $checked ? 'checked' : '';
948 $html = '<input ' . $checked_html . ' type="radio" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '" ' . self::atts_string_from_array( $atts ) . '/>';
949
950 return $html;
951 }
952
953
954 public static function button( $name, $label, $type = 'button', $atts = array(), $icon = false ) {
955 // generate id if not set
956 if ( ! isset( $atts['id'] ) && ! isset( $atts['skip_id'] ) ) {
957 $atts['id'] = self::name_to_id( $name, $atts );
958 }
959 $html = '<div class="os-form-group">';
960 if ( $icon ) {
961 $label = '<i class="latepoint-icon ' . esc_attr( $icon ) . '"></i><span>' . $label . '</span>';
962 }
963 $html .= '<button type="' . esc_attr( $type ) . '" name="' . esc_attr( $name ) . '" ' . self::atts_string_from_array( $atts ) . '>' . esc_html( $label ) . '</button>';
964 $html .= '</div>';
965
966 return $html;
967 }
968
969 public static function otp_code_field( string $name ): string {
970 return self::text_field(
971 $name,
972 '',
973 '',
974 [
975 'class' => 'os-otp-code-field required',
976 'autocomplete' => 'one-time-code',
977 'inputmode' => 'numeric',
978 'pattern' => '[0-9]*',
979 'maxlength' => '6',
980 'theme' => 'simple',
981 'placeholder' => __( 'Code', 'latepoint' ),
982 ]
983 );
984 }
985 }
986