'html-form', 'post_status' => array( 'publish', 'draft', 'pending', 'future' ), 'posts_per_page' => -1, 'ignore_sticky_posts' => true, 'no_found_rows' => true, ); $args = array_merge( $default_args, $args ); $query = new WP_Query; $posts = $query->query( $args ); $forms = array_map( 'hf_get_form', $posts ); return $forms; } /** * @param $form_id_or_slug int|string|WP_Post * @return Form * @throws Exception */ function hf_get_form( $form_id_or_slug ) { if ( is_numeric( $form_id_or_slug ) || $form_id_or_slug instanceof WP_Post ) { $post = get_post( $form_id_or_slug ); if ( ! $post instanceof WP_Post || $post->post_type !== 'html-form' ) { throw new Exception( 'Invalid form ID' ); } } else { $query = new WP_Query; $posts = $query->query( array( 'post_type' => 'html-form', 'name' => $form_id_or_slug, 'post_status' => 'publish', 'posts_per_page' => 1, 'ignore_sticky_posts' => true, 'no_found_rows' => true, ) ); if ( empty( $posts ) ) { throw new Exception( 'Invalid form slug' ); } $post = $posts[0]; } // get all post meta in a single call for performance $post_meta = get_post_meta( $post->ID ); // grab & merge form settings $default_settings = array( 'save_submissions' => 1, 'hide_after_success' => 0, 'redirect_url' => '', 'required_fields' => '', 'email_fields' => '', ); $default_settings = apply_filters( 'hf_form_default_settings', $default_settings ); $settings = array(); if ( ! empty( $post_meta['_hf_settings'][0] ) ) { $settings = (array) maybe_unserialize( $post_meta['_hf_settings'][0] ); } $settings = array_merge( $default_settings, $settings ); // grab & merge form messages $default_messages = array( 'success' => __( 'Thank you! We will be in touch soon.', 'html-forms' ), 'invalid_email' => __( 'Sorry, that email address looks invalid.', 'html-forms' ), 'required_field_missing' => __( 'Please fill in the required fields.', 'html-forms' ), 'error' => __( 'Oops. An error occurred.', 'html-forms' ), 'recaptcha_failed' => __( 'reCAPTCHA verification failed. Please try again.', 'html-forms' ), 'recaptcha_low_score' => __( 'Your submission appears to be spam. Please try again.', 'html-forms' ), ); $default_messages = apply_filters( 'hf_form_default_messages', $default_messages ); $messages = array(); foreach ( $post_meta as $meta_key => $meta_values ) { if ( strpos( $meta_key, 'hf_message_' ) === 0 ) { $message_key = substr( $meta_key, strlen( 'hf_message_' ) ); $messages[ $message_key ] = (string) $meta_values[0]; } } $messages = array_merge( $default_messages, $messages ); // finally, create form instance $form = new Form( $post->ID ); $form->title = $post->post_title; $form->slug = $post->post_name; $form->markup = $post->post_content; $form->settings = $settings; $form->messages = $messages; return $form; } /** * @param $form_id * @return int */ function hf_count_form_submissions( $form_id ) { global $wpdb; $table = $wpdb->prefix . 'hf_submissions'; $result = $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(*) FROM {$table} s WHERE s.form_id = %d;", $form_id ) ); return (int) $result; } /** * @param $form_id * @param array $args * @return Submission[] */ function hf_get_form_submissions( $form_id, array $args = array() ) { $default_args = array( 'offset' => 0, 'limit' => 1000, ); $args = array_merge( $default_args, $args ); global $wpdb; $table = $wpdb->prefix . 'hf_submissions'; $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 ); $submissions = array(); foreach ( $results as $key => $object ) { $submission = Submission::from_object( $object ); $submissions[ $key ] = $submission; } return $submissions; } /** * @param int $submission_id * @return Submission */ function hf_get_form_submission( $submission_id ) { global $wpdb; $table = $wpdb->prefix . 'hf_submissions'; $object = $wpdb->get_row( $wpdb->prepare( "SELECT s.* FROM {$table} s WHERE s.id = %d;", $submission_id ), OBJECT ); $submission = Submission::from_object( $object ); return $submission; } /** * @return array */ function hf_get_settings() { $default_settings = array( 'enable_nonce' => 0, 'load_stylesheet' => 0, 'wrapper_tag' => 'p', 'google_recaptcha' => array( 'site_key' => '', 'secret_key' => '', ), ); $settings = get_option( 'hf_settings', null ); // prevent a SQL query when option does not yet exist if ( $settings === null ) { update_option( 'hf_settings', array(), true ); $settings = array(); } // merge with default settings $settings = array_merge( $default_settings, $settings ); // Ensure nested arrays are properly merged if ( isset( $default_settings['google_recaptcha'] ) ) { $settings['google_recaptcha'] = array_merge( $default_settings['google_recaptcha'], isset( $settings['google_recaptcha'] ) ? $settings['google_recaptcha'] : array() ); } /** * Filters the global HTML Forms hf_settings * * @param array $settings */ $settings = apply_filters( 'hf_settings', $settings ); return $settings; } /** * Get element from array, allows for dot notation eg: "foo.bar" * * @param array $array * @param string $key * @param mixed $default * @return mixed */ function hf_array_get( $array, $key, $default = null ) { if ( is_null( $key ) ) { return $array; } if ( isset( $array[ $key ] ) ) { return $array[ $key ]; } foreach ( explode( '.', $key ) as $segment ) { if ( ! is_array( $array ) || ! array_key_exists( $segment, $array ) ) { return $default; } $array = $array[ $segment ]; } return $array; } /** * Processes template tags like {{user.user_email}} * * @param string $template * * @return string */ function hf_template( $template ) { $replacers = new HTML_Forms\TagReplacers(); $tags = array( 'user' => array( $replacers, 'user' ), 'post' => array( $replacers, 'post' ), 'url_params' => array( $replacers, 'url_params' ), ); /** * Filters the available tags in HTML Forms templates, like {{user.user_email}}. * * Can be used to add simple scalar replacements or more advanced replacement functions that accept a parameter. * * @param array $tags */ $tags = apply_filters( 'hf_template_tags', $tags ); $template = preg_replace_callback( '/\{\{ *(\w+)(?:\.([\w\.]+))? *(?:\|\| *(\w+))? *\}\}/', function( $matches ) use ( $tags ) { $tag = $matches[1]; $param = ! isset( $matches[2] ) ? '' : $matches[2]; $default = ! isset( $matches[3] ) ? '' : $matches[3]; // do not change anything if we have no replacer with that key, could be custom user logic or another plugin. if ( ! isset( $tags[ $tag ] ) ) { return $matches[0]; } $replacement = $tags[ $tag ]; $value = is_callable( $replacement ) ? call_user_func_array( $replacement, array( $param ) ) : $replacement; return ! empty( $value ) ? $value : $default; }, $template ); return $template; } /** * @param string $string * @param array $data * @param Closure|string $escape_function * @return string */ function hf_replace_data_variables( $string, Submission $submission, $escape_function = null ) { $data = ( !empty( $submission->data ) ? $submission->data : array() ); $submission_fields = array( 'HF_TIMESTAMP', 'HF_USER_AGENT', 'HF_IP_ADDRESS', 'HF_REFERRER_URL' ); return preg_replace_callback( '/\[(.+?)\]/', function( $matches ) use ( $submission, $submission_fields, $escape_function ) { $key = $matches[1]; if ( in_array( $key, $submission_fields ) ) { $replacement = ''; switch ( $key ) { case 'HF_TIMESTAMP' : $replacement = $submission->submitted_at; break; case 'HF_USER_AGENT' : $replacement = $submission->user_agent; break; case 'HF_IP_ADDRESS' : $replacement = $submission->ip_address; break; case 'HF_REFERRER_URL' : $replacement = $submission->referer_url; break; default : $replacement = ''; break; } } else { // replace spaces in name with underscores to match PHP requirement for keys in $_POST superglobal $key = str_replace( ' ', '_', $key ); $replacement = hf_array_get( $submission->data, $key, '' ); $replacement = hf_field_value( $replacement, 0, $escape_function ); } return $replacement; }, $string ); } /** * Returns a formatted & HTML-escaped field value. Detects file-, array- and date-types. * * 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). * * @param string|array $value * @param int $limit * @param Closure|string $escape_function * @return string * @since 1.3.1 */ function hf_field_value( $value, $limit = 0, $escape_function = 'esc_html' ) { if ( $value === '' ) { return $value; } if ( hf_is_file( $value ) ) { if ( ! is_array( $value ) || ! isset( $value['name'] ) || ! isset( $value['size'] ) || ! isset( $value['type'] ) ) { return false; } // Verify attachment exists if ( isset( $value['attachment_id'] ) && get_post( $value['attachment_id'] ) == null ) { return __( 'File not found', 'html-forms' ); } $file_url = isset( $value['url'] ) ? $value['url'] : ''; if ( isset( $value['attachment_id'] ) && apply_filters( 'hf_file_upload_use_direct_links', false ) === false ) { $file_url = admin_url( sprintf( 'post.php?action=edit&post=%d', $value['attachment_id'] ) ); } $short_name = substr( $value['name'], 0, 20 ); $suffix = strlen( $value['name'] ) > 20 ? '...' : ''; return sprintf( '%s%s (%s)', esc_url( $file_url ), esc_html( $short_name ), esc_html( $suffix ), hf_human_filesize( $value['size'] ) ); } if ( hf_is_date( $value ) ) { $date_format = get_option( 'date_format' ); return gmdate( $date_format, strtotime( str_replace( '/', '-', $value ) ) ); } // join array-values with comma if ( is_array( $value ) ) { $value = join( ', ', $value ); } // limit string to certain length if ( $limit > 0 ) { $limited = strlen( $value ) > $limit; $value = substr( $value, 0, $limit ); if ( $limited ) { $value .= '...'; } } // escape value if ( $escape_function !== null && is_callable( $escape_function ) ) { $value = $escape_function( $value ); } // add line breaks, if not string limited to certain length if ( $limit === 0 ) { $value = nl2br( $value ); } return $value; } /** * Returns true if value is a "file" * * @param mixed $value * @return bool */ function hf_is_file( $value ) { return is_array( $value ) && isset( $value['name'] ) && isset( $value['size'] ) && isset( $value['type'] ); } /** * Returns true if value looks like a date-string submitted from a * @param mixed $value * @return bool * @since 1.3.1 */ function hf_is_date( $value ) { if ( ! is_string( $value ) || strlen( $value ) !== 10 || (int) preg_match( '/\d{2,4}[-\/]\d{2}[-\/]\d{2,4}/', $value ) === 0 ) { return false; } $timestamp = strtotime( $value ); return $timestamp != false; } /** * @param int $size * @param int $precision * @return string */ function hf_human_filesize( $size, $precision = 2 ) { for ( $i = 0; ( $size / 1024 ) > 0.9; $i++, $size /= 1024 ) { // nothing, loop logic contains everything } $steps = array( 'B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB' ); return round( $size, $precision ) . $steps[ $i ]; } /** * Gets all the form tabs to show in the admin. * @param Form $form * @return array */ function hf_get_admin_tabs( Form $form ) { $tabs = array( 'fields' => __( 'Fields', 'html-forms' ), 'messages' => __( 'Messages', 'html-forms' ), 'settings' => __( 'Settings', 'html-forms' ), 'actions' => __( 'Actions', 'html-forms' ), ); if ( $form->settings['save_submissions'] ) { $tabs['submissions'] = __( 'Submissions', 'html-forms' ); } return apply_filters( 'hf_admin_tabs', $tabs, $form ); } function _hf_on_plugin_activation() { if ( is_multisite() ) { _hf_on_plugin_activation_multisite(); return; } // install table for regular wp install _hf_create_submissions_table(); // add "edit_forms" cap to user that activated the plugin $user = wp_get_current_user(); $user->add_cap( 'edit_forms', true ); } function _hf_on_plugin_activation_multisite() { $added_caps = array(); foreach ( get_sites( array( 'number' => PHP_INT_MAX ) ) as $site ) { switch_to_blog( (int) $site->blog_id ); // install table for current blog _hf_create_submissions_table(); // iterate through current blog admins foreach ( get_users( array( 'blog_id' => (int) $site->blog_id, 'role' => 'administrator', 'fields' => 'ID', ) ) as $admin_id ) { if ( ! (int) $admin_id || in_array( $admin_id, $added_caps ) ) { continue; } // add "edit_forms" cap to site admin $user = new \WP_User( (int) $admin_id ); $user->add_cap( 'edit_forms', true ); $added_caps[] = $admin_id; } restore_current_blog(); } } // install table for main site on regular installs, or active site for multisite function _hf_create_submissions_table() { /** @var wpdb */ global $wpdb; $charset_collate = $wpdb->get_charset_collate(); // create table for storing submissions $table = $wpdb->prefix . 'hf_submissions'; $wpdb->query( "CREATE TABLE IF NOT EXISTS {$table}( `id` INT UNSIGNED NOT NULL PRIMARY KEY AUTO_INCREMENT, `form_id` INT UNSIGNED NOT NULL, `data` TEXT NOT NULL, `user_agent` TEXT NULL, `ip_address` VARCHAR(255) NULL, `referer_url` TEXT NULL, `submitted_at` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ) {$charset_collate};" ); } function _hf_on_add_user_to_blog( $user_id, $role, $blog_id ) { if ( 'administrator' !== $role ) { return; } // add "edit_forms" cap to site admin $user = new \WP_User( (int) $user_id ); $user->add_cap( 'edit_forms', true ); } function _hf_on_wp_insert_site( \WP_Site $site ) { switch_to_blog( (int) $site->blog_id ); _hf_create_submissions_table(); restore_current_blog(); }