/home/techb158/dev.aleamaralawal.com/wp-content/plugins/gravityforms
Edit: /home/techb158/dev.aleamaralawal.com/wp-content/plugins/gravityforms/form_display.php (231333B)
= $page_number ) ) {
$is_valid = self::validate( $form, $field_values, $page_number, $failed_validation_page );
}
$log_is_valid = $is_valid ? 'Yes' : 'No';
GFCommon::log_debug( __METHOD__ . "(): After validation. Is submission valid? {$log_is_valid}." );
// Upload files to temp folder when going to the next page or when submitting the form and it failed validation
if ( $target_page > $page_number || $target_page === 0 ) {
if ( ! empty( $_FILES ) && ! $saving_for_later ) {
// When saving, ignore files with single file upload fields as they have not been validated.
GFCommon::log_debug( 'GFFormDisplay::process_form(): Uploading files...' );
// Uploading files to temporary folder.
$files = self::upload_files( $form, $files );
RGFormsModel::$uploaded_files[ $form_id ] = $files;
}
}
// Load target page if it did not fail validation or if going to the previous page
if ( ! $saving_for_later && $is_valid ) {
$page_number = $target_page;
} else {
$page_number = $failed_validation_page;
}
$confirmation = '';
if ( ( $is_valid && $page_number === 0 ) || $saving_for_later ) {
$ajax = isset( $_POST['gform_ajax'] );
/**
* Adds support for aborting submission, displaying the confirmation page/text to the user. This filter is useful for Spam Filters that want to abort submissions that flagged as spam.
*
* @since 2.7
*
* @see https://docs.gravityforms.com/gform_abort_submission_with_confirmation/
*
* @param bool $do_abort The value being filtered. True to abort submission and display the confirmation. False to continue with submission. Defaults to false.
* @param array $form The current form object.
*/
$abort_with_confirmation = gf_apply_filters( array( 'gform_abort_submission_with_confirmation', $form['id'] ), false, $form );
if ( $abort_with_confirmation ) {
if ( $saving_for_later ) {
GFCommon::log_debug( __METHOD__ . '(): Aborting save for later via gform_abort_submission_with_confirmation filter.' );
} else {
GFCommon::log_debug( __METHOD__ . '(): Aborting early via gform_abort_submission_with_confirmation filter.' );
}
// Display confirmation but doesn't process the form. Useful for spam filters.
$confirmation = self::handle_confirmation( $form, $lead, $ajax );
$is_valid = false;
self::set_submission_if_null( $form_id, 'abort_with_confirmation', true );
} elseif ( ! $saving_for_later ) {
GFCommon::log_debug( 'GFFormDisplay::process_form(): Submission is valid. Moving forward.' );
$gform_pre_submission_args = array( 'gform_pre_submission', $form_id );
if ( gf_has_action( $gform_pre_submission_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_pre_submission.' );
/**
* Fires before form submission is handled
*
* Typically used to modify values before the submission is processed.
*
* @since 1.0
*
* @param array $form The Form object
*/
gf_do_action( $gform_pre_submission_args, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_pre_submission.' );
}
$gform_pre_submission_filter_args = array( 'gform_pre_submission_filter', $form_id );
if ( gf_has_filter( $gform_pre_submission_filter_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_pre_submission_filter.' );
/**
* Allows the form object to be modified before the entry is saved.
*
* @since Unknown.
*
* @param array $form The form currently being processed.
*/
$form = gf_apply_filters( $gform_pre_submission_filter_args, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_pre_submission_filter.' );
}
$confirmation = self::handle_submission( $form, $lead, $ajax );
$gform_after_submission_args = array( 'gform_after_submission', $form_id );
if ( gf_has_action( $gform_after_submission_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_after_submission.' );
/**
* Allows additional actions to be performed after successful form submission.
*
* @since 1.6
*
* @param array $lead The Entry object.
* @param array $form The Form object.
*/
gf_do_action( $gform_after_submission_args, $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_after_submission.' );
}
} elseif ( $saving_for_later ) {
GFCommon::log_debug( 'GFFormDisplay::process_form(): Saving for later.' );
$lead = GFFormsModel::get_current_lead();
$form = self::update_confirmation( $form, $lead, 'form_saved' );
$confirmation = rgar( $form['confirmation'], 'message' );
$nl2br = rgar( $form['confirmation'], 'disableAutoformat' ) ? false : true;
$confirmation = GFCommon::replace_variables( $confirmation, $form, $lead, false, true, $nl2br );
$form_unique_id = GFFormsModel::get_form_unique_id( $form_id );
$ip = rgars( $form, 'personalData/preventIP' ) ? '' : GFFormsModel::get_ip();
$source_url = GFFormsModel::get_current_page_url();
$source_url = esc_url_raw( $source_url );
$resume_token = rgpost( 'gform_resume_token' );
$resume_token = sanitize_key( $resume_token );
$resume_token = GFFormsModel::save_draft_submission( $form, $lead, $field_values, $page_number, $files, $form_unique_id, $ip, $source_url, $resume_token );
$notifications_to_send = GFCommon::get_notifications_to_send( 'form_saved', $form, $lead );
$log_notification_event = empty( $notifications_to_send ) ? 'No notifications to process' : 'Processing notifications';
GFCommon::log_debug( "GFFormDisplay::process_form(): {$log_notification_event} for form_saved event." );
foreach ( $notifications_to_send as $notification ) {
if ( isset( $notification['isActive'] ) && ! $notification['isActive'] ) {
GFCommon::log_debug( "GFFormDisplay::process_form(): Notification is inactive, not processing notification (#{$notification['id']} - {$notification['name']})." );
continue;
}
$notification['message'] = self::replace_save_variables( $notification['message'], $form, $resume_token );
GFCommon::send_notification( $notification, $form, $lead );
}
self::set_submission_if_null( $form_id, 'saved_for_later', true );
self::set_submission_if_null( $form_id, 'resume_token', $resume_token );
GFCommon::log_debug( 'GFFormDisplay::process_form(): Saved incomplete submission.' );
}
/**
* Allows the confirmation redirect header to be suppressed. Required by GFAPI::submit_form().
*
* @since 2.3
*
* @param bool $suppress_redirect
*/
$suppress_redirect = apply_filters( 'gform_suppress_confirmation_redirect', false );
if ( is_array( $confirmation ) && isset( $confirmation['redirect'] ) && ! $suppress_redirect ) {
header( "Location: {$confirmation["redirect"]}" );
$gform_post_submission_args = array( 'gform_post_submission', $form_id );
if ( gf_has_action( $gform_post_submission_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_post_submission.' );
/**
* Allows additional actions to be performed after form submission when the confirmation is a redirect.
*
* @param array $lead The Entry object.
* @param array $form The Form object.
*/
gf_do_action( $gform_post_submission_args, $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_post_submission.' );
}
GFCommon::log_debug( __METHOD__ . sprintf( '(): Processing completed in %F seconds.', GFCommon::timer_end( __METHOD__ ) ) );
exit;
}
}
self::set_submission_if_null( $form_id, 'is_valid', $is_valid );
self::set_submission_if_null( $form_id, 'form', $form );
self::set_submission_if_null( $form_id, 'lead', $lead );
self::set_submission_if_null( $form_id, 'confirmation_message', $confirmation );
self::set_submission_if_null( $form_id, 'page_number', $page_number );
self::set_submission_if_null( $form_id, 'source_page_number', $source_page_number );
$gform_post_process_args = array( 'gform_post_process', $form_id );
if ( gf_has_action( $gform_post_process_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_post_process.' );
/**
* Fires after the form processing is completed. Form processing happens when submitting a page on a multi-page form (i.e. going to the "Next" or "Previous" page), or
* when submitting a single page form.
*
* @param array $form The Form Object
* @param int $page_number In a multi-page form, this variable contains the current page number.
* @param int $source_page_number In a multi-page form, this parameters contains the number of the page that the submission came from.
* For example, when clicking "Next" on page 1, this parameter will be set to 1. When clicking "Previous" on page 2, this parameter will be set to 2.
*/
gf_do_action( $gform_post_process_args, $form, $page_number, $source_page_number );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_post_process.' );
}
GFCommon::log_debug( __METHOD__ . sprintf( '(): Processing completed in %F seconds.', GFCommon::timer_end( __METHOD__ ) ) );
}
/**
* Get form object and insert review page, if necessary.
*
* @since 2.1.1.25 Added $partial_entry parameter.
* @since 1.9.15
*
* @param array $form The current Form object.
* @param array $partial_entry The partial entry from the resumed incomplete submission. Defaults to an empty array.
*
* @return array The form object.
*/
public static function maybe_add_review_page( $form, $partial_entry = array() ) {
/* Setup default review page parameters. */
$review_page = array(
'content' => '',
'cssClass' => '',
'is_enabled' => false,
'nextButton' => array(
'type' => 'text',
'text' => __( 'Review Form', 'gravityforms' ),
'imageUrl' => '',
'imageAlt' => '',
),
'previousButton' => array(
'type' => 'text',
'text' => __( 'Previous', 'gravityforms' ),
'imageUrl' => '',
'imageAlt' => '',
),
);
$gform_review_page_args = array( 'gform_review_page', rgar( $form, 'id' ) );
if ( gf_has_filter( $gform_review_page_args ) ) {
if ( empty( $partial_entry ) ) {
// Prepare partial entry for review page.
$partial_entry = GFFormsModel::get_current_lead();
}
/**
* GFFormsModel::create_lead() caches the field value and conditional logic visibility which can create
* issues when 3rd parties use hooks later in the process to modify the form. Let's flush the cache avoid
* any weirdness.
*/
GFCache::flush();
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_review_page.' );
/**
* A filter for setting up the review page.
*
* @since 2.4.5
*
* @param array $review_page The review page parameters
* @param array $form The current form object
* @param array|false $partial_entry The partial entry for the form or false on initial form display.
*/
$review_page = gf_apply_filters( $gform_review_page_args, $review_page, $form, $partial_entry );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_review_page.' );
if ( ! rgempty( 'button_text', $review_page ) ) {
$review_page['nextButton']['text'] = $review_page['button_text'];
}
}
if ( rgar( $review_page, 'is_enabled' ) ) {
$form = self::insert_review_page( $form, $review_page );
}
return $form;
}
private static function set_submission_if_null( $form_id, $key, $val ) {
self::$submission[ $form_id ] ??= array();
self::$submission[ $form_id ][ $key ] ??= $val;
}
/**
* Uploads temporary files for the current form.
*
* @since unknown
* @since 2.9.18 Updated to use GF_Field_FileUpload::upload_submission_tmp_files().
*
* @param array $form The form currently being processed.
* @param array $files The existing files parsed from the gform_uploaded_files input.
*
* @return array
*/
private static function upload_files( $form, $files ) {
$form_id = absint( rgar( $form, 'id' ) );
// Creating the tmp folder if it does not exist.
$target_path = rgar( GFFormsModel::get_tmp_upload_location( $form_id ), 'path' );
if ( empty( $target_path ) ) {
GFCommon::log_debug( __METHOD__ . '(): Aborting; GFFormsModel::get_tmp_upload_location() returned an empty path.' );
return $files;
}
if ( ! is_dir( $target_path ) && wp_mkdir_p( $target_path ) ) {
GFCommon::recursive_add_index_file( $target_path );
}
foreach ( $form['fields'] as $field ) {
if ( ! $field instanceof GF_Field_FileUpload ) {
continue;
}
$input_name = 'input_' . absint( $field->id );
$existing_files = rgar( $files, $input_name );
if ( empty( $existing_files ) || ! is_array( $existing_files ) ) {
$existing_files = array();
}
$files[ $input_name ] = array_merge( $existing_files, $field->upload_submission_tmp_files() );
if ( empty( $files[ $input_name ] ) ) {
unset( $files[ $input_name ] );
}
}
return $files;
}
public static function get_state( $form, $field_values ) {
$fields = array();
foreach ( $form['fields'] as $field ) {
/* @var GF_Field $field */
if ( $field->is_state_validation_supported() ) {
$value = RGFormsModel::get_field_value( $field, $field_values, false );
$value = $field->get_value_default_if_empty( $value );
switch ( $field->get_input_type() ) {
case 'calculation' :
case 'singleproduct' :
case 'hiddenproduct' :
$price = ! is_array( $value ) || empty( $value[ $field->id . '.2' ] ) ? $field->basePrice : $value[ $field->id . '.2' ];
if ( empty( $price ) ) {
$price = 0;
}
$price = GFCommon::to_number( $price );
$product_name = ! is_array( $value ) || empty( $value[ $field->id . '.1' ] ) ? $field->label : $value[ $field->id . '.1' ];
$fields[ $field->id . '.1' ] = wp_hash( GFFormsModel::maybe_trim_input( $product_name, $form['id'], $field ) );
$fields[ $field->id . '.2' ] = wp_hash( GFFormsModel::maybe_trim_input( $price, $form['id'], $field ) );
break;
case 'singleshipping' :
$price = ! empty( $value ) ? $value : $field->basePrice;
$price = ! empty( $price ) ? GFCommon::to_number( $price ) : 0;
$fields[ $field->id ] = wp_hash( GFFormsModel::maybe_trim_input( $price, $form['id'], $field ) );
break;
case 'radio' :
case 'select' :
$fields[ $field->id ] = array();
foreach ( $field->choices as $choice ) {
$field_value = ! empty( $choice['value'] ) || $field->enableChoiceValue ? $choice['value'] : $choice['text'];
if ( $field->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$field_value .= '|' . $price;
}
$fields[ $field->id ][] = wp_hash( GFFormsModel::maybe_trim_input( $field_value, $form['id'], $field ) );
}
break;
case 'checkbox' :
$index = 1;
foreach ( $field->choices as $choice ) {
$field_value = ! empty( $choice['value'] ) || $field->enableChoiceValue ? $choice['value'] : $choice['text'];
if ( $field->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$field_value .= '|' . $price;
}
// Checkboxes for Choice fields already have a unique ID.
if ( $field->has_persistent_choices() ) {
$input_id = $field->get_input_id_from_choice_key( $choice['key'] );
$fields[ $input_id ] = wp_hash( GFFormsModel::maybe_trim_input( $field_value, $form['id'], $field ) );
} else {
if ( $index % 10 == 0 ) { //hack to skip numbers ending in 0. so that 5.1 doesn't conflict with 5.10
$index ++;
}
$fields[ $field->id . '.' . $index ++ ] = wp_hash( GFFormsModel::maybe_trim_input( $field_value, $form['id'], $field ) );
}
}
break;
case 'consent':
$text = $field->checkboxLabel;
$description = GFFormsModel::get_latest_form_revisions_id( $form['id'] );
$fields[ $field->id . '.1' ] = wp_hash( 1 );
$fields[ $field->id . '.2' ] = wp_hash( GFFormsModel::maybe_trim_input( $text, $form['id'], $field ) );
$fields[ $field->id . '.3' ] = wp_hash( GFFormsModel::maybe_trim_input( $description, $form['id'], $field ) );
break;
}
}
}
$hash = json_encode( $fields );
$checksum = wp_hash( crc32( $hash ) );
return base64_encode( json_encode( array( $hash, $checksum ) ) );
}
/**
* Determine if form has any pages.
*
* @access private
*
* @param array $form The form object
*
* @return bool If form object has any pages
*/
private static function has_pages( $form ) {
return GFCommon::has_pages( $form );
}
private static function has_character_counter( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( $field->maxLength && ! $field->inputMask ) {
return true;
}
}
return false;
}
private static function has_placeholder( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( $field->placeholder != '' ) {
return true;
}
if ( is_array( $field->inputs ) ) {
foreach ( $field->inputs as $input ) {
if ( rgar( $input, 'placeholder' ) != '' ) {
return true;
}
}
}
}
return false;
}
private static function has_enhanced_dropdown( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( in_array( RGFormsModel::get_input_type( $field ), array( 'select', 'multiselect' ) ) && $field->enableEnhancedUI ) {
return true;
}
}
return false;
}
private static function has_password_strength( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( $field->type == 'password' && $field->passwordStrengthEnabled ) {
return true;
}
}
return false;
}
/**
* Determines if form has a Password field with the Password Visibility Toggle enabled.
*
* @since 2.4.15
*
* @param array $form Form object.
*
* @return bool
*/
private static function has_password_visibility( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( $field->type == 'password' && $field->passwordVisibilityEnabled ) {
return true;
}
}
return false;
}
private static function has_other_choice( $form ) {
if ( ! is_array( $form['fields'] ) ) {
return false;
}
foreach ( $form['fields'] as $field ) {
if ( $field->type == 'radio' && $field->enableOtherChoice ) {
return true;
}
}
return false;
}
public static function get_target_page( $form, $current_page, $field_values ) {
$form_id = (int) rgar( $form, 'id' );
$page_number = rgpost( "gform_target_page_number_{$form_id}" );
$page_number = ! is_numeric( $page_number ) ? 1 : $page_number;
// cast to an integer since page numbers can only be whole numbers
$page_number = absint( $page_number );
$direction = $page_number >= $current_page ? 1 : - 1;
//Finding next page that is not hidden by conditional logic
while ( GFFormsModel::is_page_hidden( $form, $page_number, $field_values ) ) {
$page_number += $direction;
}
//If all following pages are hidden, submit the form
if ( $page_number > self::get_max_page_number( $form ) ) {
$page_number = 0;
}
/**
* Modify the target page.
*
* @since 2.1.2.13
*
* @see https://docs.gravityforms.com/gform_target_page/
*
* @param int $page_number The target page number.
* @param array $form The current form object.
* @param int $current_page The page that was submitted.
* @param array $field_values Dynamic population values that were provided when loading the form.
*/
return (int) gf_apply_filters( array( 'gform_target_page', $form_id ), $page_number, $form, $current_page, $field_values );
}
public static function get_source_page( $form_id ) {
$page_number = rgpost( "gform_source_page_number_{$form_id}" );
return ! is_numeric( $page_number ) ? 1 : (int) $page_number;
}
public static function set_current_page( $form_id, $page_number ) {
self::$submission[ $form_id ]['page_number'] = $page_number;
}
public static function get_current_page( $form_id ) {
$page_number = isset( self::$submission[ $form_id ] ) ? intval( self::$submission[ $form_id ]['page_number'] ) : 1;
return $page_number;
}
private static function is_page_active( $form_id, $page_number ) {
return intval( self::get_current_page( $form_id ) ) == intval( $page_number );
}
/**
* Determine if the last page for the current form object is being submitted or rendered (depending on the provided $mode).
*
* @param array $form A Gravity Forms form object.
* @param string $mode Mode to check for: 'submit' or 'render'
*
* @return boolean
*/
public static function is_last_page( $form, $mode = 'submit' ) {
$page_number = self::get_source_page( $form['id'] );
$field_values = GFForms::post( 'gform_field_values' );
$target_page = self::get_target_page( $form, $page_number, $field_values );
if ( $mode == 'render' ) {
$is_valid = rgars( self::$submission, "{$form['id']}/is_valid" );
$is_last_page = ( $is_valid && $target_page == self::get_max_page_number( $form ) ) || (string) $target_page === '0';
} else {
$is_last_page = (string) $target_page === '0';
}
return $is_last_page;
}
/**
* Returns the entry limit date range for the given period.
*
* @since unknown
* @since 2.4.15 Updated the day period to use the local time.
*
* @param string $period The eriod for the entry limit.
*
* @return array
*/
private static function get_limit_period_dates( $period ) {
if ( empty( $period ) ) {
return array( 'start_date' => null, 'end_date' => null );
}
switch ( $period ) {
case 'day':
return array(
'start_date' => current_time( 'Y-m-d' ),
'end_date' => current_time( 'Y-m-d 23:59:59' ),
);
break;
case 'week':
return array(
'start_date' => gmdate( 'Y-m-d', strtotime( 'Monday this week' ) ),
'end_date' => gmdate( 'Y-m-d 23:59:59', strtotime( 'Sunday this week' ) ),
);
break;
case 'month':
$month_start = gmdate( 'Y-m-1');
return array(
'start_date' => $month_start,
'end_date' => gmdate( 'Y-m-d H:i:s', strtotime( "{$month_start} +1 month -1 second" ) ),
);
break;
case 'year':
return array(
'start_date' => gmdate( 'Y-1-1' ),
'end_date' => gmdate( 'Y-12-31 23:59:59' ),
);
break;
}
}
/**
* Get the slug for the form's theme
*
* @since 2.7
*
* @param $form
*
* @return string The theme slug
*/
public static function get_form_theme_slug( $form ) {
$form = (array) $form;
$slug = '';
$is_wp_dashboard = is_admin() && ! defined( 'DOING_AJAX' );
// If form is legacy, return that early to avoid calculating orbital styles.
if ( GFCommon::is_legacy_markup_enabled( $form ) ) {
$slug = 'legacy';
} elseif ( $is_wp_dashboard || GFCommon::is_preview() || GFCommon::is_form_editor() ) {
$slug = 'orbital';
} elseif ( isset( $form['theme'] ) ) {
$slug = $form['theme'];
} else {
$instance = rgar( $form, 'page_instance', 0 );
$all_blocks = apply_filters( 'gform_form_block_attribute_values', array() );
$block_settings = rgars( $all_blocks, rgar( $form, 'id', 0 ) . '/' . $instance, array() );
// If a theme is selected for this block or shortcode, return that.
if ( isset( $block_settings['theme'] ) ) {
$slug = $block_settings['theme'];
}
}
// allow using the short version in shortcodes.
if ( $slug == 'gravity' ) {
$slug = 'gravity-theme';
}
if ( empty( $slug ) || ! in_array( $slug, array( 'legacy', 'gravity-theme', 'orbital' ) ) ) {
$slug = GFForms::get_default_theme();
}
/**
* Allow users to filter the theme slug returned for a given form.
*
* @since 2.7
*
* @param string $slug The current theme slug for the form.
* @param array $form The form object being processed.
*
* @return string
*/
return apply_filters( 'gform_form_theme_slug', $slug, $form );
}
/**
* Determines which themes to enqueue based on the form context and current page.
*
* @since 2.9
*
* @param array $form Current form object.
* @param string|array $field_types Optional. If specified, only load themes for forms with fields of these types. Can be a string with a single field type or an array of strings with multiple field types.
*
* @return array|string[] Returns an array of theme slugs to enqueue
*/
public static function get_themes_to_enqueue( $form, $field_types = '' ) {
// In the form editor, enqueue the theme framework.
if ( GFCommon::is_form_editor() ) {
return array( 'orbital' );
}
// Enqueues Gravity and Theme Framework themes in the block editor
if ( GFCommon::is_block_editor_page() ) {
return array( 'gravity-theme', 'orbital' );
}
// Enqueues Gravity theme in the entry detail views
if ( GFCommon::is_entry_detail() ) {
return array( 'gravity-theme' );
}
// On pages other than the form editor and block editor, if a field type is specified, only enqueue a theme if the form has the specified field type.
if ( ! empty( $field_types ) && ! GFCommon::get_fields_by_type( $form, $field_types ) ) {
return array();
}
$selected_theme = self::get_form_theme_slug( $form );
return array( $selected_theme );
}
/**
* Fire the post render events for a form instance when the form is visible on the page.
*
* @since 2.8.4
*
* @param $form_id
* @param $current_page
*
* @return string
*/
public static function post_render_script( $form_id, $current_page = 'current_page' ) {
$post_render_script = '
jQuery(document).trigger("gform_pre_post_render", [{ formId: "' . $form_id . '", currentPage: "' . $current_page . '", abort: function() { this.preventDefault(); } }]);
if (event && event.defaultPrevented) {
return;
}
const gformWrapperDiv = document.getElementById( "gform_wrapper_' . $form_id . '" );
if ( gformWrapperDiv ) {
const visibilitySpan = document.createElement( "span" );
visibilitySpan.id = "gform_visibility_test_' . $form_id . '";
gformWrapperDiv.insertAdjacentElement( "afterend", visibilitySpan );
}
const visibilityTestDiv = document.getElementById( "gform_visibility_test_' . $form_id . '" );
let postRenderFired = false;
function triggerPostRender() {
if ( postRenderFired ) {
return;
}
postRenderFired = true;
gform.core.triggerPostRenderEvents( ' . $form_id . ', ' . $current_page . ' );
if ( visibilityTestDiv ) {
visibilityTestDiv.parentNode.removeChild( visibilityTestDiv );
}
}
function debounce( func, wait, immediate ) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if ( !immediate ) func.apply( context, args );
};
var callNow = immediate && !timeout;
clearTimeout( timeout );
timeout = setTimeout( later, wait );
if ( callNow ) func.apply( context, args );
};
}
const debouncedTriggerPostRender = debounce( function() {
triggerPostRender();
}, 200 );
if ( visibilityTestDiv && visibilityTestDiv.offsetParent === null ) {
const observer = new MutationObserver( ( mutations ) => {
mutations.forEach( ( mutation ) => {
if ( mutation.type === \'attributes\' && visibilityTestDiv.offsetParent !== null ) {
debouncedTriggerPostRender();
observer.disconnect();
}
});
});
observer.observe( document.body, {
attributes: true,
childList: false,
subtree: true,
attributeFilter: [ \'style\', \'class\' ],
});
} else {
triggerPostRender();
}
';
$post_render_script = gf_apply_filters( array( 'gform_post_render_script', $form_id ), $post_render_script, $form_id, $current_page );
return str_replace( [ "\t", "\n", "\r" ], '', $post_render_script );
}
/**
* Get a form for display.
*
* @since unknown
* @since 2.7.15 Added the $form_theme and $style_settings parameters.
*
* @param int $form_id The id of the form.
* @param bool $display_title Whether to display the form title.
* @param bool $display_description Whether to display the form description.
* @param bool $force_display Whether to force the form to display even if it is inactive.
* @param array $field_values Array of field values.
* @param bool $ajax Whether ajax is enabled.
* @param int $tabindex Tabindex for the form.
* @param string $form_theme Form theme slug.
* @param string $style_settings JSON-encoded style settings. Passing false will bypass the gform_default_styles filter.
*
* @return mixed|string|WP_Error
*/
public static function get_form( $form_id, $display_title = true, $display_description = true, $force_display = false, $field_values = null, $ajax = false, $tabindex = 0, $form_theme = null, $style_settings = null ) {
GFCommon::timer_start( __METHOD__ );
/**
* Provides the ability to modify the options used to display the form
*
* @param array An array of Form Arguments when adding it to a page/post (Like the ID, Title, AJAX or not, etc)
*/
$form_args = apply_filters( 'gform_form_args', compact( 'form_id', 'display_title', 'display_description', 'force_display', 'field_values', 'ajax', 'tabindex' ) );
// The submission_method property can be set in the gform_form_args filter to specify how the form should be submitted.
// Supported values are: self::SUBMISSION_METHOD_AJAX (for true ajax submission), self::SUBMISSION_METHOD_POSTBACK (for standard form submission) or self::SUBMISSION_METHOD_IFRAME (for the legacy iframe-based ajax submission ).
// It is optional, but if set, will override the $ajax property.
if ( isset( $form_args['submission_method'] ) ) {
$form_args['ajax'] = $form_args['submission_method'] == self::SUBMISSION_METHOD_IFRAME;
} elseif ( $form_args ) {
$form_args['submission_method'] = $form_args['ajax'] ? self::SUBMISSION_METHOD_IFRAME : self::SUBMISSION_METHOD_POSTBACK;
}
if ( empty( $form_args['form_id'] ) ) {
return self::get_form_not_found_html( $form_id, $ajax );
}
$form_args['display_title'] = ! isset( $form_args['display_title'] ) || ! empty( $form_args['display_title'] );
$form_args['display_description'] = ! isset( $form_args['display_description'] ) || ! empty( $form_args['display_description'] );
// phpcs:ignore
extract( $form_args );
//looking up form id by form name
if ( ! is_numeric( $form_id ) ) {
$form_title = $form_id;
$form_id = GFFormsModel::get_form_id( $form_title );
if ( $form_id === 0 ) {
return self::get_form_not_found_html( $form_title, $ajax );
}
}
$form = GFAPI::get_form( $form_id );
if ( ! $form ) {
return self::get_form_not_found_html( $form_id, $ajax );
}
if ( ! isset( self::$processed[ $form_id ] ) ) {
self::$processed[ $form_id ] = 0;
}
$form['page_instance'] = self::$processed[ $form_id ];
self::$processed[ $form_id ]++;
// Setting form style and theme
$form = self::set_form_styles( $form, $style_settings, $form_theme );
$action = wp_doing_ajax() ? remove_query_arg( 'gf_token', wp_get_referer() ) : remove_query_arg( 'gf_token' );
if ( rgpost( 'gform_send_resume_link' ) == $form_id ) {
$save_email_confirmation = self::handle_save_email_confirmation( $form, $ajax );
if ( is_wp_error( $save_email_confirmation ) ) { // Failed email validation
$resume_token = rgpost( 'gform_resume_token' );
$resume_token = sanitize_key( $resume_token );
$incomplete_submission_info = GFFormsModel::get_draft_submission_values( $resume_token );
if ( $incomplete_submission_info['form_id'] == $form_id ) {
$submission_details_json = $incomplete_submission_info['submission'];
$submission_details = json_decode( $submission_details_json, true );
$partial_entry = $submission_details['partial_entry'];
$form = self::update_confirmation( $form, $partial_entry, 'form_saved' );
$confirmation_message = rgar( $form['confirmation'], 'message' );
$nl2br = rgar( $form['confirmation'], 'disableAutoformat' ) ? false : true;
$confirmation_message = GFCommon::replace_variables( $confirmation_message, $form, $partial_entry, false, true, $nl2br );
return self::handle_save_confirmation( $form, $resume_token, $confirmation_message, $ajax );
}
} else {
return $save_email_confirmation;
}
}
$is_postback = false;
$is_valid = true;
$confirmation_message = '';
//If form was submitted, read variables set during form submission procedure
$submission_info = rgar( self::$submission, $form_id, false );
if ( rgar( $submission_info, 'saved_for_later' ) == true ) {
$resume_token = rgar( $submission_info, 'resume_token' );
$confirmation_message = rgar( $submission_info, 'confirmation_message' );
return self::handle_save_confirmation( $form, $resume_token, $confirmation_message, $ajax );
}
$partial_entry = $submitted_values = $review_page_done = false;
if ( isset( $_GET['gf_token'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$incomplete_submission_info = GFFormsModel::get_draft_submission_values( sanitize_text_field( wp_unslash( $_GET['gf_token'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
if ( rgar( $incomplete_submission_info, 'form_id' ) == $form_id ) {
$submission_details_json = $incomplete_submission_info['submission'];
$submission_details = json_decode( $submission_details_json, true );
$partial_entry = $submission_details['partial_entry'];
$submitted_values = $submission_details['submitted_values'];
$field_values = $submission_details['field_values'];
GFFormsModel::$unique_ids[ $form_id ] = $submission_details['gform_unique_id'];
GFFormsModel::$uploaded_files[ $form_id ] = $submission_details['files'];
self::set_submission_if_null( $form_id, 'resuming_incomplete_submission', true );
self::set_submission_if_null( $form_id, 'form_id', $form_id );
$form = self::maybe_add_review_page( $form, $partial_entry );
$review_page_done = true;
$max_page_number = self::get_max_page_number( $form );
$page_number = $submission_details['page_number'];
if ( $page_number > 1 && $max_page_number > 0 && $page_number > $max_page_number ) {
$page_number = $max_page_number;
}
self::set_submission_if_null( $form_id, 'page_number', $page_number );
}
}
if ( ! $review_page_done && $form !== false ) {
$form = self::maybe_add_review_page( $form );
}
if ( ! is_array( $partial_entry ) ) {
/**
* A filter that allows disabling of the form view counter
*
* @param int $form_id The Form ID to filter when disabling the form view counter
* @param bool Default set to false (view counter enabled), can be set to true to disable the counter
*/
$view_counter_disabled = gf_apply_filters( array( 'gform_disable_view_counter', $form_id ), false );
if ( rgar( $submission_info, 'form' ) ) {
$submission_info['form']['page_instance'] = rgar( $form, 'page_instance', 0 );
$is_postback = true;
$is_valid = rgar( $submission_info, 'is_valid' ) || rgar( $submission_info, 'is_confirmation' );
$form = self::set_form_styles( $submission_info['form'], $style_settings, $form_theme );
$lead = $submission_info['lead'];
$confirmation_message = rgget( 'confirmation_message', $submission_info );
if ( $is_valid && ! rgar( $submission_info, 'is_confirmation' ) ) {
$page_number = (int) rgar( $submission_info, 'page_number' );
if ( $page_number === 0 ) {
/**
* Fired after form submission
*
* @param array $lead The Entry object
* @param array $form The Form object
*/
gf_do_action( array( 'gform_post_submission', $form_id ), $lead, $form );
} else {
$source_page_number = (int) rgar( $submission_info, 'source_page_number' );
/**
* Fired after the page changes on a multi-page form
*
* @param array $form The Form object
* @param int $source_page_number The page that was submitted
* @param int $page_number The page that the user is being sent to
*/
gf_do_action( array( 'gform_post_paging', $form_id ), $form, $source_page_number, $page_number );
}
}
} elseif ( ! current_user_can( 'administrator' ) && ! $view_counter_disabled ) {
RGFormsModel::insert_form_view( $form_id );
}
}
// Running $form through the gform_pre_render filter.
$form = self::gform_pre_render( $form, 'form_display', $ajax, $field_values );
if ( empty( $form ) ) {
return self::get_form_not_found_html( $form_id, $ajax );
}
$has_pages = self::has_pages( $form );
//calling tab index filter
GFCommon::$tab_index = gf_apply_filters( array( 'gform_tabindex', $form_id ), $tabindex, $form );
//Don't display inactive forms
if ( ! $force_display && ! $is_postback ) {
$form_info = RGFormsModel::get_form( $form_id );
if ( empty( $form_info ) || ! $form_info->is_active ) {
return '';
}
// If form requires login, check if user is logged in
if ( GFCommon::form_requires_login( $form ) ) {
if ( ! is_user_logged_in() ) {
return empty( $form['requireLoginMessage'] ) ? '
' . esc_html__( 'Sorry. You must be logged in to view this form.', 'gravityforms' ) . '
' : '
' . GFCommon::gform_do_shortcode( $form['requireLoginMessage'] ) . '
';
}
}
}
// show the form regardless of the following validations when force display is set to true
if ( ! $force_display || $is_postback ) {
$form_schedule_validation = self::validate_form_schedule( $form );
// if form schedule validation fails AND this is not a postback, display the validation error
// if form schedule validation fails AND this is a postback, make sure is not a valid submission (enables display of confirmation message)
if ( $form_schedule_validation && ! $is_postback ) {
return $form_schedule_validation;
} elseif ( $form_schedule_validation && $is_postback && ! $is_valid ) {
return self::get_ajax_postback_html( $form_schedule_validation );
}
$entry_limit_validation = self::validate_entry_limit( $form );
// refer to form schedule condition notes above
if ( $entry_limit_validation && ! $is_postback ) {
return $entry_limit_validation;
} elseif ( $entry_limit_validation && $is_postback && ! $is_valid ) {
return self::get_ajax_postback_html( $entry_limit_validation );
}
}
$form_string = '';
//When called via a template, this will enqueue the proper scripts
//When called via a shortcode, this will be ignored (too late to enqueue), but the scripts will be enqueued via the enqueue_scripts event
self::enqueue_form_scripts( $form, $ajax );
$is_form_editor = GFCommon::is_form_editor();
$is_entry_detail = GFCommon::is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$should_render_hidden = self::has_conditional_logic( $form ) && rgar( rgget( 'attributes' ), 'formPreview' ) !== 'true';
if ( empty( $confirmation_message ) ) {
$wrapper_css_class = GFCommon::get_browser_class() . ' gform_wrapper';
if ( ! $is_valid ) {
$wrapper_css_class .= ' gform_validation_error';
}
$form_css_class = esc_attr( rgar( $form, 'cssClass' ) );
//Hiding entire form if conditional logic is on to prevent 'hidden' fields from blinking. Form will be set to visible in the conditional_logic.php after the rules have been applied.
$style = $should_render_hidden ? "style='display:none'" : '';
// Split form CSS class by spaces and apply wrapper to each.
$custom_wrapper_css_class = '';
if ( ! empty( $form_css_class ) ) {
// Separate the CSS classes.
$form_css_classes = explode( ' ', $form_css_class );
$form_css_classes = array_filter( $form_css_classes ); // nosemgrep audit.php.lang.misc.array-filter-no-callback
// Append _wrapper to each class.
foreach ( $form_css_classes as &$wrapper_class ) {
$wrapper_class .= '_wrapper';
}
// Merge back into a string.
$custom_wrapper_css_class = ' ' . implode( ' ', $form_css_classes );
}
$page_instance = isset( $form['page_instance'] ) ? "data-form-index='{$form['page_instance']}'" : null;
$form_theme = GFFormDisplay::get_form_theme_slug( $form );
$form_string .= "
';
if ( $ajax && $is_postback ) {
global $wp_scripts;
$form_string = self::get_ajax_postback_html( $form_string );
}
/**
* Allows users to disable the spinner on non-ajax forms.
*
* @since 2.7
*
* @param bool $show Whether to show the spinner on non-ajax-forms.
*
* @return bool
*/
$always_show_spinner = gf_apply_filters( array( 'gform_always_show_spinner', $form_id ), true );
$should_show_spinner = $ajax || $always_show_spinner;
if ( $should_show_spinner ) {
$default_spinner = GFCommon::get_base_url() . '/images/spinner.svg';
$spinner_url = gf_apply_filters( array( 'gform_ajax_spinner_url', $form_id ), $default_spinner, $form );
$theme_slug = self::get_form_theme_slug( $form );
$is_legacy = $default_spinner !== $spinner_url || in_array( $theme_slug, array( 'gravity-theme', 'legacy' ) );
$scroll_position = array( 'default' => '', 'confirmation' => '' );
if ( $anchor['scroll'] !== false ) {
$scroll_position['default'] = is_numeric( $anchor['scroll'] ) ? 'jQuery(document).scrollTop(' . intval( $anchor['scroll'] ) . ');' : "jQuery(document).scrollTop(jQuery('#gform_wrapper_{$form_id}').offset().top - mt);";
$scroll_position['confirmation'] = is_numeric( $anchor['scroll'] ) ? 'jQuery(document).scrollTop(' . intval( $anchor['scroll'] ) . ');' : "jQuery(document).scrollTop(jQuery('{$anchor['id']}').offset().top - mt);";
}
// Accessibility enhancements to properly handle the iframe title and content.
$iframe_content = esc_html__( 'This iframe contains the logic required to handle Ajax powered Gravity Forms.', 'gravityforms' );
$iframe_title = " title='{$iframe_content}'";
if ( defined( 'GF_DEBUG' ) && GF_DEBUG ) {
// In debug mode, display the iframe with the text content.
$iframe_style = 'display:block;width:600px;height:300px;border:1px solid #eee;';
} else {
// Hide the iframe and the content is not needed when not in debug mode.
$iframe_style = 'display:none;width:0px;height:0px;';
$iframe_content = '';
}
if ( ! $ajax || ! $is_postback ) {
$form_scripts_body =
'gform.initializeOnLoaded( function() {' .
"gformInitSpinner( {$form_id}, '{$spinner_url}', " . ( $is_legacy ? 'true' : 'false' ) . " );" .
"jQuery('#gform_ajax_frame_{$form_id}').on('load',function(){" .
"var contents = jQuery(this).contents().find('*').html();" .
"var is_postback = contents.indexOf('GF_AJAX_POSTBACK') >= 0;" .
'if(!is_postback){return;}' .
"var form_content = jQuery(this).contents().find('#gform_wrapper_{$form_id}');" .
"var is_confirmation = jQuery(this).contents().find('#gform_confirmation_wrapper_{$form_id}').length > 0;" .
"var is_redirect = contents.indexOf('gformRedirect(){') >= 0;" .
'var is_form = form_content.length > 0 && ! is_redirect && ! is_confirmation;' .
"var mt = parseInt(jQuery('html').css('margin-top'), 10) + parseInt(jQuery('body').css('margin-top'), 10) + 100;" .
'if(is_form){' .
( $should_render_hidden ? "form_content.find('form').css('opacity', 0);" : "" ) .
"jQuery('#gform_wrapper_{$form_id}').html(form_content.html());" .
"if(form_content.hasClass('gform_validation_error')){jQuery('#gform_wrapper_{$form_id}').addClass('gform_validation_error');} else {jQuery('#gform_wrapper_{$form_id}').removeClass('gform_validation_error');}" .
"setTimeout( function() { /* delay the scroll by 50 milliseconds to fix a bug in chrome */ {$scroll_position['default']} }, 50 );" .
"if(window['gformInitDatepicker']) {gformInitDatepicker();}" .
"if(window['gformInitPriceFields']) {gformInitPriceFields();}" .
"var current_page = jQuery('#gform_source_page_number_{$form_id}').val();" .
"gformInitSpinner( {$form_id}, '{$spinner_url}', " . ( $is_legacy ? 'true' : 'false' ) . " );" .
"jQuery(document).trigger('gform_page_loaded', [{$form_id}, current_page]);" .
"window['gf_submitting_{$form_id}'] = false;" .
'}' .
'else if(!is_redirect){' .
"var confirmation_content = jQuery(this).contents().find('.GF_AJAX_POSTBACK').html();" .
'if(!confirmation_content){' .
'confirmation_content = contents;' .
'}' .
"jQuery('#gform_wrapper_{$form_id}').replaceWith(confirmation_content);" .
"{$scroll_position['confirmation']}" .
"jQuery(document).trigger('gform_confirmation_loaded', [{$form_id}]);" .
"window['gf_submitting_{$form_id}'] = false;" .
"wp.a11y.speak(jQuery('#gform_confirmation_message_{$form_id}').text());" .
'}' .
'else{' .
"jQuery('#gform_{$form_id}').append(contents);" .
"if(window['gformRedirect']) {gformRedirect();}" .
'}' .
self::post_render_script( $form_id ) .
'} );' .
'} );';
$form_scripts = GFCommon::get_inline_script_tag( $form_scripts_body );
if ( $ajax ) {
$form_string .= "
{$form_scripts}";
} else {
$form_string .= $form_scripts;
}
}
}
$is_first_load = ! $is_postback;
if ( ( ! $ajax || $is_first_load ) ) {
self::register_form_init_scripts( $form, $field_values, $ajax );
// We can't init in footer on AJAX calls, as those actions never get called.
$init_in_footer = ! ( defined('DOING_AJAX') && DOING_AJAX );
/**
* Allows init scripts to be outputted in either the header or footer.
*
* @since unknown
* @since 2.5.3 Defaults to ( ! DOING_AJAX )
*
* @param bool Whether to output init scripts in the footer. Defaults to ( ! DOING_AJAX ).
*/
if ( apply_filters( 'gform_init_scripts_footer', $init_in_footer ) ) {
$callback = array( new GF_Late_Static_Binding( array( 'form_id' => $form['id'] ) ), 'GFFormDisplay_footer_init_scripts' );
add_action( 'wp_footer', $callback, 999 );
add_action( 'admin_print_footer_scripts', $callback, 999 );
add_action( 'gform_preview_footer', $callback );
} else {
$form_string .= self::get_form_init_scripts( $form );
$init_script_body = 'gform.initializeOnLoaded( function() {' .
self::post_render_script( $form_id, $current_page ) .
'} );';
$form_string .= GFCommon::get_inline_script_tag( $init_script_body );
}
}
$form_string = gf_apply_filters( array( 'gform_get_form_filter', $form_id ), $form_string, $form );
if ( isset( $_GET['gform_debug'] ) || GFCommon::is_preview() ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
GFCommon::log_debug( __METHOD__ . sprintf( '(): Preparing form (#%d) markup completed in %F seconds.', $form_id, GFCommon::timer_end( __METHOD__ ) ) );
}
return $form_string;
} else {
return self::get_confirmation_markup( $form, $confirmation_message, $ajax, $style_settings, $form_theme );
}
}
/**
* Get the markup for a specific page in a multipage form.
*
* @since 2.9.5
*
* @param int $form_id The form ID.
* @param int $page_number The page number to render.
* @param array $field_values An array of field values to populate the form with.
* @param string $theme The current form theme (i.e. orbital or gravity).
* @param array $style_settings An array of block or shortcode style settings.
* @param string $submission_method The submission method (i.e. ajax or postback).
*
* @return string Returns the markup for the specified page of a multipage form.
*/
public static function get_page( $form_id, $page_number, $field_values, $theme, $style_settings, $submission_method ) {
// Getting form and filtering it through gform_pre_render.
$form = GFAPI::get_form( $form_id );
$form = self::gform_pre_render( $form, 'form_display', false, $field_values );
// Maybe adding review page.
self::maybe_add_review_page( $form );
//TODO: research all the hooks / filters that need to be fired here.
$markup = '';
// If rendering the first page of the form, add the first page's header.
$is_first_page = $page_number === 1;
$tag = GFCommon::is_legacy_markup_enabled( $form ) ? 'ul' : 'div';
if ( $is_first_page ) {
// Getting the page header for the first page of the form.
$markup .= self::get_first_page_header( $form );
// Getting the field container header if this is the first page of the form.
$markup .= "<{$tag} id='gform_fields_{$form_id}' class='" . GFCommon::get_ul_classes( $form ) . "'>"; // Opening field container for first page.
}
// Adding the fields for the target page.
$markup .= self::get_fields( $form, $field_values, false, $page_number );
// If this is the last page of the form, add the last page's footer.
$is_last_page = $page_number === self::get_max_page_number( $form );
if ( $is_last_page ) {
// Closing the field container on the last page of the form.
$markup .= "{$tag}>";
// Adding the footer for the last page of the form.
$markup .= self::get_last_page_footer( $form, rgar( $form, 'labelPlacement', 'top_label' ), false, $field_values, false, false, '', $theme, $style_settings, $submission_method );
}
return $markup;
}
/**
* Get the markup for a colletion of fields in a form. If $page_number is specified, only the markup for the fields on that page will be returned. Otherwise, the markup for all fields in the form will be returned.
*
* @since 2.9.5
* @since 2.9.18 Made the honeypot the first field on the form.
*
* @param array $form The current form object.
* @param array $field_values The array of field values to populate the form with.
* @param array $submitted_values The array of submitted values if the form has been submitted.
* @param int $page_number The current page number to get fields for. Or 0 to get all fields.
*
* @return string Returns the markup for the specified page of a multipage form, or all fields in the form if no page number is specified.
*/
public static function get_fields( $form, $field_values, $submitted_values, $page_number = 0 ) {
$fields = $page_number == 0 ? $form['fields'] : self::get_fields_by_page( $form, $page_number );
$markup = '';
$has_honeypot = false;
foreach ( $fields as $field ) {
if ( $field instanceof GF_Field_Honeypot ) {
if ( $has_honeypot ) {
continue;
} else {
$has_honeypot = true;
}
}
$field->set_context_property( 'rendering_form', true );
$field->conditionalLogicFields = self::get_conditional_logic_fields( $form, $field->id );
if ( is_array( $submitted_values ) ) {
$field_value = rgar( $submitted_values, $field->id );
if ( $field->type === 'consent'
&& ( $field_value[ $field->id . '.3' ] != GFFormsModel::get_latest_form_revisions_id( $form['id'] )
|| $field_value[ $field->id . '.2' ] != $field->checkboxLabel ) ) {
$field_value = GFFormsModel::get_field_value( $field, $field_values );
}
} else {
$field_value = GFFormsModel::get_field_value( $field, $field_values );
}
$markup .= self::get_field( $field, $field_value, false, $form, $field_values, $page_number );
$markup .= self::get_row_spacer( $field, $form );
}
if ( $has_honeypot || ( $page_number !== 0 && $page_number !== 1 ) ) {
return $markup;
}
/** @var Honeypot\GF_Honeypot_Handler $honeypot_handler */
$honeypot_handler = GFForms::get_service_container()->get( Honeypot\GF_Honeypot_Service_Provider::GF_HONEYPOT_HANDLER );
if ( ! $honeypot_handler->is_honeypot_enabled( $form ) ) {
return $markup;
}
// Adding the honeypot as the first field.
$honeypot_field = $honeypot_handler->get_honeypot_field( $form );
$field_value = GFFormsModel::get_field_value( $honeypot_field );
return self::get_field( $honeypot_field, $field_value, false, $form ) . $markup;
}
/**
* Gets the fields for a specific page in a form.
*
* @since 2.9.5
*
* @param array $form The form object.
* @param int $page_number The page number to get fields for.
*
* @return array Returns an array of fields belonging to the specified page.
*/
public static function get_fields_by_page( $form, $page_number ) {
$fields = array();
foreach ( $form['fields'] as $field ) {
$field_page_number = absint( $field->pageNumber );
$belongs_to_page = $field_page_number === $page_number;
$is_page_footer = $field->type === 'page' && $field_page_number === $page_number + 1;
if ( $belongs_to_page || $is_page_footer || ( $field instanceof GF_Field_Honeypot && ! empty( $fields ) ) ) {
$fields[] = $field;
} elseif ( ! empty( $fields ) ) {
break;
}
}
return $fields;
}
public static function footer_init_scripts( $form_id ) {
global $_init_forms;
$form = RGFormsModel::get_form_meta( $form_id );
$form_string = self::get_form_init_scripts( $form );
$current_page = self::get_current_page( $form_id );
$footer_script_body = 'gform.initializeOnLoaded( function() {' . self::post_render_script( $form_id, $current_page ) . '} );';
$form_string .= GFCommon::get_inline_script_tag( $footer_script_body );
/**
* A filter to allow modification of scripts that fire in the footer
*
* @param int $form_id The Form ID to filter through
* @param string $form_string Get the form scripts in a string
* @param array $form The Form object to filter through
* @param int $current_page The Current form page ID (If paging is enabled)
*/
$form_string = gf_apply_filters( array( 'gform_footer_init_scripts_filter', $form_id ), $form_string, $form, $current_page );
if ( ! isset( $_init_forms[ $form_id ] ) ) {
echo $form_string; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ( ! is_array( $_init_forms ) ) {
$_init_forms = array();
}
$_init_forms[ $form_id ] = true;
}
}
public static function add_init_script( $form_id, $script_name, $location, $script ) {
$key = $script_name . '_' . $location;
if ( ! isset( self::$init_scripts[ $form_id ] ) ) {
self::$init_scripts[ $form_id ] = array();
}
//add script if it hasn't been added before
if ( ! array_key_exists( $key, self::$init_scripts[ $form_id ] ) ) {
self::$init_scripts[ $form_id ][ $key ] = array( 'location' => $location, 'script' => $script );
}
}
public static function get_form_button( $form_id, $button_input_id, $button, $default_text, $class, $alt, $target_page_number, $onclick = '' ) {
$is_form_editor = GFCommon::is_form_editor();
$tabindex = GFCommon::get_tabindex();
$input_type = ( rgar( $button, 'type' ) === 'link' ) ? 'button' : 'submit';
$input_onclick = $is_form_editor ? '' : "onclick='gform.submission.handleButtonClick(this);'";
$sub_type = rgar( explode( '_', $button_input_id ), 1, 'submit' );
if ( $sub_type === 'save' ) {
$sub_type .= '-continue';
}
$sub_type_attr = sprintf( "data-submission-type='%s'", esc_attr( $sub_type ) );
if ( ! empty( $target_page_number ) ) {
$input_type = 'button';
}
if ( rgar( $button, 'type' ) == 'text' || rgar( $button, 'type' ) == 'link' || empty( $button['imageUrl'] ) ) {
$button_text = ! empty( $button['text'] ) ? $button['text'] : $default_text;
if ( rgar( $button, 'type' ) == 'link' ) {
if ( GFCommon::is_legacy_markup_enabled( $form_id ) ) {
$tag = 'a';
$target = 'href="javascript:void(0);"';
$icon = '';
} else {
$tag = 'button';
$class .= GFFormDisplay::get_submit_button_class( $button, $form_id );
$target = '';
$icon = '
';
}
$button_input = "<{$tag} type='{$input_type}' {$target} id='{$button_input_id}_link' {$input_onclick} {$sub_type_attr} class='{$class}' {$tabindex} >{$icon} {$button_text}{$tag}>";
} else {
$class .= GFFormDisplay::get_submit_button_class( $button, $form_id );
$button_input = "
";
}
} else {
$imageUrl = esc_url( $button['imageUrl'] );
$class .= GFFormDisplay::get_submit_button_class( $button, $form_id );
$class .= ' gform_image_button';
$button_input = "
";
}
return $button_input;
}
/**
* Get the CSS class for the submit button.
*
* @since 2.6
*
* @param array $button The button attributes.
* @param integer $form_id The ID of the form.
*
* @return string The CSS class(es) for this button.
*/
public static function get_submit_button_class( $button, $form_id ) {
$class = ' button';
$class .= rgar( $button, 'width' ) && 'full' == $button['width'] ? ' gform-button--width-full' : '';
// if the button is at the bottom, and if it has width, add a width class.
if ( rgar( $button, 'location' ) && 'bottom' == $button['location'] && rgar( $button, 'layoutGridColumnSpan' ) && 12 !== $button['layoutGridColumnSpan'] ) {
$form = GFAPI::get_form( $form_id );
$submit = new GF_Field_Submit();
$class .= ' ' . $submit->get_css_grid_class( $form );
}
return $class;
}
public static function gform_footer( $form, $class, $ajax, $field_values, $previous_button, $display_title, $display_description, $tabindex = 1, $theme = null, $style_settings = null, $submission_method = self::SUBMISSION_METHOD_POSTBACK ) {
$form_id = absint( $form['id'] );
$footer = "
";
$button = rgar( $form, 'button', array( 'type' => 'link' ) );
if ( rgar( $form['button'], 'location' ) && 'inline' == $form['button']['location'] ) {
$button_input = '';
} else {
$button_input = self::get_form_button( $form['id'], "gform_submit_button_{$form['id']}", $button, __( 'Submit', 'gravityforms' ), 'gform_button', __( 'Submit', 'gravityforms' ), 0 );
$button_input = gf_apply_filters( array( 'gform_submit_button', $form_id ), $button_input, $form );
}
$save_button = rgars( $form, 'save/enabled' ) ? self::get_form_button( $form_id, "gform_save_{$form_id}_footer", $form['save']['button'], rgars( $form, 'save/button/text' ), 'gform_save_link gform-theme-button gform-theme-button--secondary', rgars( $form, 'save/button/text' ), 0, "jQuery(\"#gform_save_{$form_id}\").val(1);" ) : '';
/**
* Filters the save and continue link allowing the tag to be customized
*
* @since 2.0.7.7
*
* @param string $save_button The string containing the save and continue link markup.
* @param array $form The Form object associated with the link.
*/
$save_button = apply_filters( 'gform_savecontinue_link', $save_button, $form );
$save_button = apply_filters( "gform_savecontinue_link_{$form_id}", $save_button, $form );
$footer .= $previous_button . ' ' . $button_input . ' ' . $save_button;
$tabindex = intval( $tabindex );
// Make sure style settings are valid JSON.
$style_settings = self::validate_form_styles( $style_settings );
$style_settings = is_array( $style_settings ) ? json_encode( $style_settings ) : null;
$is_valid_json = is_string( $style_settings );
if ( $ajax ) {
$ajax_value = self::prepare_ajax_input_value( $form_id, $display_title, $display_description, $tabindex, $theme, $is_valid_json ? $style_settings : null );
$footer .= " ";
}
$current_page = self::get_current_page( $form_id );
$next_page = $current_page + 1;
$next_page = $next_page > self::get_max_page_number( $form ) ? 0 : $next_page;
$field_values_str = is_array( $field_values ) ? http_build_query( $field_values ) : $field_values;
$files_input = '';
if ( GFCommon::has_multifile_fileupload_field( $form ) || ! empty( RGFormsModel::$uploaded_files[ $form_id ] ) ) {
$files = ! empty( RGFormsModel::$uploaded_files[ $form_id ] ) ? json_encode( RGFormsModel::$uploaded_files[ $form_id ], JSON_UNESCAPED_UNICODE ) : '';
$files_input = " ";
}
$save_inputs = '';
if ( rgars( $form, 'save/enabled' ) ) {
$resume_token = isset( $_POST['gform_resume_token'] ) ? wp_unslash( $_POST['gform_resume_token'] ) : rgget( 'gf_token' ); // phpcs:ignore WordPress.Security.NonceVerification.Missing, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
$resume_token = sanitize_key( $resume_token );
$save_inputs = "
";
}
if ( GFCommon::form_requires_login( $form ) ) {
$footer .= wp_nonce_field( 'gform_submit_' . $form_id, '_gform_submit_nonce_' . $form_id, true, false );
}
$unique_id = isset( self::$submission[ $form_id ] ) && rgar( self::$submission[ $form_id ], 'resuming_incomplete_submission' ) == true ? rgar( GFFormsModel::$unique_ids, $form_id ) : GFFormsModel::get_form_unique_id( $form_id );
$style_settings = $is_valid_json ? esc_attr( $style_settings ) : '';
/** @var Honeypot\GF_Honeypot_Handler $honeypot_handler */
$honeypot_handler = GFForms::get_service_container()->get( Honeypot\GF_Honeypot_Service_Provider::GF_HONEYPOT_HANDLER );
if ( $honeypot_handler->is_speed_check_enabled( $form ) ) {
$footer .= " ";
}
$currency_code = GFCommon::get_currency();
$encrypted_currency = GFCommon::openssl_encrypt( $currency_code );
$footer .= "
{$save_inputs}
{$files_input}
";
return $footer;
}
public static function get_max_page_number( $form ) {
$page_number = 0;
foreach ( $form['fields'] as $field ) {
if ( $field->type == 'page' ) {
$page_number ++;
}
}
return $page_number == 0 ? 0 : $page_number + 1;
}
public static function get_first_page_with_error( $form ) {
$page = self::get_current_page( $form['id'] );
foreach ( $form['fields'] as $field ) {
if ( $field->failed_validation ) {
$page = $field->pageNumber;
break;
}
}
return $page;
}
/**
* Get the maximum field ID for the current form.
*
* @since unknown
* @since 1.9.14 Updated to public access.
* @since 2.4.15 Updated to use GFFormsModel::get_next_field_id().
*
* @param array $form The current form object.
*
* @return int
*/
public static function get_max_field_id( $form ) {
if ( ! empty( $form['fields'] ) ) {
$max = GFFormsModel::get_next_field_id( $form['fields'] ) - 1;
} else {
$max = 0;
}
return $max;
}
/**
* Used to determine the required validation result.
*
* @param GF_Field $field
* @param int $form_id
*
* @return bool
*/
public static function is_empty( $field, $form_id = 0 ) {
if ( empty( $_POST[ 'is_submit_' . $field->formId ] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing
return true;
}
return $field->is_value_submission_empty( $form_id );
}
/**
* Triggers saving or updating of the entry, spam eval, post creation, sending of notifications, and then returns the confirmation to be used for the current submission.
*
* @since unknown
* @since 2.7 Updated the $form param to pass by reference.
*
* @param array $form The form being processed.
* @param array $lead The entry being saved.
* @param bool $ajax Indicates if ajax is enabled for the form.
*
* @return string|array
*/
public static function handle_submission( &$form, &$lead, $ajax = false ) {
$form_id = absint( rgar( $form, 'id' ) );
$lead_id = gf_apply_filters( array( 'gform_entry_id_pre_save_lead', $form_id ), null, $form );
if ( ! empty( $lead_id ) ) {
GFCommon::log_debug( __METHOD__ . '(): The gform_entry_id_pre_save_lead filter was used to set the entry ID to ' . var_export( $lead_id, true ) ); // phpcs:ignore QITStandard.PHP.DebugCode.DebugFunctionFound
if ( empty( $lead ) ) {
$lead = array();
}
$lead['id'] = $lead_id;
}
// Passwords are not saved to the database but should be available during the submission process.
GF_Field_Password::stash_passwords( $form );
//creating entry in DB
RGFormsModel::save_lead( $form, $lead );
$lead = GFFormsModel::set_entry_meta( $lead, $form );
$is_spam = GFCommon::is_spam_entry( $lead, $form );
if ( $is_spam ) {
// Marking entry as spam.
GFFormsModel::update_entry_property( $lead['id'], 'status', 'spam', false, true );
$lead['status'] = 'spam';
// Creating entry note.
self::create_spam_entry_note( $lead['id'], $form['id'] );
}
// Passwords are not saved to the database but should be available during the submission process.
$lead = GF_Field_Password::hydrate_passwords( $lead );
if ( has_action( 'gform_entry_created' ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_entry_created.' );
/**
* Fired after an entry is created.
*
* @since 1.6.2
*
* @param array $lead The Entry object.
* @param array $form The Form object.
*/
do_action( 'gform_entry_created', $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_entry_created.' );
}
// Adding JS Logging statements if available.
self::log_browser_session( $form_id, $lead['id'] );
$gform_entry_post_save_args = array( 'gform_entry_post_save', $form_id );
if ( gf_has_filter( $gform_entry_post_save_args ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_entry_post_save.' );
/**
* Allows filtering of the entry after it has been saved to the database.
*
* @since Unknown.
*
* @param array $lead The entry that was saved to the database.
* @param array $form The form currently being processed.
*/
$lead = gf_apply_filters( $gform_entry_post_save_args, $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_entry_post_save.' );
}
gf_feed_processor()->save()->dispatch_on_shutdown();
RGFormsModel::set_current_lead( $lead, false );
if ( ! $is_spam ) {
GFCommon::create_post( $form, $lead );
//send notifications
GFCommon::send_form_submission_notifications( $form, $lead );
}
self::clean_up_files( $form );
// remove incomplete submission and purge expired
if ( rgars( $form, 'save/enabled' ) ) {
GFFormsModel::delete_draft_submission( rgpost( 'gform_resume_token' ) );
GFFormsModel::purge_expired_draft_submissions();
}
if ( has_action( 'gform_pre_handle_confirmation' ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_pre_handle_confirmation.' );
/**
* Fires during submission before the confirmation is processed.
*
* @since 2.3.3.10
*
* @param array $lead The entry array.
* @param array $form The Form array.
*/
do_action( 'gform_pre_handle_confirmation', $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_pre_handle_confirmation.' );
}
if ( has_filter( 'gform_entry_pre_handle_confirmation' ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_entry_pre_handle_confirmation.' );
/**
* Allows the entry to be modified before the confirmation is processed.
*
* @since 2.3.4.2
*
* @param array $lead The entry array.
* @param array $form The Form array.
*/
$lead = apply_filters( 'gform_entry_pre_handle_confirmation', $lead, $form );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_entry_pre_handle_confirmation.' );
}
//display confirmation message or redirect to confirmation page
return self::handle_confirmation( $form, $lead, $ajax );
}
/**
* Logs browser session data if available.
*
* @since 2.9.26
*
* @param int $form_id The form id
* @param int $entry_id The entry id
*
* @return void
*/
private static function log_browser_session( $form_id, $entry_id ) {
$is_logging_enabled = class_exists( 'GFLogging' ) && GFLogging::is_enabled( 'gravityforms-browser' );
if ( ! $is_logging_enabled ) {
return;
}
$data = rgpost( 'js_log' );
if ( empty( $data ) || ! is_string( $data ) ) {
return;
}
// Strip ANSI escapes for terminals
$data = preg_replace( '/\x1B\[[0-?]*[ -\/]*[@-~]/u', '', $data );
// Other basic sanitization.
$data = sanitize_textarea_field( $data );
if ( empty( $data ) ) {
return;
}
GFLogging::include_logger();
GFLogging::log_message( 'gravityforms-browser', "------ Form #{$form_id}, Entry #{$entry_id} -------\n" . $data . "\n", KLogger::DEBUG );
}
/**
* Creates an entry note with the spam reason and spam filter information in it.
*
* @since 2.7
*
* @param int $entry_id Submitted entry id.
* @param int $form_id Submitted form id.
*/
private static function create_spam_entry_note( $entry_id, $form_id ) {
$spam_filter = rgars( self::$submission, "{$form_id}/spam_filter" );
if ( empty( $spam_filter ) ) {
return;
}
$filter_name = ! rgempty( 'filter', $spam_filter ) ? $spam_filter['filter'] : __( 'Spam Filter', 'gravityforms' );
$note = __( 'This entry has been flagged as spam.', 'gravityforms' );
if ( ! rgempty( 'reason', $spam_filter ) ) {
// translators: Variable is a complete sentence containing the reason the entry was marked as spam.
$note .= ' ' . sprintf( __( 'Reason: %s', 'gravityforms' ), $spam_filter['reason'] );
}
GFAPI::add_note( $entry_id, 0, $filter_name, $note );
}
/**
* Deletes tmp files for the given form.
*
* @since Unknown
* @since 2.8.15 Added the $is_submission param.
*
* @param array $form The form the tmp files are to be deleted for.
* @param bool $is_submission Indicates if tmp files for the current form submission should be deletes as well.
*
* @return false|void
*/
public static function clean_up_files( $form, $is_submission = true ) {
$tmp_location = GFFormsModel::get_tmp_upload_location( $form['id'] );
$target_path = $tmp_location['path'];
if ( $is_submission ) {
$unique_form_id = rgpost( 'gform_unique_id' );
if ( ! ctype_alnum( $unique_form_id ) ) {
return false;
}
$filename = $unique_form_id . '_input_*';
$files = GFCommon::glob( $filename, $target_path );
if ( is_array( $files ) ) {
array_map( 'unlink', $files );
}
}
// clean up files from abandoned submissions older than 48 hours (30 days if Save and Continue is enabled)
$files = GFCommon::glob( '*', $target_path );
if ( is_array( $files ) ) {
$seconds_in_day = 24 * 60 * 60;
$save_enabled = rgars( $form, 'save/enabled' );
$expiration_days = $save_enabled ? 30 : 2;
/**
* Filter lifetime in days of temporary files.
*
* @since 2.1.3.5
*
* @param int $expiration_days The number of days temporary files should remain in the uploads directory. Default is 2 or 30 if save and continue is enabled.
* @param array $form The form currently being processed.
*/
$expiration_days = apply_filters( 'gform_temp_file_expiration_days', $expiration_days, $form );
if ( $save_enabled ) {
/**
* Filter lifetime in days of an incomplete form submission
*
* @since 2.1.3.5
*
* @param int $expiration_days The number of days temporary files should remain in the uploads directory.
*/
$expiration_days = apply_filters( 'gform_incomplete_submissions_expiration_days', $expiration_days );
}
$lifespan = $expiration_days * $seconds_in_day;
foreach ( $files as $file ) {
if ( is_file( $file ) && time() - filemtime( $file ) >= $lifespan ) {
unlink( $file );
}
}
}
}
/**
* Prepares the confirmation message or redirect to be used by the current submission.
*
* @since 2.1.1.11 Refactored to use GFFormDisplay::get_confirmation_message().
* @since 2.5 Updated to use GFFormDisplay::get_confirmation_url().
* @since 2.7 Updated the $form param to pass by reference.
*
* @param array $form The Form Object.
* @param array $entry The Entry Object.
* @param bool $ajax If AJAX is being used. Defaults to false.
* @param array $aux_data Additional data to use when building the confirmation message. Defaults to empty array.
*
* @return string|array
*/
public static function handle_confirmation( &$form, $entry, $ajax = false, $aux_data = array() ) {
$form = self::update_confirmation( $form, $entry );
GFCommon::log_debug( sprintf( '%s(): Preparing confirmation (#%s - %s).', __METHOD__, rgar( $form['confirmation'], 'id' ), rgar( $form['confirmation'], 'name' ) ) );
if ( rgar( $form['confirmation'], 'type' ) == 'message' ) {
$confirmation = self::get_confirmation_message( $form['confirmation'], $form, $entry, $aux_data );
} else {
$confirmation = array( 'redirect' => self::get_confirmation_url( $form['confirmation'], $form, $entry ) );
}
$form_id = absint( $form['id'] );
$filter = array( 'gform_confirmation', $form_id );
if ( gf_has_filters( $filter ) ) {
GFCommon::log_debug( __METHOD__ . '(): Executing functions hooked to gform_confirmation.' );
/**
* Allows the form confirmation to be overridden.
*
* @since unknown
*
* @param string|array $confirmation The confirmation message or an array when performing a redirect.
* @param array $form The form which was submitted.
* @param array $entry The entry created from the form submission.
* @param bool $ajax Indicates if ajax is enabled for the current form.
*/
$confirmation = gf_apply_filters( $filter, $confirmation, $form, $entry, $ajax );
GFCommon::log_debug( __METHOD__ . '(): Completed gform_confirmation.' );
}
if ( is_array( $confirmation ) && ! empty( $confirmation['redirect'] ) ) {
$suppress_redirect = false;
/**
* Allows the confirmation redirect header to be suppressed. Required by GFAPI::submit_form().
*
* @since 2.3
*
* @param bool $suppress_redirect Indicates if the redirect header should be suppressed.
*/
$suppress_redirect = apply_filters( 'gform_suppress_confirmation_redirect', $suppress_redirect );
if ( ( headers_sent() || $ajax ) && ! $suppress_redirect ) {
// Using client side redirect for AJAX forms or if headers have already been sent.
$confirmation = self::get_js_redirect_confirmation( $confirmation['redirect'], $ajax );
}
} elseif ( is_string( $confirmation ) && ! empty( $confirmation ) ) {
$confirmation = GFCommon::gform_do_shortcode( $confirmation );
} else {
$confirmation = null;
}
if ( empty( $confirmation ) ) {
GFCommon::log_debug( __METHOD__ . '(): Invalid confirmation; using default text instead.' );
$form['confirmation'] = GFFormsModel::get_default_confirmation();
$confirmation = self::get_confirmation_message( $form['confirmation'], $form, $entry );
}
GFCommon::log_debug( __METHOD__ . '(): Confirmation to be used => ' . print_r( $confirmation, true ) );
return $confirmation;
}
/**
* Returns the redirect URL for the current submission.
*
* @since 2.5
*
* @param array $confirmation The confirmation properties.
* @param array $form The form which was submitted.
* @param array $entry The entry created from the form submission.
*
* @return string
*/
public static function get_confirmation_url( $confirmation, $form, $entry ) {
if ( ! empty( $confirmation['pageId'] ) && $confirmation['type'] === 'page' ) {
$url = get_permalink( $confirmation['pageId'] );
if ( empty( $url ) ) {
GFCommon::log_debug( sprintf( '%s(): Selected page (%s) is invalid.', __METHOD__, $confirmation['pageId'] ) );
return '';
}
} else {
$url = rgar( $confirmation, 'url' );
if ( ! empty( $url ) ) {
$url = trim( GFCommon::replace_variables( $url, $form, $entry, false, false, true, 'text' ) );
}
if ( empty( $url ) ) {
GFCommon::log_debug( __METHOD__ . '(): URL is empty.' );
return '';
}
}
$url_info = parse_url( $url );
$query_string = rgar( $url_info, 'query' );
$dynamic_query = GFCommon::replace_variables( trim( $confirmation['queryString'] ), $form, $entry, true, false, false, 'text' );
$dynamic_query = str_replace( array( "\r", "\n" ), '', $dynamic_query );
$query_string .= rgempty( 'query', $url_info ) || empty( $dynamic_query ) ? $dynamic_query : '&' . $dynamic_query;
if ( ! empty( $url_info['fragment'] ) ) {
$query_string .= '#' . rgar( $url_info, 'fragment' );
}
$url = isset( $url_info['scheme'] ) ? $url_info['scheme'] : 'http';
$url .= '://' . rgar( $url_info, 'host' );
if ( ! empty( $url_info['port'] ) ) {
$url .= ':' . rgar( $url_info, 'port' );
}
$url .= rgar( $url_info, 'path' );
if ( ! empty( $query_string ) ) {
$url .= "?{$query_string}";
}
return $url;
}
/**
* Gets the confirmation message to be displayed.
*
* @since 2.1.1.11
* @access public
*
* @param array $confirmation The Confirmation Object.
* @param array $form The Form Object.
* @param array $entry The Entry Object.
* @param array $aux_data Additional data to be passed to GFCommon::replace_variables().
*
* @return string The confirmation message.
*/
public static function get_confirmation_message( $confirmation, $form, $entry, $aux_data = array() ) {
$ajax = isset( $_POST['gform_ajax'] ); // phpcs:ignore WordPress.Security.NonceVerification.Missing
$anchor = self::get_anchor( $form, $ajax );
$anchor = $anchor['tag'];
$nl2br = rgar( $confirmation, 'disableAutoformat' ) ? false : true;
$css_class = esc_attr( rgar( $form, 'cssClass' ) );
$message = GFCommon::replace_variables( $confirmation['message'], $form, $entry, false, true, $nl2br, 'html', $aux_data );
$message = self::maybe_sanitize_confirmation_message( $message );
$message = empty( $confirmation['message'] ) ? "{$anchor} " : "{$anchor}
';
return $message;
}
/**
* Sanitizes a confirmation message.
*
* @since 2.0.0
* @param $confirmation_message
*
* @return string
*/
private static function maybe_sanitize_confirmation_message( $confirmation_message ) {
return GFCommon::maybe_sanitize_confirmation_message( $confirmation_message );
}
private static function get_js_redirect_confirmation( $url, $ajax ) {
// JSON_HEX_TAG is available on PHP >= 5.3. It will prevent payloads such as