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