PluginProbe
HTML Forms – Simple WordPress Forms Plugin / 1.7.0
HTML Forms – Simple WordPress Forms Plugin v1.7.0
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 +209 -17 1.3.151.7.0 View file →
@@ -77,8 +77,10 @@
77 77 'success' => __( 'Thank you! We will be in touch soon.', 'html-forms' ),
78 78 'invalid_email' => __( 'Sorry, that email address looks invalid.', 'html-forms' ),
79 79 'required_field_missing' => __( 'Please fill in the required fields.', 'html-forms' ),
80 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' ),
81 83 );
82 84 $default_messages = apply_filters( 'hf_form_default_messages', $default_messages );
83 85 $messages = array();
84 86 foreach ( $post_meta as $meta_key => $meta_values ) {
@@ -100,21 +102,49 @@
100 102 }
101 103
102 104 /**
103 105 * @param $form_id
106 + * @return int
107 + */
108 +function hf_count_form_submissions( $form_id, $search = '' ) {
109 + global $wpdb;
110 + $table = $wpdb->prefix . 'hf_submissions';
111 + if ( $search !== '' ) {
112 + $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} s WHERE s.form_id = %d AND s.data LIKE %s;", $form_id, '%' . $wpdb->esc_like( $search ) . '%' ) );
113 + } else {
114 + $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} s WHERE s.form_id = %d;", $form_id ) );
115 + }
116 + return (int) $result;
117 +}
118 +
119 +/**
120 + * @param $form_id
104 121 * @param array $args
105 122 * @return Submission[]
106 123 */
107 124 function hf_get_form_submissions( $form_id, array $args = array() ) {
108 125 $default_args = array(
109 - 'offset' => 0,
110 - 'limit' => 1000,
126 + 'offset' => 0,
127 + 'limit' => 1000,
128 + 'orderby' => 'submitted_at',
129 + 'order' => 'DESC',
130 + 'search' => '',
111 131 );
112 - $args = array_merge( $default_args, $args );
132 + $args = array_merge( $default_args, $args );
113 133
134 + $allowed_orderby = array( 'submitted_at', 'id' );
135 + $orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? $args['orderby'] : 'submitted_at';
136 + $order = strtoupper( $args['order'] ) === 'ASC' ? 'ASC' : 'DESC';
137 +
114 138 global $wpdb;
115 - $table = $wpdb->prefix . 'hf_submissions';
116 - $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 );
139 + $table = $wpdb->prefix . 'hf_submissions';
140 + if ( $args['search'] !== '' ) {
141 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby and $order are whitelisted above
142 + $results = $wpdb->get_results( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.form_id = %d AND s.data LIKE %s ORDER BY s.{$orderby} {$order} LIMIT %d, %d;", $form_id, '%' . $wpdb->esc_like( $args['search'] ) . '%', $args['offset'], $args['limit'] ), OBJECT_K );
143 + } else {
144 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared -- $orderby and $order are whitelisted above
145 + $results = $wpdb->get_results( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.form_id = %d ORDER BY s.{$orderby} {$order} LIMIT %d, %d;", $form_id, $args['offset'], $args['limit'] ), OBJECT_K );
146 + }
117 147 $submissions = array();
118 148 foreach ( $results as $key => $object ) {
119 149 $submission = Submission::from_object( $object );
120 150 $submissions[ $key ] = $submission;
@@ -137,9 +167,15 @@
137 167 * @return array
138 168 */
139 169 function hf_get_settings() {
140 170 $default_settings = array(
171 + 'enable_nonce' => 0,
141 172 'load_stylesheet' => 0,
173 + 'wrapper_tag' => 'p',
174 + 'google_recaptcha' => array(
175 + 'site_key' => '',
176 + 'secret_key' => '',
177 + ),
142 178 );
143 179
144 180 $settings = get_option( 'hf_settings', null );
145 181
@@ -150,8 +186,16 @@
150 186 }
151 187
152 188 // merge with default settings
153 189 $settings = array_merge( $default_settings, $settings );
190 +
191 + // Ensure nested arrays are properly merged
192 + if ( isset( $default_settings['google_recaptcha'] ) ) {
193 + $settings['google_recaptcha'] = array_merge(
194 + $default_settings['google_recaptcha'],
195 + isset( $settings['google_recaptcha'] ) ? $settings['google_recaptcha'] : array()
196 + );
197 + }
154 198
155 199 /**
156 200 * Filters the global HTML Forms hf_settings
157 201 *
@@ -241,20 +285,48 @@
241 285 * @param array $data
242 286 * @param Closure|string $escape_function
243 287 * @return string
244 288 */
245 -function hf_replace_data_variables( $string, $data = array(), $escape_function = null ) {
246 - $string = preg_replace_callback(
247 - '/\[([a-zA-Z0-9\-\._]+)\]/',
248 - function( $matches ) use ( $data, $escape_function ) {
249 - $key = $matches[1];
250 - $replacement = hf_array_get( $data, $key, '' );
251 - $replacement = hf_field_value( $replacement, 0, $escape_function );
289 +function hf_replace_data_variables( $string, Submission $submission, $escape_function = null ) {
290 + $data = ( !empty( $submission->data ) ? $submission->data : array() );
291 + $submission_fields = array( 'HF_TIMESTAMP', 'HF_USER_AGENT', 'HF_IP_ADDRESS', 'HF_REFERRER_URL' );
292 +
293 + return preg_replace_callback(
294 + '/\[(.+?)\]/',
295 + function( $matches ) use ( $submission, $submission_fields, $escape_function ) {
296 + $key = $matches[1];
297 +
298 + if ( in_array( $key, $submission_fields ) ) {
299 + $replacement = '';
300 +
301 + switch ( $key ) {
302 + case 'HF_TIMESTAMP' :
303 + $replacement = $submission->submitted_at;
304 + break;
305 + case 'HF_USER_AGENT' :
306 + $replacement = $submission->user_agent;
307 + break;
308 + case 'HF_IP_ADDRESS' :
309 + $replacement = $submission->ip_address;
310 + break;
311 + case 'HF_REFERRER_URL' :
312 + $replacement = $submission->referer_url;
313 + break;
314 + default :
315 + $replacement = '';
316 + break;
317 + }
318 + } else {
319 + // replace spaces in name with underscores to match PHP requirement for keys in $_POST superglobal
320 + $key = str_replace( ' ', '_', $key );
321 + $replacement = hf_array_get( $submission->data, $key, '' );
322 + $replacement = hf_field_value( $replacement, 0, $escape_function );
323 + }
324 +
252 325 return $replacement;
253 326 },
254 327 $string
255 328 );
256 - return $string;
257 329 }
258 330
259 331 /**
260 332 * Returns a formatted & HTML-escaped field value. Detects file-, array- and date-types.
@@ -272,20 +344,33 @@
272 344 return $value;
273 345 }
274 346
275 347 if ( hf_is_file( $value ) ) {
348 + if ( ! is_array( $value )
349 + || ! isset( $value['name'] )
350 + || ! isset( $value['size'] )
351 + || ! isset( $value['type'] ) ) {
352 + return false;
353 + }
354 +
355 + // Verify attachment exists
356 + if ( isset( $value['attachment_id'] ) && get_post( $value['attachment_id'] ) == null ) {
357 + return __( 'File not found', 'html-forms' );
358 + }
359 +
276 360 $file_url = isset( $value['url'] ) ? $value['url'] : '';
277 - if ( isset( $value['attachment_id'] ) ) {
361 + if ( isset( $value['attachment_id'] ) && apply_filters( 'hf_file_upload_use_direct_links', false ) === false ) {
278 362 $file_url = admin_url( sprintf( 'post.php?action=edit&post=%d', $value['attachment_id'] ) );
279 363 }
364 +
280 365 $short_name = substr( $value['name'], 0, 20 );
281 366 $suffix = strlen( $value['name'] ) > 20 ? '...' : '';
282 - 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'] ) );
367 + 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'] ) );
283 368 }
284 369
285 370 if ( hf_is_date( $value ) ) {
286 371 $date_format = get_option( 'date_format' );
287 - return gmdate( $date_format, strtotime( $value ) );
372 + return gmdate( $date_format, strtotime( str_replace( '/', '-', $value ) ) );
288 373 }
289 374
290 375 // join array-values with comma
291 376 if ( is_array( $value ) ) {
@@ -306,8 +391,13 @@
306 391 if ( $escape_function !== null && is_callable( $escape_function ) ) {
307 392 $value = $escape_function( $value );
308 393 }
309 394
395 + // add line breaks, if not string limited to certain length
396 + if ( $limit === 0 ) {
397 + $value = nl2br( $value );
398 + }
399 +
310 400 return $value;
311 401 }
312 402
313 403 /**
@@ -329,9 +419,8 @@
329 419 * @return bool
330 420 * @since 1.3.1
331 421 */
332 422 function hf_is_date( $value ) {
333 -
334 423 if ( ! is_string( $value )
335 424 || strlen( $value ) !== 10
336 425 || (int) preg_match( '/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/', $value ) === 0 ) {
337 426 return false;
@@ -351,5 +440,108 @@
351 440 // nothing, loop logic contains everything
352 441 }
353 442 $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' );
354 443 return round( $size, $precision ) . $steps[ $i ];
444 +}
445 +
446 +/**
447 + * Gets all the form tabs to show in the admin.
448 + * @param Form $form
449 + * @return array
450 + */
451 +function hf_get_admin_tabs( Form $form ) {
452 + $tabs = array(
453 + 'fields' => __( 'Fields', 'html-forms' ),
454 + 'messages' => __( 'Messages', 'html-forms' ),
455 + 'settings' => __( 'Settings', 'html-forms' ),
456 + 'actions' => __( 'Actions', 'html-forms' ),
457 + );
458 +
459 + if ( $form->settings['save_submissions'] ) {
460 + $tabs['submissions'] = __( 'Submissions', 'html-forms' );
461 + }
462 + return apply_filters( 'hf_admin_tabs', $tabs, $form );
463 +}
464 +
465 +function _hf_on_plugin_activation() {
466 + if ( is_multisite() ) {
467 + _hf_on_plugin_activation_multisite();
468 + return;
469 + }
470 +
471 + // install table for regular wp install
472 + _hf_create_submissions_table();
473 +
474 + // add "edit_forms" cap to user that activated the plugin
475 + $user = wp_get_current_user();
476 + $user->add_cap( 'edit_forms', true );
477 +}
478 +
479 +function _hf_on_plugin_activation_multisite() {
480 + $added_caps = array();
481 +
482 + foreach ( get_sites( array( 'number' => PHP_INT_MAX ) ) as $site ) {
483 + switch_to_blog( (int) $site->blog_id );
484 +
485 + // install table for current blog
486 + _hf_create_submissions_table();
487 +
488 + // iterate through current blog admins
489 + foreach ( get_users(
490 + array(
491 + 'blog_id' => (int) $site->blog_id,
492 + 'role' => 'administrator',
493 + 'fields' => 'ID',
494 + )
495 + ) as $admin_id ) {
496 + if ( ! (int) $admin_id || in_array( $admin_id, $added_caps ) ) {
497 + continue;
498 + }
499 +
500 + // add "edit_forms" cap to site admin
501 + $user = new \WP_User( (int) $admin_id );
502 + $user->add_cap( 'edit_forms', true );
503 +
504 + $added_caps[] = $admin_id;
505 + }
506 +
507 + restore_current_blog();
508 + }
509 +}
510 +
511 +// install table for main site on regular installs, or active site for multisite
512 +function _hf_create_submissions_table() {
513 + /** @var wpdb */
514 + global $wpdb;
515 +
516 + $charset_collate = $wpdb->get_charset_collate();
517 +
518 + // create table for storing submissions
519 + $table = $wpdb->prefix . 'hf_submissions';
520 + $wpdb->query(
521 + "CREATE TABLE IF NOT EXISTS {$table}(
522 + `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT,
523 + `form_id` INT UNSIGNED NOT NULL,
524 + `data` TEXT NOT NULL,
525 + `user_agent` TEXT NULL,
526 + `ip_address` VARCHAR(255) NULL,
527 + `referer_url` TEXT NULL,
528 + `submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
529 +) {$charset_collate};"
530 + );
531 +}
532 +
533 +function _hf_on_add_user_to_blog( $user_id, $role, $blog_id ) {
534 + if ( 'administrator' !== $role ) {
535 + return;
536 + }
537 +
538 + // add "edit_forms" cap to site admin
539 + $user = new \WP_User( (int) $user_id );
540 + $user->add_cap( 'edit_forms', true );
541 +}
542 +
543 +function _hf_on_wp_insert_site( \WP_Site $site ) {
544 + switch_to_blog( (int) $site->blog_id );
545 + _hf_create_submissions_table();
546 + restore_current_blog();
355 547 }