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

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