PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.6.0
HTML Forms – Simple WordPress Forms Plugin v1.6.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 1.3.17 All 66 releases
html-forms / src / functions.php

functions.php in HTML Forms – Simple WordPress Forms Plugin 1.6.0, at src/functions.php

518 lines 14.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 use HTML_Forms\Form;
4 use HTML_Forms\Submission;
5
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 /**
26 * @param $form_id_or_slug int|string|WP_Post
27 * @return Form
28 * @throws Exception
29 */
30 function hf_get_form( $form_id_or_slug ) {
31
32 if ( is_numeric( $form_id_or_slug ) || $form_id_or_slug instanceof WP_Post ) {
33 $post = get_post( $form_id_or_slug );
34
35 if ( ! $post instanceof WP_Post || $post->post_type !== 'html-form' ) {
36 throw new Exception( 'Invalid form ID' );
37 }
38 } else {
39
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 }
56
57 // get all post meta in a single call for performance
58 $post_meta = get_post_meta( $post->ID );
59
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 );
74
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 'recaptcha_failed' => __( 'reCAPTCHA verification failed. Please try again.', 'html-forms' ),
82 'recaptcha_low_score' => __( 'Your submission appears to be spam. Please try again.', 'html-forms' ),
83 );
84 $default_messages = apply_filters( 'hf_form_default_messages', $default_messages );
85 $messages = array();
86 foreach ( $post_meta as $meta_key => $meta_values ) {
87 if ( strpos( $meta_key, 'hf_message_' ) === 0 ) {
88 $message_key = substr( $meta_key, strlen( 'hf_message_' ) );
89 $messages[ $message_key ] = (string) $meta_values[0];
90 }
91 }
92 $messages = array_merge( $default_messages, $messages );
93
94 // finally, create form instance
95 $form = new Form( $post->ID );
96 $form->title = $post->post_title;
97 $form->slug = $post->post_name;
98 $form->markup = $post->post_content;
99 $form->settings = $settings;
100 $form->messages = $messages;
101 return $form;
102 }
103
104 /**
105 * @param $form_id
106 * @return int
107 */
108 function hf_count_form_submissions( $form_id ) {
109 global $wpdb;
110 $table = $wpdb->prefix . 'hf_submissions';
111 $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} s WHERE s.form_id = %d;", $form_id ) );
112 return (int) $result;
113 }
114
115 /**
116 * @param $form_id
117 * @param array $args
118 * @return Submission[]
119 */
120 function hf_get_form_submissions( $form_id, array $args = array() ) {
121 $default_args = array(
122 'offset' => 0,
123 'limit' => 1000,
124 );
125 $args = array_merge( $default_args, $args );
126
127 global $wpdb;
128 $table = $wpdb->prefix . 'hf_submissions';
129 $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 );
130 $submissions = array();
131 foreach ( $results as $key => $object ) {
132 $submission = Submission::from_object( $object );
133 $submissions[ $key ] = $submission;
134 }
135 return $submissions;
136 }
137
138 /**
139 * @param int $submission_id
140 * @return Submission
141 */
142 function hf_get_form_submission( $submission_id ) {
143 global $wpdb;
144 $table = $wpdb->prefix . 'hf_submissions';
145 $object = $wpdb->get_row( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.id = %d;", $submission_id ), OBJECT );
146 $submission = Submission::from_object( $object );
147 return $submission;
148 }
149 /**
150 * @return array
151 */
152 function hf_get_settings() {
153 $default_settings = array(
154 'enable_nonce' => 0,
155 'load_stylesheet' => 0,
156 'wrapper_tag' => 'p',
157 'google_recaptcha' => array(
158 'site_key' => '',
159 'secret_key' => '',
160 ),
161 );
162
163 $settings = get_option( 'hf_settings', null );
164
165 // prevent a SQL query when option does not yet exist
166 if ( $settings === null ) {
167 update_option( 'hf_settings', array(), true );
168 $settings = array();
169 }
170
171 // merge with default settings
172 $settings = array_merge( $default_settings, $settings );
173
174 // Ensure nested arrays are properly merged
175 if ( isset( $default_settings['google_recaptcha'] ) ) {
176 $settings['google_recaptcha'] = array_merge(
177 $default_settings['google_recaptcha'],
178 isset( $settings['google_recaptcha'] ) ? $settings['google_recaptcha'] : array()
179 );
180 }
181
182 /**
183 * Filters the global HTML Forms hf_settings
184 *
185 * @param array $settings
186 */
187 $settings = apply_filters( 'hf_settings', $settings );
188
189 return $settings;
190 }
191
192 /**
193 * Get element from array, allows for dot notation eg: "foo.bar"
194 *
195 * @param array $array
196 * @param string $key
197 * @param mixed $default
198 * @return mixed
199 */
200 function hf_array_get( $array, $key, $default = null ) {
201 if ( is_null( $key ) ) {
202 return $array;
203 }
204
205 if ( isset( $array[ $key ] ) ) {
206 return $array[ $key ];
207 }
208
209 foreach ( explode( '.', $key ) as $segment ) {
210 if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) {
211 return $default;
212 }
213
214 $array = $array[ $segment ];
215 }
216
217 return $array;
218 }
219
220 /**
221 * Processes template tags like {{user.user_email}}
222 *
223 * @param string $template
224 *
225 * @return string
226 */
227 function hf_template( $template ) {
228 $replacers = new HTML_Forms\TagReplacers();
229 $tags = array(
230 'user' => array( $replacers, 'user' ),
231 'post' => array( $replacers, 'post' ),
232 'url_params' => array( $replacers, 'url_params' ),
233 );
234
235 /**
236 * Filters the available tags in HTML Forms templates, like {{user.user_email}}.
237 *
238 * Can be used to add simple scalar replacements or more advanced replacement functions that accept a parameter.
239 *
240 * @param array $tags
241 */
242 $tags = apply_filters( 'hf_template_tags', $tags );
243
244 $template = preg_replace_callback(
245 '/\{\{ *(\w+)(?:\.([\w\.]+))? *(?:\|\| *(\w+))? *\}\}/',
246 function( $matches ) use ( $tags ) {
247 $tag = $matches[1];
248 $param = ! isset( $matches[2] ) ? '' : $matches[2];
249 $default = ! isset( $matches[3] ) ? '' : $matches[3];
250
251 // do not change anything if we have no replacer with that key, could be custom user logic or another plugin.
252 if ( ! isset( $tags[ $tag ] ) ) {
253 return $matches[0];
254 }
255
256 $replacement = $tags[ $tag ];
257 $value = is_callable( $replacement ) ? call_user_func_array( $replacement, array( $param ) ) : $replacement;
258 return ! empty( $value ) ? $value : $default;
259 },
260 $template
261 );
262
263 return $template;
264 }
265
266 /**
267 * @param string $string
268 * @param array $data
269 * @param Closure|string $escape_function
270 * @return string
271 */
272 function hf_replace_data_variables( $string, Submission $submission, $escape_function = null ) {
273 $data = ( !empty( $submission->data ) ? $submission->data : array() );
274 $submission_fields = array( 'HF_TIMESTAMP', 'HF_USER_AGENT', 'HF_IP_ADDRESS', 'HF_REFERRER_URL' );
275
276 return preg_replace_callback(
277 '/\[(.+?)\]/',
278 function( $matches ) use ( $submission, $submission_fields, $escape_function ) {
279 $key = $matches[1];
280
281 if ( in_array( $key, $submission_fields ) ) {
282 $replacement = '';
283
284 switch ( $key ) {
285 case 'HF_TIMESTAMP' :
286 $replacement = $submission->submitted_at;
287 break;
288 case 'HF_USER_AGENT' :
289 $replacement = $submission->user_agent;
290 break;
291 case 'HF_IP_ADDRESS' :
292 $replacement = $submission->ip_address;
293 break;
294 case 'HF_REFERRER_URL' :
295 $replacement = $submission->referer_url;
296 break;
297 default :
298 $replacement = '';
299 break;
300 }
301 } else {
302 // replace spaces in name with underscores to match PHP requirement for keys in $_POST superglobal
303 $key = str_replace( ' ', '_', $key );
304 $replacement = hf_array_get( $submission->data, $key, '' );
305 $replacement = hf_field_value( $replacement, 0, $escape_function );
306 }
307
308 return $replacement;
309 },
310 $string
311 );
312 }
313
314 /**
315 * Returns a formatted & HTML-escaped field value. Detects file-, array- and date-types.
316 *
317 * 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).
318 *
319 * @param string|array $value
320 * @param int $limit
321 * @param Closure|string $escape_function
322 * @return string
323 * @since 1.3.1
324 */
325 function hf_field_value( $value, $limit = 0, $escape_function = 'esc_html' ) {
326 if ( $value === '' ) {
327 return $value;
328 }
329
330 if ( hf_is_file( $value ) ) {
331 $file_url = isset( $value['url'] ) ? $value['url'] : '';
332 if ( isset( $value['attachment_id'] ) && apply_filters( 'hf_file_upload_use_direct_links', false ) === false ) {
333 $file_url = admin_url( sprintf( 'post.php?action=edit&post=%d', $value['attachment_id'] ) );
334 }
335 $short_name = substr( $value['name'], 0, 20 );
336 $suffix = strlen( $value['name'] ) > 20 ? '...' : '';
337 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'] ) );
338 }
339
340 if ( hf_is_date( $value ) ) {
341 $date_format = get_option( 'date_format' );
342 return gmdate( $date_format, strtotime( str_replace( '/', '-', $value ) ) );
343 }
344
345 // join array-values with comma
346 if ( is_array( $value ) ) {
347 $value = join( ', ', $value );
348 }
349
350 // limit string to certain length
351 if ( $limit > 0 ) {
352 $limited = strlen( $value ) > $limit;
353 $value = substr( $value, 0, $limit );
354
355 if ( $limited ) {
356 $value .= '...';
357 }
358 }
359
360 // escape value
361 if ( $escape_function !== null && is_callable( $escape_function ) ) {
362 $value = $escape_function( $value );
363 }
364
365 // add line breaks, if not string limited to certain length
366 if ( $limit === 0 ) {
367 $value = nl2br( $value );
368 }
369
370 return $value;
371 }
372
373 /**
374 * Returns true if value is a "file"
375 *
376 * @param mixed $value
377 * @return bool
378 */
379 function hf_is_file( $value ) {
380 return is_array( $value )
381 && isset( $value['name'] )
382 && isset( $value['size'] )
383 && isset( $value['type'] );
384 }
385
386 /**
387 * Returns true if value looks like a date-string submitted from a <input type="date">
388 * @param mixed $value
389 * @return bool
390 * @since 1.3.1
391 */
392 function hf_is_date( $value ) {
393 if ( ! is_string( $value )
394 || strlen( $value ) !== 10
395 || (int) preg_match( '/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/', $value ) === 0 ) {
396 return false;
397 }
398
399 $timestamp = strtotime( $value );
400 return $timestamp != false;
401 }
402
403 /**
404 * @param int $size
405 * @param int $precision
406 * @return string
407 */
408 function hf_human_filesize( $size, $precision = 2 ) {
409 for ( $i = 0; ( $size / 1024 ) > 0.9; $i++, $size /= 1024 ) {
410 // nothing, loop logic contains everything
411 }
412 $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
413 return round( $size, $precision ) . $steps[ $i ];
414 }
415
416 /**
417 * Gets all the form tabs to show in the admin.
418 * @param Form $form
419 * @return array
420 */
421 function hf_get_admin_tabs( Form $form ) {
422 $tabs = array(
423 'fields' => __( 'Fields', 'html-forms' ),
424 'messages' => __( 'Messages', 'html-forms' ),
425 'settings' => __( 'Settings', 'html-forms' ),
426 'actions' => __( 'Actions', 'html-forms' ),
427 );
428
429 if ( $form->settings['save_submissions'] ) {
430 $tabs['submissions'] = __( 'Submissions', 'html-forms' );
431 }
432 return apply_filters( 'hf_admin_tabs', $tabs, $form );
433 }
434
435 function _hf_on_plugin_activation() {
436 if ( is_multisite() ) {
437 _hf_on_plugin_activation_multisite();
438 return;
439 }
440
441 // install table for regular wp install
442 _hf_create_submissions_table();
443
444 // add "edit_forms" cap to user that activated the plugin
445 $user = wp_get_current_user();
446 $user->add_cap( 'edit_forms', true );
447 }
448
449 function _hf_on_plugin_activation_multisite() {
450 $added_caps = array();
451
452 foreach ( get_sites( array( 'number' => PHP_INT_MAX ) ) as $site ) {
453 switch_to_blog( (int) $site->blog_id );
454
455 // install table for current blog
456 _hf_create_submissions_table();
457
458 // iterate through current blog admins
459 foreach ( get_users(
460 array(
461 'blog_id' => (int) $site->blog_id,
462 'role' => 'administrator',
463 'fields' => 'ID',
464 )
465 ) as $admin_id ) {
466 if ( ! (int) $admin_id || in_array( $admin_id, $added_caps ) ) {
467 continue;
468 }
469
470 // add "edit_forms" cap to site admin
471 $user = new \WP_User( (int) $admin_id );
472 $user->add_cap( 'edit_forms', true );
473
474 $added_caps[] = $admin_id;
475 }
476
477 restore_current_blog();
478 }
479 }
480
481 // install table for main site on regular installs, or active site for multisite
482 function _hf_create_submissions_table() {
483 /** @var wpdb */
484 global $wpdb;
485
486 $charset_collate = $wpdb->get_charset_collate();
487
488 // create table for storing submissions
489 $table = $wpdb->prefix . 'hf_submissions';
490 $wpdb->query(
491 "CREATE TABLE IF NOT EXISTS {$table}(
492 `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
493 `form_id` INT UNSIGNED NOT NULL,
494 `data` TEXT NOT NULL,
495 `user_agent` TEXT NULL,
496 `ip_address` VARCHAR(255) NULL,
497 `referer_url` TEXT NULL,
498 `submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
499 ) {$charset_collate};"
500 );
501 }
502
503 function _hf_on_add_user_to_blog( $user_id, $role, $blog_id ) {
504 if ( 'administrator' !== $role ) {
505 return;
506 }
507
508 // add "edit_forms" cap to site admin
509 $user = new \WP_User( (int) $user_id );
510 $user->add_cap( 'edit_forms', true );
511 }
512
513 function _hf_on_wp_insert_site( \WP_Site $site ) {
514 switch_to_blog( (int) $site->blog_id );
515 _hf_create_submissions_table();
516 restore_current_blog();
517 }
518