PluginProbe
HTML Forms – Simple WordPress Forms Plugin / trunk
HTML Forms – Simple WordPress Forms Plugin vtrunk
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 trunk, at src/functions.php

531 lines 14.9 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 if ( ! is_array( $value )
332 || ! isset( $value['name'] )
333 || ! isset( $value['size'] )
334 || ! isset( $value['type'] ) ) {
335 return false;
336 }
337
338 // Verify attachment exists
339 if ( isset( $value['attachment_id'] ) && get_post( $value['attachment_id'] ) == null ) {
340 return __( 'File not found', 'html-forms' );
341 }
342
343 $file_url = isset( $value['url'] ) ? $value['url'] : '';
344 if ( isset( $value['attachment_id'] ) && apply_filters( 'hf_file_upload_use_direct_links', false ) === false ) {
345 $file_url = admin_url( sprintf( 'post.php?action=edit&post=%d', $value['attachment_id'] ) );
346 }
347
348 $short_name = substr( $value['name'], 0, 20 );
349 $suffix = strlen( $value['name'] ) > 20 ? '...' : '';
350 return sprintf( '<a href="%s">%s%s</a> (%s)', esc_url( $file_url ), esc_html( $short_name ), esc_html( $suffix ), hf_human_filesize( $value['size'] ) );
351 }
352
353 if ( hf_is_date( $value ) ) {
354 $date_format = get_option( 'date_format' );
355 return gmdate( $date_format, strtotime( str_replace( '/', '-', $value ) ) );
356 }
357
358 // join array-values with comma
359 if ( is_array( $value ) ) {
360 $value = join( ', ', $value );
361 }
362
363 // limit string to certain length
364 if ( $limit > 0 ) {
365 $limited = strlen( $value ) > $limit;
366 $value = substr( $value, 0, $limit );
367
368 if ( $limited ) {
369 $value .= '...';
370 }
371 }
372
373 // escape value
374 if ( $escape_function !== null && is_callable( $escape_function ) ) {
375 $value = $escape_function( $value );
376 }
377
378 // add line breaks, if not string limited to certain length
379 if ( $limit === 0 ) {
380 $value = nl2br( $value );
381 }
382
383 return $value;
384 }
385
386 /**
387 * Returns true if value is a "file"
388 *
389 * @param mixed $value
390 * @return bool
391 */
392 function hf_is_file( $value ) {
393 return is_array( $value )
394 && isset( $value['name'] )
395 && isset( $value['size'] )
396 && isset( $value['type'] );
397 }
398
399 /**
400 * Returns true if value looks like a date-string submitted from a <input type="date">
401 * @param mixed $value
402 * @return bool
403 * @since 1.3.1
404 */
405 function hf_is_date( $value ) {
406 if ( ! is_string( $value )
407 || strlen( $value ) !== 10
408 || (int) preg_match( '/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/', $value ) === 0 ) {
409 return false;
410 }
411
412 $timestamp = strtotime( $value );
413 return $timestamp != false;
414 }
415
416 /**
417 * @param int $size
418 * @param int $precision
419 * @return string
420 */
421 function hf_human_filesize( $size, $precision = 2 ) {
422 for ( $i = 0; ( $size / 1024 ) > 0.9; $i++, $size /= 1024 ) {
423 // nothing, loop logic contains everything
424 }
425 $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
426 return round( $size, $precision ) . $steps[ $i ];
427 }
428
429 /**
430 * Gets all the form tabs to show in the admin.
431 * @param Form $form
432 * @return array
433 */
434 function hf_get_admin_tabs( Form $form ) {
435 $tabs = array(
436 'fields' => __( 'Fields', 'html-forms' ),
437 'messages' => __( 'Messages', 'html-forms' ),
438 'settings' => __( 'Settings', 'html-forms' ),
439 'actions' => __( 'Actions', 'html-forms' ),
440 );
441
442 if ( $form->settings['save_submissions'] ) {
443 $tabs['submissions'] = __( 'Submissions', 'html-forms' );
444 }
445 return apply_filters( 'hf_admin_tabs', $tabs, $form );
446 }
447
448 function _hf_on_plugin_activation() {
449 if ( is_multisite() ) {
450 _hf_on_plugin_activation_multisite();
451 return;
452 }
453
454 // install table for regular wp install
455 _hf_create_submissions_table();
456
457 // add "edit_forms" cap to user that activated the plugin
458 $user = wp_get_current_user();
459 $user->add_cap( 'edit_forms', true );
460 }
461
462 function _hf_on_plugin_activation_multisite() {
463 $added_caps = array();
464
465 foreach ( get_sites( array( 'number' => PHP_INT_MAX ) ) as $site ) {
466 switch_to_blog( (int) $site->blog_id );
467
468 // install table for current blog
469 _hf_create_submissions_table();
470
471 // iterate through current blog admins
472 foreach ( get_users(
473 array(
474 'blog_id' => (int) $site->blog_id,
475 'role' => 'administrator',
476 'fields' => 'ID',
477 )
478 ) as $admin_id ) {
479 if ( ! (int) $admin_id || in_array( $admin_id, $added_caps ) ) {
480 continue;
481 }
482
483 // add "edit_forms" cap to site admin
484 $user = new \WP_User( (int) $admin_id );
485 $user->add_cap( 'edit_forms', true );
486
487 $added_caps[] = $admin_id;
488 }
489
490 restore_current_blog();
491 }
492 }
493
494 // install table for main site on regular installs, or active site for multisite
495 function _hf_create_submissions_table() {
496 /** @var wpdb */
497 global $wpdb;
498
499 $charset_collate = $wpdb->get_charset_collate();
500
501 // create table for storing submissions
502 $table = $wpdb->prefix . 'hf_submissions';
503 $wpdb->query(
504 "CREATE TABLE IF NOT EXISTS {$table}(
505 `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
506 `form_id` INT UNSIGNED NOT NULL,
507 `data` TEXT NOT NULL,
508 `user_agent` TEXT NULL,
509 `ip_address` VARCHAR(255) NULL,
510 `referer_url` TEXT NULL,
511 `submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
512 ) {$charset_collate};"
513 );
514 }
515
516 function _hf_on_add_user_to_blog( $user_id, $role, $blog_id ) {
517 if ( 'administrator' !== $role ) {
518 return;
519 }
520
521 // add "edit_forms" cap to site admin
522 $user = new \WP_User( (int) $user_id );
523 $user->add_cap( 'edit_forms', true );
524 }
525
526 function _hf_on_wp_insert_site( \WP_Site $site ) {
527 switch_to_blog( (int) $site->blog_id );
528 _hf_create_submissions_table();
529 restore_current_blog();
530 }
531