PluginProbe ʕ •ᴥ•ʔ
Pods – Custom Content Types and Fields / 3.3.4
Pods – Custom Content Types and Fields v3.3.4
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 / includes / forms.php
pods / includes Last commit date
compatibility 6 years ago access.php 9 months ago classes.php 2 years ago compatibility.php 2 years ago data.php 11 months ago forms.php 4 years ago general.php 11 months ago media.php 4 years ago
forms.php
551 lines
1 <?php
2 /**
3 * @package Pods\Global\Functions\Forms
4 */
5
6 use Pods\Whatsit;
7 use Pods\Whatsit\Field;
8 use Pods\Whatsit\Pod;
9 use Pods\Whatsit\Store;
10 use Pods\Permissions;
11
12 /**
13 * Enqueue a script in a way that is compatible with enqueueing before the asset was registered.
14 *
15 * @since 2.8.6
16 *
17 * @param string $handle Name of the script. Should be unique.
18 * @param string $src Full URL of the script, or path of the script relative to the WordPress root directory.
19 * Default empty.
20 * @param string[] $deps Optional. An array of registered script handles this script depends on. Default empty array.
21 * @param string|bool|null $ver Optional. String specifying script version number, if it has one, which is added to the URL
22 * as a query string for cache busting purposes. If version is set to false, a version
23 * number is automatically added equal to current installed WordPress version.
24 * If set to null, no version is added.
25 * @param bool $in_footer Optional. Whether to enqueue the script before </body> instead of in the <head>.
26 * Default 'false'.
27 */
28 function pods_form_enqueue_script( $handle, $src = '', $deps = [], $ver = false, $in_footer = false ) {
29 // Use dynamic arguments to support future versions of wp_enqueue_script.
30 $args = func_get_args();
31
32 // Check that the script is already registered, or we are registering it when enqueueing.
33 if ( ! empty( $src ) || wp_script_is( $handle, 'registered' ) ) {
34 call_user_func_array( 'wp_enqueue_script', $args );
35
36 return;
37 }
38
39 // The script was enqueued before the enqueue scripts action was called.
40 add_action( 'pods_after_enqueue_scripts', static function() use ( $args ) {
41 call_user_func_array( 'wp_enqueue_script', $args );
42 } );
43 }
44
45 /**
46 * Enqueue a style in a way that is compatible with enqueueing before the asset was registered.
47 *
48 * @since 2.8.6
49 *
50 * @param string $handle Name of the stylesheet. Should be unique.
51 * @param string $src Full URL of the stylesheet, or path of the stylesheet relative to the WordPress root directory.
52 * Default empty.
53 * @param string[] $deps Optional. An array of registered stylesheet handles this stylesheet depends on. Default empty array.
54 * @param string|bool|null $ver Optional. String specifying stylesheet version number, if it has one, which is added to the URL
55 * as a query string for cache busting purposes. If version is set to false, a version
56 * number is automatically added equal to current installed WordPress version.
57 * If set to null, no version is added.
58 * @param string $media Optional. The media for which this stylesheet has been defined.
59 * Default 'all'. Accepts media types like 'all', 'print' and 'screen', or media queries like
60 * '(orientation: portrait)' and '(max-width: 640px)'.
61 */
62 function pods_form_enqueue_style( $handle, $src = '', $deps = array(), $ver = false, $media = 'all' ) {
63 // Use dynamic arguments to support future versions of wp_enqueue_script.
64 $args = func_get_args();
65
66 // Check that the style is already registered, or we are registering it when enqueueing.
67 if ( ! empty( $src ) || wp_style_is( $handle, 'registered' ) ) {
68 call_user_func_array( 'wp_enqueue_style', $args );
69
70 return;
71 }
72
73 // The style was enqueued before the enqueue scripts action was called.
74 add_action( 'pods_after_enqueue_scripts', static function() use ( $args ) {
75 call_user_func_array( 'wp_enqueue_style', $args );
76 } );
77 }
78
79 /**
80 * Render form fields outside of the <form> context.
81 *
82 * @since 2.8.0
83 *
84 * @param string $name The object name.
85 * @param int|string $object_id The object ID.
86 * @param array $options The customization options.
87 */
88 function pods_form_render_fields( $name, $object_id, array $options = [] ) {
89 $defaults = [
90 'section_field' => null,
91 'section' => null,
92 'separator' => 'before',
93 'wrapper' => false,
94 'wrapper_class' => null,
95 'container_class' => null,
96 'heading' => 'h2',
97 'heading_class' => null,
98 'heading_sub_container' => null,
99 'heading_sub_container_class' => null,
100 'separated_heading' => null,
101 'render' => 'table',
102 ];
103
104 $options = array_merge( $defaults, $options );
105
106 $pod = pods( $name, $object_id, true );
107
108 if ( ! $pod ) {
109 return;
110 }
111
112 // Return groups.
113 $options['return_type'] = 'group';
114
115 $wrapper_classes = [
116 'pods-form-wrapper',
117 'pods-form-wrapper--pod--' . $name,
118 ];
119
120 if ( $options['wrapper_class'] ) {
121 if ( ! is_array( $options['wrapper_class'] ) ) {
122 $options['wrapper_class'] = explode( ' ', $options['wrapper_class'] );
123 }
124
125 foreach ( $options['wrapper_class'] as $wrapper_class ) {
126 $wrapper_classes[] = $wrapper_class;
127 }
128 }
129
130 $wrapper_classes = array_map( 'sanitize_html_class', $wrapper_classes );
131 $wrapper_classes = implode( ' ', $wrapper_classes );
132
133 // Get groups/fields and render them.
134 $groups = pods_form_get_visible_objects( $pod, $options );
135
136 foreach ( $groups as $group ) {
137 $fields = $group->get_fields();
138
139 /**
140 * Allow hooking into before the form field output for a group is rendered.
141 *
142 * @since 2.8.0
143 *
144 * @param Whatsit\Group $group The Group object.
145 */
146 do_action( 'pods_form_render_fields_group_pre', $group );
147
148 $is_table_separated_render = 'table-separated' === $options['render'];
149 $is_table_render = 'table' === $options['render'] || $is_table_separated_render;
150 $is_table_rows_render = 'table-rows' === $options['render'];
151 $is_div_rows_render = 'div-rows' === $options['render'];
152
153 if ( $is_table_separated_render ) {
154 echo "</table>\n";
155 }
156
157 if ( ! $is_table_rows_render && 'before' === $options['separator'] ) {
158 echo "<hr />\n";
159 }
160
161 if ( $is_table_rows_render ) {
162 printf(
163 '<tr><td colspan="2" class="%s">',
164 $wrapper_classes
165 );
166 } elseif ( $is_div_rows_render && $options['wrapper'] ) {
167 printf(
168 '<div class="%s">',
169 $wrapper_classes
170 );
171 }
172
173 if ( $options['heading'] ) {
174 $heading_classes = [
175 'pods-form-heading',
176 'pods-form-heading--pod-' . $name,
177 'pods-form-heading--group',
178 'pods-form-heading--group-' . $group['name'],
179 ];
180
181 if ( $options['heading_class'] ) {
182 if ( ! is_array( $options['heading_class'] ) ) {
183 $options['heading_class'] = explode( ' ', $options['heading_class'] );
184 }
185
186 foreach ( $options['heading_class'] as $heading_class ) {
187 $heading_classes[] = $heading_class;
188 }
189 }
190
191 $heading_classes = array_map( 'sanitize_html_class', $heading_classes );
192 $heading_classes = implode( ' ', $heading_classes );
193
194 $heading_text = wp_kses_post( $group['label'] );
195
196 if ( $options['heading_sub_container'] ) {
197 $heading_sub_container_classes = [];
198
199 if ( $options['heading_sub_container_class'] ) {
200 if ( ! is_array( $options['heading_sub_container_class'] ) ) {
201 $options['heading_sub_container_class'] = explode( ' ', $options['heading_sub_container_class'] );
202 }
203
204 foreach ( $options['heading_sub_container_class'] as $heading_sub_container_class ) {
205 $heading_sub_container_classes[] = $heading_sub_container_class;
206 }
207 }
208
209 $heading_sub_container_extra_html = '';
210
211 if ( ! empty( $heading_sub_container_classes ) ) {
212 $heading_sub_container_classes = array_map( 'sanitize_html_class', $heading_sub_container_classes );
213 $heading_sub_container_classes = implode( ' ', $heading_sub_container_classes );
214
215 $heading_sub_container_extra_html = sprintf(
216 ' class="%s"',
217 esc_attr( $heading_sub_container_classes )
218 );
219 }
220
221 $heading_text = sprintf(
222 '<%1$s%2$s>%3$s</%1$s>' . "\n",
223 esc_html( $options['heading_sub_container'] ),
224 $heading_sub_container_extra_html,
225 $heading_text
226 );
227 }
228
229 printf(
230 '<%1$s class="%2$s">%3$s</%1$s>' . "\n",
231 esc_html( $options['heading'] ),
232 esc_attr( $heading_classes ),
233 $heading_text
234 );
235 }
236
237 if ( $is_table_rows_render ) {
238 echo '</td></tr>';
239 }
240
241 $id = $object_id;
242
243 $container_classes = [
244 'pods-form',
245 'pods-form-container',
246 'pods-form-container--pod--' . $name,
247 'pods-form-container--group',
248 'pods-form-container--group--' . $group['name'],
249 ];
250
251 if ( $options['container_class'] ) {
252 if ( ! is_array( $options['container_class'] ) ) {
253 $options['container_class'] = explode( ' ', $options['container_class'] );
254 }
255
256 foreach ( $options['container_class'] as $container_class ) {
257 $container_classes[] = $container_class;
258 }
259 }
260
261 $container_classes = array_map( 'sanitize_html_class', $container_classes );
262 $container_classes = implode( ' ', $container_classes );
263
264 if ( $is_table_render || $is_table_rows_render ) {
265 if ( $is_table_render ) {
266 echo '<table class="form-table ' . esc_attr( $container_classes ) . '">' . "\n";
267 }
268
269 $field_prefix = 'pods_meta_';
270 $field_row_classes = 'pods-meta';
271
272 pods_view( PODS_DIR . 'ui/forms/table-rows.php', compact( array_keys( get_defined_vars() ) ) );
273
274 if ( $is_table_render ) {
275 echo "</table>\n";
276 }
277 } elseif ( 'div-rows' === $options['render'] ) {
278 echo '<div class="' . esc_attr( $container_classes ) . '">' . "\n";
279
280 $field_prefix = 'pods_meta_';
281 $field_row_classes = 'pods-meta';
282
283 pods_view( PODS_DIR . 'ui/forms/div-rows.php', compact( array_keys( get_defined_vars() ) ) );
284
285 echo "</div>\n";
286 }
287
288 if ( $is_table_separated_render ) {
289 if ( $options['heading'] && $options['separated_heading'] ) {
290 printf( '<%1$s>%2$s</%1$s>' . "\n", esc_html( $options['heading'] ), wp_kses_post( $options['separated_heading'] ) );
291 }
292
293 echo '<table class="form-table">' . "\n";
294 } elseif ( $is_div_rows_render && $options['wrapper'] ) {
295 echo '</div>';
296 }
297
298 if ( ! $is_table_rows_render && 'after' === $options['separator'] ) {
299 echo "<hr />\n";
300 }
301
302 /**
303 * Allow hooking into after the form field output for a group is rendered.
304 *
305 * @since 2.8.0
306 *
307 * @param Whatsit\Group $group The Group object.
308 */
309 do_action( 'pods_form_render_fields_group_post', $group );
310 }
311 }
312
313 /**
314 * Get the list of Groups or Fields that are able to be shown.
315 *
316 * @since 2.8.0
317 *
318 * @param Pods $pod The Pods object.
319 * @param array $options The customization options.
320 *
321 * @return Whatsit\Group[]|Whatsit\Field[] List of Groups or Fields that are able to be shown.
322 */
323 function pods_form_get_visible_objects( $pod, array $options = [] ) {
324 $defaults = [
325 'section_field' => null,
326 'section' => null,
327 'return_type' => 'group',
328 ];
329
330 $options = array_merge( $defaults, $options );
331
332 $visible_groups = [];
333 $visible_fields = [];
334
335 $return_fields = 'field' === $options['return_type'];
336
337 // Get groups/fields and render them.
338 $groups = $pod->pod_data->get_groups();
339
340 foreach ( $groups as $group ) {
341 // Skip if the section does not match.
342 if (
343 $options['section']
344 && $options['section_field']
345 && (
346 'any' === $options['section']
347 || ! in_array( $options['section'], (array) $group[ $options['section_field'] ], true )
348 )
349 ) {
350 continue;
351 }
352
353 $fields = $group->get_fields();
354
355 if ( empty( $fields ) ) {
356 continue;
357 }
358
359 if ( ! pods_permission( $group ) ) {
360 continue;
361 }
362
363 $field_found = false;
364
365 foreach ( $fields as $field ) {
366 if ( ! pods_permission( $field ) ) {
367 continue;
368 }
369
370 if ( pods_v( 'hidden', $field, false ) ) {
371 continue;
372 }
373
374 if ( $return_fields ) {
375 $visible_fields[ $field['name'] ] = $field;
376
377 continue;
378 }
379
380 $field_found = true;
381
382 break;
383 }
384
385 if ( ! $field_found ) {
386 continue;
387 }
388
389 $visible_groups[ $group['name'] ] = $group;
390 }
391
392 if ( $return_fields ) {
393 return $visible_fields;
394 }
395
396 return $visible_groups;
397 }
398
399 /**
400 * Validate the submitted fields from the form.
401 *
402 * @since 2.8.0
403 *
404 * @param string $name The object name.
405 * @param int|string|null $object_id The object ID.
406 * @param array $options The customization options.
407 *
408 * @return true|WP_Error[]|null True if the fields validate, a list of WP_Error objects with validation errors, or null if Pod does not exist.
409 */
410 function pods_form_validate_submitted_fields( $name, $object_id = null, array $options = [] ) {
411 $pod = pods( $name, $object_id, true );
412
413 if ( ! $pod ) {
414 return null;
415 }
416
417 // Get the fields.
418 $options['return_type'] = 'field';
419
420 // Get fields and save them.
421 $fields = pods_form_get_visible_objects( $pod, $options );
422
423 $api = pods_api();
424
425 // Enforce WP_Error objects for validation errors.
426 $api->display_errors = 'wp_error';
427
428 $errors = [];
429
430 foreach ( $fields as $field ) {
431 $field_name = $field['name'];
432
433 $value = pods_form_get_submitted_field_value( $field_name );
434
435 $field_is_valid = $api->handle_field_validation( $value, $field_name, [], $fields, $pod );
436
437 if ( is_wp_error( $field_is_valid ) ) {
438 $errors[] = $field_is_valid;
439 }
440 }
441
442 // Check for validation errors.
443 if ( ! empty( $errors ) ) {
444 return $errors;
445 }
446
447 // Fields are valid.
448 return true;
449 }
450
451 /**
452 * Save the submitted fields from the form.
453 *
454 * @since 2.8.0
455 *
456 * @param string $name The object name.
457 * @param int|string $object_id The object ID.
458 * @param bool $is_new_item Whether this is a new item being saved.
459 * @param array $options The customization options.
460 *
461 * @return int|null The saved item or null if the pod does not exist.
462 */
463 function pods_form_save_submitted_fields( $name, $object_id, $is_new_item = false, array $options = [] ) {
464 $pod = pods( $name, $object_id, true );
465
466 if ( ! $pod ) {
467 return null;
468 }
469
470 // Get the submitted field values.
471 $data = pods_form_get_submitted_field_values( $name, $options );
472
473 return $pod->save( $data, null, null, [
474 'is_new_item' => $is_new_item,
475 'podsmeta' => true,
476 ] );
477 }
478
479 /**
480 * Get the submitted field values from the form.
481 *
482 * @since 2.8.0
483 *
484 * @param string $name The object name.
485 * @param array $options The customization options.
486 *
487 * @return array List of submitted field values and their values.
488 */
489 function pods_form_get_submitted_field_values( $name, array $options = [] ) {
490 // Get the submitted fields.
491 $fields = pods_form_get_submitted_fields( $name, $options );
492 $fields = array_keys( $fields );
493
494 $data = [];
495
496 foreach ( $fields as $field_name ) {
497 $data[ $field_name ] = pods_form_get_submitted_field_value( $field_name );
498 }
499
500 return $data;
501 }
502
503 /**
504 * Get the submitted field value for a field.
505 *
506 * @since 2.8.0
507 *
508 * @param string|array|Field $field The field name or object.
509 * @param string $method The method to get the value from (default: post).
510 *
511 * @return mixed The submitted field value for a field.
512 */
513 function pods_form_get_submitted_field_value( $field, $method = 'post' ) {
514 $field_name = $field;
515
516 if ( $field instanceof Field ) {
517 $field_name = $field->get_name();
518 } elseif ( is_array( $field ) ) {
519 $field_name = $field['name'];
520 } elseif ( ! is_string( $field ) ) {
521 return '';
522 }
523
524 return pods_v( 'pods_meta_' . $field_name, $method, '' );
525 }
526
527
528 /**
529 * Get the submitted fields from the form.
530 *
531 * @since 2.8.0
532 *
533 * @param string $name The object name.
534 * @param array $options The customization options.
535 *
536 * @return array List of submitted fields and their values.
537 */
538 function pods_form_get_submitted_fields( $name, array $options = [] ) {
539 $pod = pods( $name, null, true );
540
541 if ( ! $pod ) {
542 return [];
543 }
544
545 // Get the fields.
546 $options['return_type'] = 'field';
547
548 // Get fields and save them.
549 return pods_form_get_visible_objects( $pod, $options );
550 }
551