PluginProbe
Advanced Forms for ACF / trunk
Advanced Forms for ACF vtrunk
1.9.0 1.9.1 1.9.2.1 1.9.3 1.9.3.1 1.9.3.2 1.9.3.3 1.9.3.4 1.9.3.5 1.9.3.6 1.9.3.7 1.9.3.8 trunk 1.0.0 1.0.1 1.0.2 1.0.3 1.0.3.1 1.0.3.2 1.0.3.3 1.0.4 1.1.0 1.1.1 1.2.0 1.3.0 All 51 releases
advanced-forms / api / api-helpers.php

api-helpers.php in Advanced Forms for ACF trunk, at api/api-helpers.php

352 lines 10.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3
4 /**
5 * Searches input for tags {field:FIELD_NAME} and replaces with field values.
6 * Also replaces general tags such as {all_fields}.
7 *
8 * @since 1.0.1
9 *
10 */
11 function af_resolve_merge_tags( $input, $fields = false ) {
12 // Get fields from the global submission object if fields weren't passed
13 if ( ! $fields && af_has_submission() ) {
14 $fields = AF()->submission['fields'];
15 }
16
17 // Find all merge tags
18 if ( preg_match_all( "/{(.*?)}/", $input, $matches ) ) {
19 foreach ( $matches[1] as $i=>$tag ) {
20 // Resolve each merge tag and insert the value
21 $value = apply_filters( 'af/merge_tags/resolve', '', $tag, $fields );
22 $input = str_replace( $matches[0][ $i ], $value, $input );
23 }
24 }
25
26 return $input;
27 }
28
29
30 /**
31 * Renders a single field include (for emails, success messages etc.)
32 *
33 * @since 1.2.0
34 *
35 */
36 function _af_render_field_include( $field, $value = false ) {
37 if ( ! $value ) {
38 $value = $field['value'];
39 }
40
41 $output = '';
42
43 if ( 'repeater' == $field['type'] && is_array( $value ) ) {
44 $output .= '<table class="af-field-include af-field-include-repeater">';
45
46 // Column headings
47 $output .= '<thead><tr>';
48 foreach ( $field['sub_fields'] as $sub_field ) {
49 $output .= sprintf( '<th>%s</th>', $sub_field['label'] );
50 }
51 $output .= '</tr></thead>';
52
53 // Rows
54 $output .= '<tbody>';
55 if ( is_array( $value ) ) {
56 foreach ( $value as $row_values ) {
57 $output .= '<tr>';
58 foreach ( $field['sub_fields'] as $sub_field ) {
59 $output .= sprintf( '<td>%s</td>', _af_render_field_include( $sub_field, $row_values[ $sub_field['name'] ] ) );
60 }
61 $output .= '</tr>';
62 }
63 }
64 $output .= '</tbody>';
65
66 $output .= '</table>';
67 } elseif ( 'flexible_content' === $field['type'] ) {
68 $output .= '<table class="af-field-include af-field-include-flexible_content">';
69
70 foreach ( $value as $row ) {
71 $row_layout_name = $row['acf_fc_layout'];
72
73 // Find layout based on name
74 $row_layout = NULL;
75 foreach ( $field['layouts'] as $layout ) {
76 if ( $layout['name'] === $row_layout_name ) {
77 $row_layout = $layout;
78 break;
79 }
80 }
81
82 // Output header with layout name for the row
83 $output .= sprintf( '<tr><th>%s</th></tr>', $layout['label'] );
84 $output .= '<tr><td>';
85
86 // The subfield values will be displayed in a nested table, similar to a group field
87 $output .= '<table class="af-field-include af-field-include-flexible_content-inner">';
88 foreach ( $layout['sub_fields'] as $sub_field ) {
89 if ( isset( $row[ $sub_field['name'] ] ) ) {
90 $output .= sprintf( '<tr><th>%s</th></tr>', $sub_field['label'] );
91 $output .= sprintf( '<tr><td>%s</td></tr>', _af_render_field_include( $sub_field, $row[ $sub_field['name'] ] ) );
92 }
93 }
94 $output .= '</table>';
95
96 $output .= '</td></tr>';
97 }
98
99 $output .= '</table>';
100 } elseif ( 'clone' == $field['type'] || 'group' == $field['type'] ) {
101 $output .= sprintf( '<table class="af-field-include af-field-include-%s">', $field['type'] );
102
103 foreach ( $field['sub_fields'] as $sub_field ) {
104 if ( isset( $value[ $sub_field['name'] ] ) ) {
105 $output .= sprintf( '<tr><th>%s</th></tr>', $sub_field['label'] );
106 $output .= sprintf( '<tr><td>%s</td></tr>', _af_render_field_include( $sub_field, $value[ $sub_field['name'] ] ) );
107 }
108 }
109
110 $output .= '</table>';
111 } elseif ( 'true_false' == $field['type'] ) {
112 $true_text = isset( $field['ui_on_text'] ) && ! empty( $field['ui_on_text'] ) ? $field['ui_on_text'] : __( 'Yes', 'advanced-forms' );
113 $false_text = isset( $field['ui_off_text'] ) && ! empty( $field['ui_off_text'] ) ? $field['ui_off_text'] : __( 'No', 'advanced-forms' );
114
115 $output = $value ? $true_text : $false_text;
116 } elseif ( 'image' == $field['type'] ) {
117 $output .= sprintf( '<img src="%s" alt="%s" />', esc_attr( $value['sizes']['medium'] ), esc_attr( $value['alt']));
118 } elseif ( 'gallery' == $field['type'] && is_array( $value ) ) {
119 foreach ( $value as $image ) {
120 $output .= sprintf( '<img src="%s" alt="%s" />', esc_attr( $image['sizes']['medium'] ), esc_attr( $image['alt']));
121 }
122 } elseif ( 'file' == $field['type'] ) {
123 if ( 'url' === $field['return_format'] ) {
124 $output .= sprintf( '<a href="%s">Download</a>', $value );
125 } else if ( 'array' == $field['return_format'] ) {
126 $output .= sprintf( '<a href="%s">%s</a>', $value['url'], htmlspecialchars( $value['title'] ) );
127 }
128 } elseif ( in_array( $field['type'], array( 'wysiwyg', 'textarea', 'calculated' ) ) ) {
129 // Sanitize input using kses
130 $output .= wp_kses_post( stripslashes( $value ) );
131 } else {
132 $output = _af_render_field_include_value( $value );
133 }
134
135 // Allow third-parties to alter rendered field
136 $output = apply_filters( 'af/field/render_include', $output, $field, $value );
137 $output = apply_filters( 'af/field/render_include/name=' . $field['name'], $output, $field, $value );
138 $output = apply_filters( 'af/field/render_include/key=' . $field['key'], $output, $field, $value );
139
140 return $output;
141 }
142
143
144 /**
145 * Handle the different shapes field values may take and create an appropriate string
146 *
147 * WP_Post - post title
148 * WP_User - user first name and last name combined
149 * User array - user first name and last name combined
150 * WP_Term - term name
151 * Array - render each value and join with commas
152 * Other - cast to string
153 *
154 * @since 1.3.0
155 *
156 */
157 function _af_render_field_include_value( $value ) {
158 $rendered_value = '';
159
160 if ( $value instanceof WP_Post ) {
161
162 $rendered_value = $value->post_title;
163
164 } elseif ( $value instanceof WP_User ) {
165
166 $rendered_value = sprintf( '%s %s', $value->first_name, $value->last_name );
167
168 } elseif ( is_array( $value ) && isset( $value['user_email'] ) ) {
169
170 $rendered_value = sprintf( '%s %s', $value['user_firstname'], $value['user_lastname'] );
171
172 } elseif ( $value instanceof WP_Term ) {
173
174 $rendered_value = $value->name;
175
176 } elseif ( is_array( $value ) ) {
177
178 $rendered_values = array();
179
180 foreach ( $value as $single_value ) {
181
182 $rendered_values[] = _af_render_field_include_value( $single_value );
183
184 }
185
186 $rendered_value = join( ', ', $rendered_values );
187
188 } else {
189
190 $rendered_value = (string)$value;
191
192 }
193
194 // Sanitize output to protect against XSS
195 return htmlspecialchars( $rendered_value );
196 }
197
198
199 /**
200 * Output an "Insert field" button populated with $fields
201 * $floating adds class "floating" to the wrapper making the button float right in an input field
202 *
203 * @since 1.1.1
204 *
205 */
206 function _af_field_inserter_button( $form, $type = 'all', $floating = false ) {
207 $classses = ( $floating ) ? 'floating' : '';
208
209 echo '<a class="af-field-dropdown ' . $classses . ' button">' . __( 'Insert field', 'advanced-forms' );
210
211 echo '<div class="af-dropdown">';
212
213 $custom_tags = apply_filters( 'af/merge_tags/custom', array(), $form );
214 foreach ( $custom_tags as $custom_tag ) {
215 echo sprintf( '<div class="field-option" data-insert-value="{%s}">%s</div>', $custom_tag['value'], $custom_tag['label'] );
216 }
217
218 if ( ! empty( $custom_tags ) ) {
219 echo '<div class="field-divider"></div>';
220 }
221
222 if ( 'all' == $type ) {
223 echo sprintf( '<div class="field-option" data-insert-value="{all_fields}">%s</div>', __( 'All fields', 'advanced-forms' ) );
224 }
225
226 $fields = af_get_form_fields( $form, $type );
227 foreach ( $fields as $field ) {
228 _af_field_inserter_render_option( $field );
229 }
230
231 echo '</div>';
232 echo '</a>';
233 }
234
235 function _af_field_inserter_render_option( $field, $ancestors = array() ) {
236 $insert_value = '';
237 if ( empty( $ancestors ) ) {
238 $insert_value = sprintf( '{field:%s}', $field['name'] );
239 } else {
240 $hierarchy = array_merge( $ancestors, array( $field['name'] ) );
241 $top_level_name = array_shift( $hierarchy );
242 $insert_value = sprintf( '{field:%s[%s]}', $top_level_name, join( '][', $hierarchy ) );
243 }
244
245 $label = wp_strip_all_tags( $field['label'] );
246 $type = acf_get_field_type_label( $field['type'] );
247
248 echo sprintf( '<div class="field-option" data-insert-value="%s" role="button">', $insert_value );
249 echo sprintf( '<span class="field-name">%s</span><span class="field-type">%s</span>', $label, $type );
250 echo '</div>';
251
252 // Append options for sub fields if they exist (and we are dealing with a group or clone field)
253 $parent_field_types = array( 'group', 'clone' );
254 if ( in_array( $field['type'], $parent_field_types ) && isset( $field['sub_fields'] ) ) {
255 array_push( $ancestors, $field['name'] );
256
257 echo '<div class="sub-fields-wrapper">';
258 foreach ( $field['sub_fields'] as $sub_field ) {
259 _af_field_inserter_render_option( $sub_field, $ancestors );
260 }
261 echo '</div>';
262 }
263 }
264
265
266 /**
267 * Generates choices for a form field picker.
268 * Returns an array with field key => field label suitable for usage with an ACF select field.
269 *
270 * $type can be either 'all' or 'regular'.
271 *
272 * @since 1.3.0
273 *
274 */
275 function _af_form_field_choices( $form_key, $type = 'all' ) {
276
277 $form_fields = af_get_form_fields( $form_key, $type );
278
279 $choices = array();
280
281 if ( ! empty( $form_fields ) ) {
282
283 foreach ( $form_fields as $field ) {
284
285 $choices[ $field['key'] ] = $field['label'];
286
287 }
288
289 }
290
291
292 return $choices;
293
294 }
295
296
297 /**
298 * Find a nested sub field based on some selector.
299 * If the selector is ["g1", "g2", "f1"] then the function will find a
300 * field named "f1" inside "g2" which is inside field "g1".
301 * The $field parameter should be the top-level field, "g1" in the example.
302 *
303 * @since 1.7.2
304 *
305 */
306 function af_pick_sub_field( $field, $selector ) {
307 while ( ! empty( $selector ) && $field && isset( $field['sub_fields'] ) ) {
308 $search = array_shift( $selector );
309 $field = acf_search_fields( $search, $field['sub_fields'] );
310 }
311
312 return $field;
313 }
314
315
316 /**
317 * Find a nested value of a sub field based on some selector.
318 * If the selector is ["g1", "g2", "f1"] then the function will return the
319 * value of field "f1" inside "g2" which is inside "g1".
320 * The $field parameter should be the top-level field, "g1" in the example.
321 *
322 * @since 1.7.2
323 *
324 */
325 function af_pick_sub_field_value( $field, $selector ) {
326 $value = $field['value'];
327
328 while ( ! empty( $selector ) ) {
329 $search = array_shift( $selector );
330 if ( isset( $value[ $search ] ) ) {
331 $value = $value[ $search ];
332 } else {
333 return false;
334 }
335 }
336
337 return $value;
338 }
339
340
341 /**
342 * Retrieves full URL (with trailing slash) to the plugin assets folder
343 *
344 * @since 1.3.0
345 *
346 */
347 function af_assets_url( $path = '' ) {
348
349 return plugin_dir_url( dirname( __FILE__ ) ) . 'assets/' . $path;
350
351 }
352