PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.3.33
HTML Forms – Simple WordPress Forms Plugin v1.3.33
1.7.0 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0 1.3.0 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.14 1.3.15 1.3.16 All 67 releases
← All changes | src/functions.php +384 -152 1.2.01.3.33 View file →
@@ -1,11 +1,29 @@
1 1 <?php
2 2
3 3 use HTML_Forms\Form;
4 4 use HTML_Forms\Submission;
5 -use WP_Post;
6 5
7 6 /**
7 + * @param array $args
8 + * @return array
9 + */
10 +function hf_get_forms( array $args = array() ) {
11 + $default_args = array(
12 + 'post_type' => 'html-form',
13 + 'post_status' => array( 'publish', 'draft', 'pending', 'future' ),
14 + 'posts_per_page' => -1,
15 + 'ignore_sticky_posts' => true,
16 + 'no_found_rows' => true,
17 + );
18 + $args = array_merge( $default_args, $args );
19 + $query = new WP_Query;
20 + $posts = $query->query( $args );
21 + $forms = array_map( 'hf_get_form', $posts );
22 + return $forms;
23 +}
24 +
25 +/**
8 26 * @param $form_id_or_slug int|string|WP_Post
9 27 * @return Form
10 28 * @throws Exception
11 29 */
@@ -10,95 +28,110 @@
10 28 * @throws Exception
11 29 */
12 30 function hf_get_form( $form_id_or_slug ) {
13 31
14 - if( is_numeric( $form_id_or_slug ) || $form_id_or_slug instanceof WP_Post ) {
15 - $post = get_post( $form_id_or_slug );
32 + if ( is_numeric( $form_id_or_slug ) || $form_id_or_slug instanceof WP_Post ) {
33 + $post = get_post( $form_id_or_slug );
16 34
17 - if( ! $post || $post->post_type !== 'html-form' ) {
18 - throw new Exception( "Invalid form ID" );
19 - }
20 - } else {
21 - $posts = get_posts(
22 - array(
23 - 'post_type' => 'html-form',
24 - 'name' => $form_id_or_slug,
25 - 'post_status' => 'publish',
26 - 'numberposts' => 1,
27 - )
28 - );
35 + if ( ! $post instanceof WP_Post || $post->post_type !== 'html-form' ) {
36 + throw new Exception( 'Invalid form ID' );
37 + }
38 + } else {
29 39
30 - if( empty( $posts ) ) {
31 - throw new Exception( 'Invalid form slug' );
32 - }
33 - $post = $posts[0];
34 - }
40 + $query = new WP_Query;
41 + $posts = $query->query(
42 + array(
43 + 'post_type' => 'html-form',
44 + 'name' => $form_id_or_slug,
45 + 'post_status' => 'publish',
46 + 'posts_per_page' => 1,
47 + 'ignore_sticky_posts' => true,
48 + 'no_found_rows' => true,
49 + )
50 + );
51 + if ( empty( $posts ) ) {
52 + throw new Exception( 'Invalid form slug' );
53 + }
54 + $post = $posts[0];
55 + }
35 56
36 - // get all post meta in a single call for performance
37 - $post_meta = get_post_meta( $post->ID );
57 + // get all post meta in a single call for performance
58 + $post_meta = get_post_meta( $post->ID );
38 59
39 - // grab & merge form settings
40 - $default_settings = array(
41 - 'save_submissions' => 1,
42 - 'hide_after_success' => 0,
43 - 'redirect_url' => '',
44 - 'required_fields' =>'',
45 - 'email_fields' => '',
46 - );
47 - $default_settings = apply_filters( 'hf_form_default_settings', $default_settings );
48 - $settings = array();
49 - if( ! empty( $post_meta['_hf_settings'][0] ) ) {
50 - $settings = (array) maybe_unserialize( $post_meta['_hf_settings'][0] );
51 - }
52 - $settings = array_merge( $default_settings, $settings );
60 + // grab & merge form settings
61 + $default_settings = array(
62 + 'save_submissions' => 1,
63 + 'hide_after_success' => 0,
64 + 'redirect_url' => '',
65 + 'required_fields' => '',
66 + 'email_fields' => '',
67 + );
68 + $default_settings = apply_filters( 'hf_form_default_settings', $default_settings );
69 + $settings = array();
70 + if ( ! empty( $post_meta['_hf_settings'][0] ) ) {
71 + $settings = (array) maybe_unserialize( $post_meta['_hf_settings'][0] );
72 + }
73 + $settings = array_merge( $default_settings, $settings );
53 74
54 - // grab & merge form messages
55 - $default_messages = array(
56 - 'success' => __('Thank you! We will be in touch soon.', 'html-forms'),
57 - 'invalid_email' => __( 'Sorry, that email address looks invalid.', 'html-forms' ),
58 - 'required_field_missing' => __( "Please fill in the required fields.", "html-forms" ),
59 - 'error' => __( 'Oops. An error occurred.', 'html-forms' ),
60 - );
61 - $messages = array();
62 - foreach( $post_meta as $meta_key => $meta_values ) {
63 - if( strpos( $meta_key, 'hf_message_' ) === 0 ) {
64 - $message_key = substr( $meta_key, strlen( 'hf_message_' ) );
65 - $messages[$message_key] = (string) $meta_values[0];
66 - }
67 - }
68 - $messages = array_merge( $default_messages, $messages );
75 + // grab & merge form messages
76 + $default_messages = array(
77 + 'success' => __( 'Thank you! We will be in touch soon.', 'html-forms' ),
78 + 'invalid_email' => __( 'Sorry, that email address looks invalid.', 'html-forms' ),
79 + 'required_field_missing' => __( 'Please fill in the required fields.', 'html-forms' ),
80 + 'error' => __( 'Oops. An error occurred.', 'html-forms' ),
81 + );
82 + $default_messages = apply_filters( 'hf_form_default_messages', $default_messages );
83 + $messages = array();
84 + foreach ( $post_meta as $meta_key => $meta_values ) {
85 + if ( strpos( $meta_key, 'hf_message_' ) === 0 ) {
86 + $message_key = substr( $meta_key, strlen( 'hf_message_' ) );
87 + $messages[ $message_key ] = (string) $meta_values[0];
88 + }
89 + }
90 + $messages = array_merge( $default_messages, $messages );
69 91
70 - // finally, create form instance
71 - $form = new Form( $post->ID );
72 - $form->title = $post->post_title;
73 - $form->slug = $post->post_name;
74 - $form->markup = $post->post_content;
75 - $form->settings = $settings;
76 - $form->messages = $messages;
77 - return $form;
92 + // finally, create form instance
93 + $form = new Form( $post->ID );
94 + $form->title = $post->post_title;
95 + $form->slug = $post->post_name;
96 + $form->markup = $post->post_content;
97 + $form->settings = $settings;
98 + $form->messages = $messages;
99 + return $form;
78 100 }
79 101
80 102 /**
81 103 * @param $form_id
104 + * @return int
105 + */
106 +function hf_count_form_submissions( $form_id ) {
107 + global $wpdb;
108 + $table = $wpdb->prefix . 'hf_submissions';
109 + $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} s WHERE s.form_id = %d;", $form_id ) );
110 + return (int) $result;
111 +}
112 +
113 +/**
114 + * @param $form_id
82 115 * @param array $args
83 116 * @return Submission[]
84 117 */
85 118 function hf_get_form_submissions( $form_id, array $args = array() ) {
86 - $default_args = array(
87 - 'offset' => 0,
88 - 'limit' => 1000,
89 - );
90 - $args = array_merge( $default_args, $args );
119 + $default_args = array(
120 + 'offset' => 0,
121 + 'limit' => 1000,
122 + );
123 + $args = array_merge( $default_args, $args );
91 124
92 - global $wpdb;
93 - $table = $wpdb->prefix .'hf_submissions';
94 - $results = $wpdb->get_results( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.form_id = %d ORDER BY s.submitted_at DESC LIMIT %d, %d;", $form_id, $args['offset'], $args['limit'] ), OBJECT_K );
95 - $submissions = array();
96 - foreach( $results as $key => $object ) {
97 - $submission = Submission::from_object( $object );
98 - $submissions[$key] = $submission;
99 - }
100 - return $submissions;
125 + global $wpdb;
126 + $table = $wpdb->prefix . 'hf_submissions';
127 + $results = $wpdb->get_results( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.form_id = %d ORDER BY s.submitted_at DESC LIMIT %d, %d;", $form_id, $args['offset'], $args['limit'] ), OBJECT_K );
128 + $submissions = array();
129 + foreach ( $results as $key => $object ) {
130 + $submission = Submission::from_object( $object );
131 + $submissions[ $key ] = $submission;
132 + }
133 + return $submissions;
101 134 }
102 135
103 136 /**
104 137 * @param int $submission_id
@@ -104,35 +137,41 @@
104 137 * @param int $submission_id
105 138 * @return Submission
106 139 */
107 140 function hf_get_form_submission( $submission_id ) {
108 - global $wpdb;
109 - $table = $wpdb->prefix .'hf_submissions';
110 - $object = $wpdb->get_row( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.id = %d;", $submission_id ), OBJECT );
111 - $submission = Submission::from_object( $object );
112 - return $submission;
141 + global $wpdb;
142 + $table = $wpdb->prefix . 'hf_submissions';
143 + $object = $wpdb->get_row( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.id = %d;", $submission_id ), OBJECT );
144 + $submission = Submission::from_object( $object );
145 + return $submission;
113 146 }
114 147 /**
115 148 * @return array
116 149 */
117 150 function hf_get_settings() {
118 - $default_settings = array(
119 - 'load_stylesheet' => 0,
120 - );
151 + $default_settings = array(
152 + 'load_stylesheet' => 0,
153 + );
121 154
122 - $settings = get_option( 'hf_settings', array() );
155 + $settings = get_option( 'hf_settings', null );
123 156
124 - // merge with default settings
125 - $settings = array_merge( $default_settings, $settings );
157 + // prevent a SQL query when option does not yet exist
158 + if ( $settings === null ) {
159 + update_option( 'hf_settings', array(), true );
160 + $settings = array();
161 + }
126 162
127 - /**
128 - * Filters the global HTML Forms hf_settings
129 - *
130 - * @param array $settings
131 - */
132 - $settings = apply_filters( 'hf_settings', $settings );
163 + // merge with default settings
164 + $settings = array_merge( $default_settings, $settings );
133 165
134 - return $settings;
166 + /**
167 + * Filters the global HTML Forms hf_settings
168 + *
169 + * @param array $settings
170 + */
171 + $settings = apply_filters( 'hf_settings', $settings );
172 +
173 + return $settings;
135 174 }
136 175
137 176 /**
138 177 * Get element from array, allows for dot notation eg: "foo.bar"
@@ -142,25 +181,25 @@
142 181 * @param mixed $default
143 182 * @return mixed
144 183 */
145 184 function hf_array_get( $array, $key, $default = null ) {
146 - if ( is_null( $key ) ) {
147 - return $array;
148 - }
185 + if ( is_null( $key ) ) {
186 + return $array;
187 + }
149 188
150 - if ( isset( $array[$key] ) ) {
151 - return $array[$key];
152 - }
189 + if ( isset( $array[ $key ] ) ) {
190 + return $array[ $key ];
191 + }
153 192
154 - foreach (explode( '.', $key ) as $segment) {
155 - if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) {
156 - return $default;
157 - }
193 + foreach ( explode( '.', $key ) as $segment ) {
194 + if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) {
195 + return $default;
196 + }
158 197
159 - $array = $array[$segment];
160 - }
198 + $array = $array[ $segment ];
199 + }
161 200
162 - return $array;
201 + return $array;
163 202 }
164 203
165 204 /**
166 205 * Processes template tags like {{user.user_email}}
@@ -169,74 +208,267 @@
169 208 *
170 209 * @return string
171 210 */
172 211 function hf_template( $template ) {
173 - $replacers = new HTML_Forms\TagReplacers();
174 - $tags = array(
175 - 'user' => array( $replacers, 'user' ),
176 - 'post' => array( $replacers, 'post'),
177 - 'url_params' => array( $replacers, 'url_params' ),
178 - );
212 + $replacers = new HTML_Forms\TagReplacers();
213 + $tags = array(
214 + 'user' => array( $replacers, 'user' ),
215 + 'post' => array( $replacers, 'post' ),
216 + 'url_params' => array( $replacers, 'url_params' ),
217 + );
179 218
180 - /**
181 - * Filters the available tags in HTML Forms templates, like {{user.user_email}}.
182 - *
183 - * Can be used to add simple scalar replacements or more advanced replacement functions that accept a parameter.
184 - *
185 - * @param array $tags
186 - */
187 - $tags = apply_filters( 'hf_template_tags', $tags );
219 + /**
220 + * Filters the available tags in HTML Forms templates, like {{user.user_email}}.
221 + *
222 + * Can be used to add simple scalar replacements or more advanced replacement functions that accept a parameter.
223 + *
224 + * @param array $tags
225 + */
226 + $tags = apply_filters( 'hf_template_tags', $tags );
188 227
189 - $template = preg_replace_callback( '/\{\{ *(\w+)(?:\.([\w\.]+))? *(?:\|\| *(\w+))? *\}\}/', function( $matches ) use ( $tags ) {
190 - $tag = $matches[1];
191 - $param = ! isset( $matches[2] ) ? "" : $matches[2];
192 - $default = ! isset( $matches[3] ) ? "" : $matches[3];
193 - $value = "";
228 + $template = preg_replace_callback(
229 + '/\{\{ *(\w+)(?:\.([\w\.]+))? *(?:\|\| *(\w+))? *\}\}/',
230 + function( $matches ) use ( $tags ) {
231 + $tag = $matches[1];
232 + $param = ! isset( $matches[2] ) ? '' : $matches[2];
233 + $default = ! isset( $matches[3] ) ? '' : $matches[3];
194 234
195 - // do not change anything if we have no replacer with that key, could be custom user logic or another plugin.
196 - if( ! isset( $tags[ $tag] ) ) {
197 - return $matches[0];
198 - }
235 + // do not change anything if we have no replacer with that key, could be custom user logic or another plugin.
236 + if ( ! isset( $tags[ $tag ] ) ) {
237 + return $matches[0];
238 + }
199 239
200 - $replacement = $tags[$tag];
201 - $value = is_callable( $replacement ) ? call_user_func_array( $replacement, array( $param ) ) : $replacement;
202 - return ! empty( $value ) ? $value : $default;
203 - }, $template );
240 + $replacement = $tags[ $tag ];
241 + $value = is_callable( $replacement ) ? call_user_func_array( $replacement, array( $param ) ) : $replacement;
242 + return ! empty( $value ) ? $value : $default;
243 + },
244 + $template
245 + );
204 246
205 - return $template;
247 + return $template;
206 248 }
207 249
208 250 /**
209 251 * @param string $string
210 252 * @param array $data
211 - *
253 + * @param Closure|string $escape_function
212 254 * @return string
213 255 */
214 -function hf_replace_data_variables( $string, $data = array() ) {
215 - $string = preg_replace_callback( '/\[([a-zA-Z0-9\-\._]+)\]/', function( $matches ) use ( $data ) {
216 - $key = $matches[1];
217 - $replacement = hf_array_get( $data, $key, '' );
218 - $replacement = is_array( $replacement ) ? join( ', ', $replacement ) : $replacement;
219 - return $replacement;
220 - }, $string );
221 - return $string;
256 +function hf_replace_data_variables( $string, $data = array(), $escape_function = null ) {
257 + return preg_replace_callback(
258 + '/\[(.+?)\]/',
259 + function( $matches ) use ( $data, $escape_function ) {
260 + $key = $matches[1];
261 + // replace spaces in name with underscores to match PHP requirement for keys in $_POST superglobal
262 + $key = str_replace( ' ', '_', $key );
263 + $replacement = hf_array_get( $data, $key, '' );
264 + $replacement = hf_field_value( $replacement, 0, $escape_function );
265 + return $replacement;
266 + },
267 + $string
268 + );
222 269 }
223 270
224 271 /**
225 -* Poor man's file object, compatible with serialization..
272 +* Returns a formatted & HTML-escaped field value. Detects file-, array- and date-types.
226 273 *
274 +* Caveat: if value is a file, an HTML string is returned (which means email action should use "Content-Type: html" when it includes a file field).
275 +*
276 +* @param string|array $value
277 +* @param int $limit
278 +* @param Closure|string $escape_function
279 +* @return string
280 +* @since 1.3.1
281 +*/
282 +function hf_field_value( $value, $limit = 0, $escape_function = 'esc_html' ) {
283 + if ( $value === '' ) {
284 + return $value;
285 + }
286 +
287 + if ( hf_is_file( $value ) ) {
288 + $file_url = isset( $value['url'] ) ? $value['url'] : '';
289 + if ( isset( $value['attachment_id'] ) && apply_filters( 'hf_file_upload_use_direct_links', false ) === false ) {
290 + $file_url = admin_url( sprintf( 'post.php?action=edit&post=%d', $value['attachment_id'] ) );
291 + }
292 + $short_name = substr( $value['name'], 0, 20 );
293 + $suffix = strlen( $value['name'] ) > 20 ? '...' : '';
294 + return sprintf( '<a href="%s">%s%s</a> (%s)', esc_attr( $file_url ), esc_html( $short_name ), esc_html( $suffix ), hf_human_filesize( $value['size'] ) );
295 + }
296 +
297 + if ( hf_is_date( $value ) ) {
298 + $date_format = get_option( 'date_format' );
299 + return gmdate( $date_format, strtotime( str_replace( '/', '-', $value ) ) );
300 + }
301 +
302 + // join array-values with comma
303 + if ( is_array( $value ) ) {
304 + $value = join( ', ', $value );
305 + }
306 +
307 + // limit string to certain length
308 + if ( $limit > 0 ) {
309 + $limited = strlen( $value ) > $limit;
310 + $value = substr( $value, 0, $limit );
311 +
312 + if ( $limited ) {
313 + $value .= '...';
314 + }
315 + }
316 +
317 + // escape value
318 + if ( $escape_function !== null && is_callable( $escape_function ) ) {
319 + $value = $escape_function( $value );
320 + }
321 +
322 + // add line breaks, if not string limited to certain length
323 + if ( $limit === 0 ) {
324 + $value = nl2br( $value );
325 + }
326 +
327 + return $value;
328 +}
329 +
330 +/**
331 +* Returns true if value is a "file"
332 +*
333 +* @param mixed $value
227 334 * @return bool
228 335 */
229 -function hf_is_file( $file ) {
230 - return isset( $file['name'] ) && isset( $file['size'] ) && isset( $file['type'] );
336 +function hf_is_file( $value ) {
337 + return is_array( $value )
338 + && isset( $value['name'] )
339 + && isset( $value['size'] )
340 + && isset( $value['type'] );
231 341 }
232 342
233 -/**
234 -* @return string
343 +/**
344 +* Returns true if value looks like a date-string submitted from a <input type="date">
345 +* @param mixed $value
346 +* @return bool
347 +* @since 1.3.1
235 348 */
236 -function hf_human_filesize($size, $precision = 2) {
237 - for( $i = 0; ($size / 1024) > 0.9; $i++, $size /= 1024 ) {
238 - // nothing, loop logic contains everything
239 - }
240 - $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
241 - return round($size, $precision) . $steps[$i];
349 +function hf_is_date( $value ) {
350 + if ( ! is_string( $value )
351 + || strlen( $value ) !== 10
352 + || (int) preg_match( '/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/', $value ) === 0 ) {
353 + return false;
354 + }
355 +
356 + $timestamp = strtotime( $value );
357 + return $timestamp != false;
358 +}
359 +
360 +/**
361 + * @param int $size
362 + * @param int $precision
363 + * @return string
364 +*/
365 +function hf_human_filesize( $size, $precision = 2 ) {
366 + for ( $i = 0; ( $size / 1024 ) > 0.9; $i++, $size /= 1024 ) {
367 + // nothing, loop logic contains everything
368 + }
369 + $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
370 + return round( $size, $precision ) . $steps[ $i ];
371 +}
372 +
373 +/**
374 + * Gets all the form tabs to show in the admin.
375 + * @param Form $form
376 + * @return array
377 + */
378 +function hf_get_admin_tabs( Form $form ) {
379 + $tabs = array(
380 + 'fields' => __( 'Fields', 'html-forms' ),
381 + 'messages' => __( 'Messages', 'html-forms' ),
382 + 'settings' => __( 'Settings', 'html-forms' ),
383 + 'actions' => __( 'Actions', 'html-forms' ),
384 + );
385 +
386 + if ( $form->settings['save_submissions'] ) {
387 + $tabs['submissions'] = __( 'Submissions', 'html-forms' );
388 + }
389 + return apply_filters( 'hf_admin_tabs', $tabs, $form );
390 +}
391 +
392 +function _hf_on_plugin_activation() {
393 + if ( is_multisite() ) {
394 + _hf_on_plugin_activation_multisite();
395 + return;
396 + }
397 +
398 + // install table for regular wp install
399 + _hf_create_submissions_table();
400 +
401 + // add "edit_forms" cap to user that activated the plugin
402 + $user = wp_get_current_user();
403 + $user->add_cap( 'edit_forms', true );
404 +}
405 +
406 +function _hf_on_plugin_activation_multisite() {
407 + $added_caps = array();
408 +
409 + foreach ( get_sites( array( 'number' => PHP_INT_MAX ) ) as $site ) {
410 + switch_to_blog( (int) $site->blog_id );
411 +
412 + // install table for current blog
413 + _hf_create_submissions_table();
414 +
415 + // iterate through current blog admins
416 + foreach ( get_users(
417 + array(
418 + 'blog_id' => (int) $site->blog_id,
419 + 'role' => 'administrator',
420 + 'fields' => 'ID',
421 + )
422 + ) as $admin_id ) {
423 + if ( ! (int) $admin_id || in_array( $admin_id, $added_caps ) ) {
424 + continue;
425 + }
426 +
427 + // add "edit_forms" cap to site admin
428 + $user = new \WP_User( (int) $admin_id );
429 + $user->add_cap( 'edit_forms', true );
430 +
431 + $added_caps[] = $admin_id;
432 + }
433 +
434 + restore_current_blog();
435 + }
436 +}
437 +
438 +// install table for main site on regular installs, or active site for multisite
439 +function _hf_create_submissions_table() {
440 + /** @var wpdb */
441 + global $wpdb;
442 +
443 + $charset_collate = $wpdb->get_charset_collate();
444 +
445 + // create table for storing submissions
446 + $table = $wpdb->prefix . 'hf_submissions';
447 + $wpdb->query(
448 + "CREATE TABLE IF NOT EXISTS {$table}(
449 + `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
450 + `form_id` INT UNSIGNED NOT NULL,
451 + `data` TEXT NOT NULL,
452 + `user_agent` TEXT NULL,
453 + `ip_address` VARCHAR(255) NULL,
454 + `referer_url` TEXT NULL,
455 + `submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
456 +) {$charset_collate};"
457 + );
458 +}
459 +
460 +function _hf_on_add_user_to_blog( $user_id, $role, $blog_id ) {
461 + if ( 'administrator' !== $role ) {
462 + return;
463 + }
464 +
465 + // add "edit_forms" cap to site admin
466 + $user = new \WP_User( (int) $user_id );
467 + $user->add_cap( 'edit_forms', true );
468 +}
469 +
470 +function _hf_on_wp_insert_site( \WP_Site $site ) {
471 + switch_to_blog( (int) $site->blog_id );
472 + _hf_create_submissions_table();
473 + restore_current_blog();
242 474 }