PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.2.5
Pods – Custom Content Types and Fields v3.2.5
trunk 1.14.8 2.7.31.3 2.8.23.3 2.9.19.3 3.0.10.3 3.1.4.1 3.2.0 3.2.1 3.2.1.1 3.2.2 3.2.4 3.2.5 3.2.6 3.2.7 3.2.7.1 3.2.8 3.2.8.1 3.2.8.2 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9
pods / classes / fields / number.php
pods / classes / fields Last commit date
avatar.php 3 years ago boolean.php 3 years ago code.php 2 years ago color.php 3 years ago comment.php 4 years ago currency.php 3 years ago date.php 2 years ago datetime.php 2 years ago email.php 3 years ago file.php 1 year ago heading.php 2 years ago html.php 2 years ago link.php 3 years ago number.php 2 years ago oembed.php 2 years ago paragraph.php 2 years ago password.php 3 years ago phone.php 3 years ago pick.php 1 year ago slug.php 3 years ago taxonomy.php 4 years ago text.php 2 years ago time.php 2 years ago website.php 3 years ago wysiwyg.php 2 years ago
number.php
500 lines
1 <?php
2
3 /**
4 * @package Pods\Fields
5 */
6 class PodsField_Number extends PodsField {
7
8 /**
9 * {@inheritdoc}
10 */
11 public static $group = 'Number';
12
13 /**
14 * {@inheritdoc}
15 */
16 public static $type = 'number';
17
18 /**
19 * {@inheritdoc}
20 */
21 public static $label = 'Plain Number';
22
23 /**
24 * {@inheritdoc}
25 */
26 public static $prepare = '%d';
27
28 /**
29 * {@inheritdoc}
30 */
31 public function setup() {
32
33 static::$group = __( 'Number', 'pods' );
34 static::$label = __( 'Plain Number', 'pods' );
35 }
36
37 /**
38 * {@inheritdoc}
39 */
40 public function options() {
41
42 $options = array(
43 static::$type . '_format_type' => array(
44 'label' => __( 'Input Type', 'pods' ),
45 'default' => 'number',
46 'type' => 'pick',
47 'data' => array(
48 'number' => __( 'Freeform Number', 'pods' ),
49 'slider' => __( 'Slider', 'pods' ),
50 ),
51 'pick_format_single' => 'dropdown',
52 'pick_show_select_text' => 0,
53 'dependency' => true,
54 ),
55 static::$type . '_format' => array(
56 'label' => __( 'Number Format', 'pods' ),
57 'default' => apply_filters( 'pods_form_ui_field_number_format_default', 'i18n' ),
58 'type' => 'pick',
59 'data' => array(
60 'i18n' => __( 'Localized Default', 'pods' ),
61 '9,999.99' => '1,234.00',
62 '9999.99' => '1234.00',
63 '9.999,99' => '1.234,00',
64 '9999,99' => '1234,00',
65 '9 999,99' => '1 234,00',
66 '9\'999.99' => '1\'234.00',
67 ),
68 'pick_format_single' => 'dropdown',
69 'pick_show_select_text' => 0,
70 ),
71 static::$type . '_decimals' => array(
72 'label' => __( 'Decimals', 'pods' ),
73 'default' => 0,
74 'type' => 'number',
75 'dependency' => true,
76 'help' => __( 'Set to a positive number to enable decimals. The upper limit in the database for this field is 30 decimals.', 'pods' ),
77 ),
78 static::$type . '_format_soft' => array(
79 'label' => __( 'Soft Formatting', 'pods' ),
80 'help' => __( 'Remove trailing decimals (0)', 'pods' ),
81 'default' => 0,
82 'type' => 'boolean',
83 'excludes-on' => array( static::$type . '_decimals' => 0 ),
84 ),
85 static::$type . '_step' => array(
86 'label' => __( 'Slider Increment (Step)', 'pods' ),
87 'depends-on' => array( static::$type . '_format_type' => 'slider' ),
88 'default' => 1,
89 'type' => 'text',
90 ),
91 static::$type . '_min' => array(
92 'label' => __( 'Minimum Number', 'pods' ),
93 'depends-on-any' => array(
94 static::$type . '_format_type' => 'slider',
95 static::$type . '_html5' => true,
96 ),
97 'default' => '',
98 'type' => 'text',
99 ),
100 static::$type . '_max' => array(
101 'label' => __( 'Maximum Number', 'pods' ),
102 'depends-on-any' => array(
103 static::$type . '_format_type' => 'slider',
104 static::$type . '_html5' => true,
105 ),
106 'default' => '',
107 'type' => 'text',
108 ),
109 static::$type . '_max_length' => array(
110 'label' => __( 'Maximum Digits', 'pods' ),
111 'default' => 12,
112 'type' => 'number',
113 'help' => __( 'Set to -1 for no limit. The upper limit in the database for this field is 64 digits.', 'pods' ),
114 ),
115 static::$type . '_html5' => array(
116 'label' => __( 'Enable HTML5 Input Field', 'pods' ),
117 'default' => apply_filters( 'pods_form_ui_field_html5', 0, static::$type ),
118 'depends-on' => array( static::$type . '_format_type' => 'number' ),
119 'type' => 'boolean',
120 ),
121 static::$type . '_placeholder' => array(
122 'label' => __( 'HTML Placeholder', 'pods' ),
123 'default' => '',
124 'type' => 'text',
125 'help' => array(
126 __( 'Placeholders can provide instructions or an example of the required data format for a field. Please note: It is not a replacement for labels or description text, and it is less accessible for people using screen readers.', 'pods' ),
127 'https://www.w3.org/WAI/tutorials/forms/instructions/#placeholder-text',
128 ),
129 ),
130 );
131
132 return $options;
133 }
134
135 /**
136 * {@inheritdoc}
137 */
138 public function schema( $options = null ) {
139
140 $length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
141
142 if ( $length < 1 || 64 < $length ) {
143 $length = 64;
144 }
145
146 $decimals = $this->get_max_decimals( $options );
147
148 $schema = 'DECIMAL(' . $length . ',' . $decimals . ')';
149
150 return $schema;
151
152 }
153
154 /**
155 * {@inheritdoc}
156 */
157 public function prepare( $options = null ) {
158
159 $format = static::$prepare;
160
161 $decimals = $this->get_max_decimals( $options );
162
163 if( 6 < $decimals ) {
164 // %F only allows 6 decimals by default
165 $format = '%.' . $decimals . 'F';
166 } else if ( 0 < $decimals ) {
167 $format = '%F';
168 }
169
170 return $format;
171
172 }
173
174 /**
175 * @todo 2.8 Centralize the usage of this method. See PR #5540.
176 * {@inheritdoc}
177 */
178 public function is_empty( $value = null ) {
179
180 $is_empty = false;
181
182 $value = (float) $value;
183
184 if ( empty( $value ) ) {
185 $is_empty = true;
186 }
187
188 return $is_empty;
189
190 }
191
192 /**
193 * {@inheritdoc}
194 */
195 public function display( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
196 return $this->format( $value, $name, $options, $pod, $id );
197 }
198
199 /**
200 * {@inheritdoc}
201 */
202 public function input( $name, $value = null, $options = null, $pod = null, $id = null ) {
203
204 $options = ( is_array( $options ) || is_object( $options ) ) ? $options : (array) $options;
205 $form_field_type = PodsForm::$field_type;
206 $is_read_only = false;
207
208 $value = $this->normalize_value_for_input( $value, $options, '' );
209
210 if ( 'slider' === pods_v( static::$type . '_format_type', $options, 'number' ) ) {
211 $field_type = 'slider';
212 } else {
213 $field_type = static::$type;
214 }
215
216 if ( isset( $options['name'] ) && ! pods_permission( $options ) ) {
217 if ( pods_v( 'read_only', $options, false ) ) {
218 $is_read_only = true;
219 } else {
220 return;
221 }
222 } elseif ( ! pods_has_permissions( $options ) && pods_v( 'read_only', $options, false ) ) {
223 $is_read_only = true;
224 }
225
226 if ( $is_read_only ) {
227 $options['readonly'] = true;
228
229 $field_type = 'text';
230 }
231
232 // Enforce boolean.
233 $options[ static::$type . '_html5' ] = filter_var( pods_v( static::$type . '_html5', $options, false ), FILTER_VALIDATE_BOOLEAN );
234 $options[ static::$type . '_format_soft' ] = filter_var( pods_v( static::$type . '_format_soft', $options, false ), FILTER_VALIDATE_BOOLEAN );
235
236 // Only format the value for non-HTML5 inputs.
237 if ( ! $options[ static::$type . '_html5' ] ) {
238 // Ensure proper format
239 if ( is_array( $value ) ) {
240 foreach ( $value as $k => $repeatable_value ) {
241 $value[ $k ] = $this->format( $repeatable_value, $name, $options, $pod, $id );
242 }
243 } else {
244 $value = $this->format( $value, $name, $options, $pod, $id );
245 }
246 }
247
248 if ( ! empty( $options['disable_dfv'] ) ) {
249 return pods_view( PODS_DIR . 'ui/fields/number.php', compact( array_keys( get_defined_vars() ) ) );
250 }
251
252 $type = pods_v( 'type', $options, static::$type );
253
254 $args = compact( array_keys( get_defined_vars() ) );
255 $args = (object) $args;
256
257 $this->render_input_script( $args );
258 }
259
260 /**
261 * {@inheritdoc}
262 */
263 public function regex( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
264
265 $format_args = $this->get_number_format_args( $options );
266 $thousands = $format_args['thousands'];
267 $dot = $format_args['dot'];
268
269 return '\-*[0-9\\' . implode( '\\', array_filter( array( $dot, $thousands ) ) ) . ']+';
270 }
271
272 /**
273 * {@inheritdoc}
274 */
275 public function validate( $value, $name = null, $options = null, $fields = null, $pod = null, $id = null, $params = null ) {
276 $validate = parent::validate( $value, $name, $options, $fields, $pod, $id, $params );
277
278 $errors = array();
279
280 if ( is_array( $validate ) ) {
281 $errors = $validate;
282 }
283
284 $format_args = $this->get_number_format_args( $options );
285 $thousands = $format_args['thousands'];
286 $dot = $format_args['dot'];
287
288 $check = str_replace(
289 array( $thousands, $dot, html_entity_decode( $thousands ) ),
290 array( '', '.', '' ),
291 $value
292 );
293
294 $check = trim( $check );
295
296 $check = preg_replace( '/[0-9\.\-\s]/', '', $check );
297
298 $label = pods_v( 'label', $options, ucwords( str_replace( '_', ' ', $name ) ) );
299
300 if ( 0 < strlen( $check ) ) {
301 // Translators: %s stands for the input value.
302 $errors[] = sprintf( esc_html__( '%s is not numeric', 'pods' ), $label );
303 }
304
305 if ( ! empty( $errors ) ) {
306 return $errors;
307 }
308
309 return $validate;
310 }
311
312 /**
313 * {@inheritdoc}
314 */
315 public function pre_save( $value, $id = null, $name = null, $options = null, $fields = null, $pod = null, $params = null ) {
316
317 $format_args = $this->get_number_format_args( $options );
318 $thousands = $format_args['thousands'];
319 $dot = $format_args['dot'];
320 $decimals = $format_args['decimals'];
321
322 // Slider only supports `1234.00` format so no need for replacing characters.
323 if ( 'slider' !== pods_v( static::$type . '_format_type', $options ) ) {
324 // Not a slider so we need to replace format characters.
325 $value = str_replace(
326 array( $thousands, html_entity_decode( $thousands ), $dot, html_entity_decode( $dot ) ),
327 array( '', '', '.', '.' ),
328 $value
329 );
330
331 // HTML5 supports both `1234.00` and `1234,00` formats so let's replace commas as decimals (thousands replaced above).
332 if ( 1 === (int) pods_v( static::$type . '_html5', $options, false ) ) {
333 $value = str_replace( ',', '.', $value );
334 }
335 }
336
337 $value = trim( $value );
338
339 $value = preg_replace( '/[^0-9\.\-]/', '', $value );
340
341 if ( $this->is_empty( $value ) && ( ! is_numeric( $value ) || 0.0 !== (float) $value ) ) {
342 // Don't enforce a default value here.
343 return null;
344 }
345
346 $value = number_format( (float) $value, $decimals, '.', '' );
347
348 // Optionally remove trailing decimal zero's.
349 if ( pods_v( static::$type . '_format_soft', $options, false ) ) {
350 $value = $this->trim_decimals( $value, '.' );
351 }
352
353 return $value;
354 }
355
356 /**
357 * {@inheritdoc}
358 */
359 public function format( $value = null, $name = null, $options = null, $pod = null, $id = null ) {
360
361 if ( $this->is_empty( $value ) && ( ! is_numeric( $value ) || 0.0 !== (float) $value ) ) {
362 // Don't enforce a default value here.
363 return null;
364 }
365
366 $format_args = $this->get_number_format_args( $options );
367 $thousands = $format_args['thousands'];
368 $dot = $format_args['dot'];
369 $decimals = $format_args['decimals'];
370
371 if ( 'i18n' === pods_v( static::$type . '_format', $options ) ) {
372 $value = number_format_i18n( (float) $value, $decimals );
373 } else {
374 $value = number_format( (float) $value, $decimals, $dot, $thousands );
375 }
376
377 // Optionally remove trailing decimal zero's.
378 if ( pods_v( static::$type . '_format_soft', $options, false ) ) {
379 $value = $this->trim_decimals( $value, $dot );
380 }
381
382 return $value;
383 }
384
385 /**
386 * Trim trailing 0 decimals from numbers.
387 *
388 * @since 2.7.15
389 *
390 * @param string $value
391 * @param string $dot
392 *
393 * @return string
394 */
395 public function trim_decimals( $value, $dot ) {
396 $parts = explode( $dot, $value );
397
398 if ( isset( $parts[1] ) ) {
399 $parts[1] = rtrim( $parts[1], '0' );
400
401 if ( empty( $parts[1] ) ) {
402 unset( $parts[1] );
403 }
404 }
405
406 return implode( $dot, $parts );
407 }
408
409 /**
410 * Get the formatting arguments for numbers.
411 *
412 * @since 2.7.0
413 *
414 * @param array $options Field options.
415 *
416 * @return array {
417 * @type string $thousands
418 * @type string $dot
419 * @type int $decimals
420 * }
421 */
422 public function get_number_format_args( $options ) {
423
424 $format = pods_v( static::$type . '_format', $options );
425 $format = pods_unslash( $format );
426
427 switch ( $format ) {
428 case '9.999,99':
429 $thousands = '.';
430 $dot = ',';
431 break;
432 case '9,999.99':
433 $thousands = ',';
434 $dot = '.';
435 break;
436 case '9\'999.99':
437 $thousands = '\'';
438 $dot = '.';
439 break;
440 case '9 999,99':
441 $thousands = ' ';
442 $dot = ',';
443 break;
444 case '9999.99':
445 $thousands = '';
446 $dot = '.';
447 break;
448 case '9999,99':
449 $thousands = '';
450 $dot = ',';
451 break;
452 default:
453 global $wp_locale;
454 $thousands = $wp_locale->number_format['thousands_sep'];
455 $dot = $wp_locale->number_format['decimal_point'];
456 break;
457 }
458
459 $decimals = $this->get_max_decimals( $options );
460
461 return array(
462 'thousands' => $thousands,
463 'dot' => $dot,
464 'decimals' => $decimals,
465 );
466 }
467
468 /**
469 * Get the max allowed decimals.
470 *
471 * @since 2.7.0
472 *
473 * @param array $options Field options.
474 *
475 * @return int
476 */
477 public function get_max_decimals( $options ) {
478
479 $length = (int) pods_v( static::$type . '_max_length', $options, 12, true );
480
481 if ( $length < 1 || 64 < $length ) {
482 $length = 64;
483 }
484
485 $decimals = (int) pods_v( static::$type . '_decimals', $options, 0 );
486
487 if ( $decimals < 1 ) {
488 $decimals = 0;
489 } elseif ( 30 < $decimals ) {
490 $decimals = 30;
491 }
492
493 if ( $length < $decimals ) {
494 $decimals = $length;
495 }
496
497 return $decimals;
498 }
499 }
500