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