';
}
break;
}
/**
* Filter the markup of the order summary which appears on the Entry Detail, the {all_fields} merge tag and the {pricing_fields} merge tag.
*
* @since 2.1.2.5
* @see https://docs.gravityforms.com/gform_order_summary/
*
* @var string $field_data The order summary markup.
* @var array $form Current form object.
* @var array $lead Current entry object.
* @var array $products Current order summary object.
* @var string $format Format that should be used to display the summary ('html' or 'text').
*/
$field_data = gf_apply_filters( array( 'gform_order_summary', $form['id'] ), $field_data, $form, $lead, $products, $format );
return $field_data;
}
public static function send_user_notification( $form, $lead, $override_options = false ) {
_deprecated_function( 'send_user_notification', '1.7', 'send_notification' );
$notification = self::prepare_user_notification( $form, $lead, $override_options );
self::send_email( $notification['from'], $notification['to'], $notification['bcc'], $notification['reply_to'], $notification['subject'], $notification['message'], $notification['from_name'], $notification['message_format'], $notification['attachments'], $lead );
}
public static function send_admin_notification( $form, $lead, $override_options = false ) {
_deprecated_function( 'send_admin_notification', '1.7', 'send_notification' );
$notification = self::prepare_admin_notification( $form, $lead, $override_options );
self::send_email( $notification['from'], $notification['to'], $notification['bcc'], $notification['replyTo'], $notification['subject'], $notification['message'], $notification['from_name'], $notification['message_format'], $notification['attachments'], $lead );
}
private static function prepare_user_notification( $form, $lead, $override_options = false ) {
$form_id = $form['id'];
if ( ! isset( $form['autoResponder'] ) ) {
return;
}
//handling autoresponder email
$to_field = isset( $form['autoResponder']['toField'] ) ? rgget( $form['autoResponder']['toField'], $lead ) : '';
$to = gf_apply_filters( array( 'gform_autoresponder_email', $form_id ), $to_field, $form );
$subject = GFCommon::replace_variables( rgget( 'subject', $form['autoResponder'] ), $form, $lead, false, false );
$message_format = gf_apply_filters( array(
'gform_notification_format',
$form_id
), 'html', 'user', $form, $lead );
$message = GFCommon::replace_variables( rgget( 'message', $form['autoResponder'] ), $form, $lead, false, false, ! rgget( 'disableAutoformat', $form['autoResponder'] ), $message_format );
/**
* Allows the disabling of the notification message defined in the shortcode.
*
* @since 1.9.2
*
* @param bool true If the notification message shortcode should be used.
* @param array $form The Form Object.
* @param array $lead The Entry Object.
*/
if ( apply_filters( 'gform_enable_shortcode_notification_message', true, $form, $lead ) ) {
$message = do_shortcode( $message );
}
//Running trough variable replacement
$to = GFCommon::replace_variables( $to, $form, $lead, false, false );
$from = GFCommon::replace_variables( rgget( 'from', $form['autoResponder'] ), $form, $lead, false, false );
$bcc = GFCommon::replace_variables( rgget( 'bcc', $form['autoResponder'] ), $form, $lead, false, false );
$reply_to = GFCommon::replace_variables( rgget( 'replyTo', $form['autoResponder'] ), $form, $lead, false, false );
$from_name = GFCommon::replace_variables( rgget( 'fromName', $form['autoResponder'] ), $form, $lead, false, false );
// override default values if override options provided
if ( $override_options && is_array( $override_options ) ) {
foreach ( $override_options as $override_key => $override_value ) {
${$override_key} = $override_value;
}
}
$attachments = gf_apply_filters( array(
'gform_user_notification_attachments',
$form_id
), array(), $lead, $form );
//Disabling autoformat to prevent double autoformatting of messages
$disableAutoformat = '1';
return compact( 'to', 'from', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'attachments', 'disableAutoformat' );
}
/**
* Prepare admin notification.
*
* @deprecated
*
* @since unknown
*
* @param array $form The form object.
* @param array $lead The lead object.
* @param bool|array $override_options Defaults to false, or can be an array to override options.
*
* @return array
*/
private static function prepare_admin_notification( $form, $lead, $override_options = false ) {
$form_id = $form['id'];
//handling admin notification email
$subject = GFCommon::replace_variables( rgget( 'subject', $form['notification'] ), $form, $lead, false, false );
$message_format = gf_apply_filters( array(
'gform_notification_format',
$form_id
), 'html', 'admin', $form, $lead );
$message = GFCommon::replace_variables( rgget( 'message', $form['notification'] ), $form, $lead, false, false, ! rgget( 'disableAutoformat', $form['notification'] ), $message_format );
if ( apply_filters( 'gform_enable_shortcode_notification_message', true, $form, $lead ) ) {
$message = do_shortcode( $message );
}
$version_info = self::get_version_info();
$is_expired = ! rgempty( 'expiration_time', $version_info ) && $version_info['expiration_time'] < time();
if ( ! rgar( $version_info, 'is_valid_key' ) && $is_expired ) {
$message .= "
Your Gravity Forms License Key has expired. In order to continue receiving support and software updates you must renew your license key. You can do so by following the renewal instructions on the Gravity Forms Settings page in your WordPress Dashboard or by clicking here.";
}
$from = rgempty( 'fromField', $form['notification'] ) ? rgget( 'from', $form['notification'] ) : rgget( $form['notification']['fromField'], $lead );
if ( rgempty( 'fromNameField', $form['notification'] ) ) {
$from_name = rgget( 'fromName', $form['notification'] );
} else {
$field = RGFormsModel::get_field( $form, rgget( 'fromNameField', $form['notification'] ) );
$value = RGFormsModel::get_lead_field_value( $lead, $field );
$from_name = GFCommon::get_lead_field_display( $field, $value );
}
$replyTo = rgempty( 'replyToField', $form['notification'] ) ? rgget( 'replyTo', $form['notification'] ) : rgget( $form['notification']['replyToField'], $lead );
if ( rgempty( 'routing', $form['notification'] ) ) {
$email_to = rgempty( 'toField', $form['notification'] ) ? rgget( 'to', $form['notification'] ) : rgget( 'toField', $form['notification'] );
} else {
$email_to = array();
foreach ( $form['notification']['routing'] as $routing ) {
$source_field = RGFormsModel::get_field( $form, $routing['fieldId'] );
$field_value = RGFormsModel::get_lead_field_value( $lead, $source_field );
$is_value_match = RGFormsModel::is_value_match( $field_value, $routing['value'], $routing['operator'], $source_field, $routing, $form ) && ! RGFormsModel::is_field_hidden( $form, $source_field, array(), $lead );
if ( $is_value_match ) {
$email_to[] = $routing['email'];
}
}
$email_to = join( ',', $email_to );
}
//Running through variable replacement
$email_to = GFCommon::replace_variables( $email_to, $form, $lead, false, false );
$from = GFCommon::replace_variables( $from, $form, $lead, false, false );
$bcc = GFCommon::replace_variables( rgget( 'bcc', $form['notification'] ), $form, $lead, false, false );
$reply_to = GFCommon::replace_variables( $replyTo, $form, $lead, false, false );
$from_name = GFCommon::replace_variables( $from_name, $form, $lead, false, false );
//Filters the admin notification email to address. Allows users to change email address before notification is sent
$to = gf_apply_filters( array( 'gform_notification_email', $form_id ), $email_to, $lead );
// override default values if override options provided
if ( $override_options && is_array( $override_options ) ) {
foreach ( $override_options as $override_key => $override_value ) {
${$override_key} = $override_value;
}
}
$attachments = gf_apply_filters( array(
'gform_admin_notification_attachments',
$form_id
), array(), $lead, $form );
//Disabling autoformat to prevent double autoformatting of messages
$disableAutoformat = '1';
return compact( 'to', 'from', 'bcc', 'replyTo', 'subject', 'message', 'from_name', 'message_format', 'attachments', 'disableAutoformat' );
}
public static function send_notification( $notification, $form, $lead, $data = array() ) {
GFCommon::log_debug( "GFCommon::send_notification(): Starting to process notification (#{$notification['id']} - {$notification['name']})." );
$notification = gf_apply_filters( array( 'gform_notification', $form['id'] ), $notification, $form, $lead );
$to_field = '';
if ( rgar( $notification, 'toType' ) == 'field' ) {
$to_field = rgar( $notification, 'toField' );
if ( rgempty( 'toField', $notification ) ) {
$to_field = rgar( $notification, 'to' );
}
}
$email_to = rgar( $notification, 'to' );
//do routing logic if "to" field doesn't have a value (to support legacy notifications that will run routing prior to this method)
if ( empty( $email_to ) && rgar( $notification, 'toType' ) == 'routing' && ! empty( $notification['routing'] ) ) {
$email_to = array();
foreach ( $notification['routing'] as $routing ) {
if ( rgempty( 'email', $routing ) ) {
continue;
}
GFCommon::log_debug( __METHOD__ . '(): Evaluating Routing - rule => ' . print_r( $routing, 1 ) );
$source_field = RGFormsModel::get_field( $form, rgar( $routing, 'fieldId' ) );
$field_value = RGFormsModel::get_lead_field_value( $lead, $source_field );
$is_value_match = RGFormsModel::is_value_match( $field_value, rgar( $routing, 'value', '' ), rgar( $routing, 'operator', 'is' ), $source_field, $routing, $form ) && ! RGFormsModel::is_field_hidden( $form, $source_field, array(), $lead );
if ( $is_value_match ) {
$email_to[] = $routing['email'];
}
GFCommon::log_debug( __METHOD__ . '(): Evaluating Routing - field value => ' . print_r( $field_value, 1 ) );
$is_value_match = $is_value_match ? 'Yes' : 'No';
GFCommon::log_debug( __METHOD__ . '(): Evaluating Routing - is value match? ' . $is_value_match );
}
$email_to = join( ',', $email_to );
} elseif ( ! empty( $to_field ) ) {
$source_field = RGFormsModel::get_field( $form, $to_field );
$email_to = RGFormsModel::get_lead_field_value( $lead, $source_field );
}
// Running through variable replacement
$to = GFCommon::replace_variables( $email_to, $form, $lead, false, false, false, 'text', $data );
$subject = GFCommon::replace_variables( rgar( $notification, 'subject' ), $form, $lead, false, false, false, 'text', $data );
$from = GFCommon::replace_variables( rgar( $notification, 'from' ), $form, $lead, false, false, false, 'text', $data );
$from_name = GFCommon::replace_variables( rgar( $notification, 'fromName' ), $form, $lead, false, false, false, 'text', $data );
$bcc = GFCommon::replace_variables( rgar( $notification, 'bcc' ), $form, $lead, false, false, false, 'text', $data );
$replyTo = GFCommon::replace_variables( rgar( $notification, 'replyTo' ), $form, $lead, false, false, false, 'text', $data );
/**
* Enable the CC header for the notification.
*
* @since 2.3
*
* @param bool $enable_cc Should the CC header be enabled?
* @param array $notification The current notification object.
* @param array $from The current form object.
*/
$enable_cc = gf_apply_filters( array( 'gform_notification_enable_cc', $form['id'], $notification['id'] ), false, $notification, $form );
// Set CC if enabled.
$cc = $enable_cc ? GFCommon::replace_variables( rgar( $notification, 'cc' ), $form, $lead, false, false, false, 'text', $data ) : null;
$message_format = rgempty( 'message_format', $notification ) ? 'html' : rgar( $notification, 'message_format' );
$merge_tag_format = $message_format === 'multipart' ? 'html' : $message_format;
$message = GFCommon::replace_variables( rgar( $notification, 'message' ), $form, $lead, false, false, ! rgar( $notification, 'disableAutoformat' ), $merge_tag_format, $data );
if ( apply_filters( 'gform_enable_shortcode_notification_message', true, $form, $lead ) ) {
$message = do_shortcode( $message );
}
// Allow attachments to be passed as a single path (string) or an array of paths, if string provided, add to array.
$attachments = rgar( $notification, 'attachments' );
if ( ! empty( $attachments ) ) {
$attachments = is_array( $attachments ) ? $attachments : array( $attachments );
} else {
$attachments = array();
}
// Add attachment fields.
if ( rgar( $notification, 'enableAttachments', false ) ) {
// Get file upload fields and upload root.
$upload_fields = GFCommon::get_fields_by_type( $form, array( 'fileupload' ) );
$upload_root = GFFormsModel::get_upload_root();
foreach ( $upload_fields as $upload_field ) {
// Get field value.
$attachment_urls = rgar( $lead, $upload_field->id );
// If field value is empty, skip.
if ( empty( $attachment_urls ) ) {
self::log_debug( __METHOD__ . '(): No file(s) to attach for field #' . $upload_field->id );
continue;
}
// Convert to array.
$attachment_urls = $upload_field->multipleFiles ? json_decode( $attachment_urls, true ) : array( $attachment_urls );
self::log_debug( __METHOD__ . '(): Attaching file(s) for field #' . $upload_field->id . '. ' . print_r( $attachment_urls, true ) );
// Loop through attachment URLs; replace URL with path and add to attachments.
foreach ( $attachment_urls as $attachment_url ) {
$attachment_url = preg_replace( '|^(.*?)/gravity_forms/|', $upload_root, $attachment_url );
$attachments[] = $attachment_url;
}
}
}
$attachments = array_unique( $attachments );
if ( $message_format === 'multipart' ) {
// Creating alternate text message.
$text_message = GFCommon::replace_variables( rgar( $notification, 'message' ), $form, $lead, false, false, ! rgar( $notification, 'disableAutoformat' ), 'text', $data );
if ( apply_filters( 'gform_enable_shortcode_notification_message', true, $form, $lead ) ) {
$text_message = do_shortcode( $text_message );
}
// Formatting text message. Removes all tags.
$text_message = self::format_text_message( $text_message );
// Sends text and html messages to send_email()
$message = array(
'html' => $message,
'text' => $text_message,
);
}
self::send_email( $from, $to, $bcc, $replyTo, $subject, $message, $from_name, $message_format, $attachments, $lead, $notification, $cc );
return compact( 'to', 'from', 'bcc', 'replyTo', 'subject', 'message', 'from_name', 'message_format', 'attachments', 'cc' );
}
public static function send_notifications( $notification_ids, $form, $lead, $do_conditional_logic = true, $event = 'form_submission', $data = array() ) {
$entry_id = rgar( $lead, 'id' );
if ( ! is_array( $notification_ids ) || empty( $notification_ids ) ) {
GFCommon::log_debug( __METHOD__ . "(): Aborting. No notifications to process for {$event} event for entry #{$entry_id}." );
return;
}
GFCommon::log_debug( __METHOD__ . "(): Processing notifications for {$event} event for entry #{$entry_id}: " . print_r( $notification_ids, true ) . "\n(only active/applicable notifications are sent)" );
foreach ( $notification_ids as $notification_id ) {
if ( ! isset( $form['notifications'][ $notification_id ] ) ) {
continue;
}
if ( isset( $form['notifications'][ $notification_id ]['isActive'] ) && ! $form['notifications'][ $notification_id ]['isActive'] ) {
GFCommon::log_debug( __METHOD__ . "(): Notification is inactive, not processing notification (#{$notification_id} - {$form['notifications'][$notification_id]['name']}) for entry #{$entry_id}." );
continue;
}
$notification = $form['notifications'][ $notification_id ];
//check conditional logic when appropriate
if ( $do_conditional_logic && ! GFCommon::evaluate_conditional_logic( rgar( $notification, 'conditionalLogic' ), $form, $lead ) ) {
GFCommon::log_debug( __METHOD__ . "(): Notification conditional logic not met, not processing notification (#{$notification_id} - {$notification['name']}) for entry #{$entry_id}." );
continue;
}
if ( rgar( $notification, 'type' ) == 'user' ) {
//Getting user notification from legacy structure (for backwards compatibility)
$legacy_notification = GFCommon::prepare_user_notification( $form, $lead );
$notification = self::merge_legacy_notification( $notification, $legacy_notification );
} elseif ( rgar( $notification, 'type' ) == 'admin' ) {
//Getting admin notification from legacy structure (for backwards compatibility)
$legacy_notification = GFCommon::prepare_admin_notification( $form, $lead );
$notification = self::merge_legacy_notification( $notification, $legacy_notification );
}
//sending notification
self::send_notification( $notification, $form, $lead, $data );
}
}
public static function send_form_submission_notifications( $form, $lead ) {
GFAPI::send_notifications( $form, $lead );
}
private static function merge_legacy_notification( $notification, $notification_data ) {
$keys = array(
'to',
'from',
'bcc',
'replyTo',
'subject',
'message',
'from_name',
'message_format',
'attachments',
'disableAutoformat'
);
foreach ( $keys as $key ) {
$notification[ $key ] = rgar( $notification_data, $key );
}
return $notification;
}
public static function get_notifications_to_send( $event, $form, $lead ) {
$notifications = self::get_notifications( $event, $form );
$notifications_to_send = array();
foreach ( $notifications as $notification ) {
if ( GFCommon::evaluate_conditional_logic( rgar( $notification, 'conditionalLogic' ), $form, $lead ) ) {
$notifications_to_send[] = $notification;
}
}
return $notifications_to_send;
}
public static function get_notifications( $event, $form ) {
if ( rgempty( 'notifications', $form ) ) {
return array();
}
$notifications = array();
foreach ( $form['notifications'] as $notification ) {
$notification_event = rgar( $notification, 'event' );
$omit_from_resend = array( 'form_saved', 'form_save_email_requested' );
if ( $notification_event == $event || ( $event == 'resend_notifications' && ! in_array( $notification_event, $omit_from_resend ) ) ) {
$notifications[] = $notification;
}
}
return $notifications;
}
public static function has_admin_notification( $form ) {
return ( ! empty( $form['notification']['to'] ) || ! empty( $form['notification']['routing'] ) ) && ( ! empty( $form['notification']['subject'] ) || ! empty( $form['notification']['message'] ) );
}
public static function has_user_notification( $form ) {
return ! empty( $form['autoResponder']['toField'] ) && ( ! empty( $form['autoResponder']['subject'] ) || ! empty( $form['autoResponder']['message'] ) );
}
public static function send_email( $from, $to, $bcc, $reply_to, $subject, $message, $from_name = '', $message_format = 'html', $attachments = '', $entry = false, $notification = false, $cc = null ) {
global $phpmailer;
$entry_id = rgar( $entry, 'id' );
$to = str_replace( ' ', '', $to );
$bcc = str_replace( ' ', '', $bcc );
$cc = str_replace( ' ', '', $cc );
if ( ! GFCommon::is_valid_email( $from ) ) {
$from = get_bloginfo( 'admin_email' );
}
// Array containing email details.
$email = compact( 'from', 'to', 'bcc', 'reply_to', 'subject', 'message', 'from_name', 'message_format', 'attachments', 'cc' );
$error = false;
if ( ! GFCommon::is_valid_email_list( $to ) ) {
$error_info = esc_html__( 'Cannot send email because the TO address is invalid.', 'gravityforms' );
GFFormsModel::add_notification_note( $entry_id, false, $notification, $error_info, $email );
$error = new WP_Error( 'invalid_to', 'Cannot send email because the TO address is invalid.' );
} elseif ( empty( $subject ) && empty( $message ) ) {
$error_info = esc_html__( 'Cannot send email because there is no SUBJECT and no MESSAGE.', 'gravityforms' );
GFFormsModel::add_notification_note( $entry_id, false, $notification, $error_info, $email );
$error = new WP_Error( 'missing_subject_and_message', 'Cannot send email because there is no SUBJECT and no MESSAGE.' );
} elseif ( ! GFCommon::is_valid_email( $from ) ) {
$error_info = esc_html__( 'Cannot send email because the FROM address is invalid.', 'gravityforms' );
GFFormsModel::add_notification_note( $entry_id, false, $notification, $error_info, $email );
$error = new WP_Error( 'invalid_from', 'Cannot send email because the FROM address is invalid.' );
}
switch ( strtolower( $message_format ) ) {
case 'html' :
$content_type = 'text/html';
break;
case 'text' :
$content_type = 'text/plain';
break;
case 'multipart' :
$boundary = self::$email_boundary;
$content_type = "multipart/alternative; boundary={$boundary}";
break;
default :
//When content type is unknown, default to HTML
$content_type = 'text/html';
break;
}
if ( is_wp_error( $error ) ) {
GFCommon::log_error( __METHOD__ . '(): ' . $error->get_error_message() );
GFCommon::log_error( print_r( compact( 'to', 'subject', 'message' ), true ) );
/**
* Fires when an email from Gravity Forms has failed to send
*
* @since 1.8.10
*
* @param string $error The Error message returned after the email fails to send
* @param array $details The details of the message that failed
* @param array $entry The Entry object
*
*/
do_action( 'gform_send_email_failed', $error, $email, $entry );
return;
}
/**
* Allows for formatting of the TO email address to improve spam score.
*
* @param bool enabled Value being filtered. Return true to format email TO, or false to leave email TO as is. Defaults to false.
*
* @since 2.2.0.3
*/
if ( apply_filters( 'gform_format_email_to', false ) ) {
// Formats email TO field to improve Spam Assassin score
$to = self::format_email_to( $to );
}
$message = self::format_email_message( $message, $message_format, $subject );
$name = empty( $from_name ) ? $from : $from_name;
$headers = array();
$headers['From'] = 'From: "' . wp_strip_all_tags( $name, true ) . '" <' . $from . '>';
if ( GFCommon::is_valid_email_list( $reply_to ) ) {
$headers['Reply-To'] = "Reply-To: {$reply_to}";
}
if ( GFCommon::is_valid_email_list( $bcc ) ) {
$headers['Bcc'] = "Bcc: $bcc";
}
if ( GFCommon::is_valid_email_list( $cc ) ) {
$headers['Cc'] = "Cc: $cc";
}
$headers['Content-type'] = "Content-type: {$content_type}; charset=" . get_option( 'blog_charset' );
$abort_email = false;
/**
* Modify the email before a notification has been sent.
* You may also use this to prevent an email from being sent.
*
* @since 2.2.3.8 Added $entry parameter.
* @since 1.9.15.6 Added $notification parameter.
* @since Unknown
*
* @param array $email An array containing the email to address, subject, message, headers, attachments and abort email flag.
* @param string $message_format The message format: html or text.
* @param array $notification The current Notification object.
* @param array $entry The current Entry object.
*/
extract( apply_filters( 'gform_pre_send_email', compact( 'to', 'subject', 'message', 'headers', 'attachments', 'abort_email' ), $message_format, $notification, $entry ) );
$is_success = false;
// Determine when to add entry id information to the logging message.
$entry_info = $entry_id ? ' for entry #' . $entry_id : '';
if ( ! $abort_email ) {
GFCommon::log_debug( __METHOD__ . '(): Sending email via wp_mail().' );
GFCommon::log_debug( print_r( compact( 'to', 'subject', 'message', 'headers', 'attachments', 'abort_email' ), true ) );
// Content type filter is needed to get around a bug in WordPress that ignores the boundary attribute and character set.
add_filter( 'wp_mail_content_type', array( 'GFCommon', 'set_content_type_boundary' ) );
add_filter( 'wp_mail_charset', array( 'GFCommon', 'set_mail_charset' ) );
// Sending email.
$is_success = wp_mail( $to, $subject, $message, $headers, $attachments );
// Removing filter. It is only needed when sending GF notifications.
remove_filter( 'wp_mail_content_type', array( 'GFCommon', 'set_content_type_boundary' ) );
remove_filter( 'wp_mail_charset', array( 'GFCommon', 'set_mail_charset' ) );
$result = is_wp_error( $is_success ) ? $is_success->get_error_message() : $is_success;
// Get $phpmailer->ErrorInfo value if available.
$error_info = is_object( $phpmailer ) ? $phpmailer->ErrorInfo : '';
// Add note with sending result ?
GFFormsModel::add_notification_note( $entry_id, $result, $notification, $error_info, $email );
GFCommon::log_debug( __METHOD__ . "(): Result from wp_mail(): {$result}" );
if ( ! is_wp_error( $is_success ) && $is_success ) {
GFCommon::log_debug( sprintf( '%s(): WordPress successfully passed the notification email (#%s - %s)%s to the sending server.', __METHOD__, $notification['id'], $notification['name'], $entry_info ) );
} else {
GFCommon::log_error( sprintf( '%s(): WordPress was unable to send the notification email (#%s - %s)%s to the sending server.', __METHOD__, $notification['id'], $notification['name'], $entry_info ) );
}
if ( has_filter( 'phpmailer_init' ) ) {
GFCommon::log_debug( __METHOD__ . '(): The WordPress phpmailer_init hook has been detected, usually used by SMTP plugins. It can alter the email setup/content or sending server, and impact the notification deliverability.' );
}
if ( ! empty( $error_info ) ) {
GFCommon::log_debug( __METHOD__ . '(): PHPMailer class returned an error message: ' . $error_info );
}
} else {
GFCommon::log_debug( sprintf( '%s(): Aborting notification (#%s - %s)%s. The gform_pre_send_email hook was used to set the abort_email parameter to true.', __METHOD__, $notification['id'], $notification['name'], $entry_info ) );
}
self::add_emails_sent();
/**
* Fires after an email is sent
*
* @param bool $is_success True is successfully sent. False if failed
* @param string $to Recipient address
* @param string $subject Subject line
* @param string $message Message body
* @param string $headers Email headers
* @param string $attachments Email attachments
* @param string $message_format Format of the email. Ex: text, html
* @param string $from Address of the sender
* @param string $from_name Displayed name of the sender
* @param string $bcc BCC recipients
* @param string $reply_to Reply-to address
* @param array $entry Entry object associated with the sent email
* @param string $cc CC recipients
*
*/
do_action( 'gform_after_email', $is_success, $to, $subject, $message, $headers, $attachments, $message_format, $from, $from_name, $bcc, $reply_to, $entry, $cc );
}
/**
* Sets the boundary attribute of the Content-type email header.
* This is a target of the wp_mail_content_type filter and is needed to get around a WordPress bug
* That ignores the boundary attribute if added to the $headers parameter of wp_mail().
*
* @since 2.2
*
* @param $content_type Content type to be filtered
*
* @return string
*/
public static function set_content_type_boundary( $content_type ) {
if ( $content_type === 'multipart/alternative' ) {
$boundary = GFCommon::$email_boundary;
$content_type = "{$content_type}; boundary={$boundary}";
}
return $content_type;
}
/**
* Sets the character set email header.
*
* This is a target of the wp_mail_charset filter and is needed to get around a WordPress bug
* that ignores the charset attribute if added to the $headers parameter of wp_mail().
*
* @since 2.2
*
* @param string $charset Character set to be filtered.
*
* @return string
*/
public static function set_mail_charset( $charset ) {
if ( empty( $charset ) ) {
$charset = get_option( 'blog_charset' );
}
return $charset;
}
/**
* Formats emails to improve Spam Assassin score.
*
* @since 2.2
*
* @param string $to Email or comma separated list of emails to be formatted
*
* @return string
*/
private static function format_email_to( $to ) {
$emails = explode( ',', $to );
$email_list = array();
foreach ( $emails as $email ) {
if ( empty( $email ) ) {
continue;
}
// Formatting To to improve Spam Assassin score
if ( strpos( $email, '<' ) === false ) {
$email_list[] = "\"{$email}\" <$email>";
}
}
return implode( ',', $email_list );
}
/**
* Formats the email message to improve Spam Assassin score.
*
* @since 2.2
*
* @param string $message Email message to be formatted.
* @param string $message_format Format of the message to be sent. 'text' or 'html'.
* @param string $subject Email subject.
*
* @return string
*/
private static function format_email_message( $message, $message_format, $subject ) {
switch ( strtolower( $message_format ) ) {
case 'html' :
// Formatting HTML message
$message = self::format_html_message( $message, $subject );
return $message;
break;
case 'text' :
// No format needed for text messages
return $message;
break;
case 'multipart' :
$html_message = self::format_html_message( $message['html'], $subject );
$text_message = $message['text'];
$boundary = self::$email_boundary;
// Formatting multipart message
$message = "--{$boundary}
Content-Type: text/plain;
{$text_message}
--{$boundary}
Content-Type: text/html;
{$html_message}
--{$boundary}--";
return $message;
break;
default :
return $message;
}
}
public static function add_emails_sent() {
$count = self::get_emails_sent();
update_option( 'gform_email_count', ++ $count );
}
public static function get_emails_sent() {
$count = get_option( 'gform_email_count' );
if ( ! $count ) {
$count = 0;
}
return $count;
}
public static function get_api_calls() {
$count = get_option( 'gform_api_count' );
if ( ! $count ) {
$count = 0;
}
return $count;
}
public static function add_api_call() {
$count = self::get_api_calls();
update_option( 'gform_api_count', ++ $count );
}
public static function has_post_field( $fields ) {
foreach ( $fields as $field ) {
if ( in_array( $field->type, array(
'post_title',
'post_content',
'post_excerpt',
'post_category',
'post_image',
'post_tags',
'post_custom_field'
) ) ) {
return true;
}
}
return false;
}
public static function has_list_field( $form ) {
return self::has_field_by_type( $form, 'list' );
}
/**
* Whether the form contains a repeater field.
*
* @since 2.4
*
* @param $form
*
* @return bool
*/
public static function has_repeater_field( $form ) {
if ( is_array( $form['fields'] ) ) {
foreach ( $form['fields'] as $field ) {
if ( $field instanceof GF_Field_Repeater ) {
return true;
}
}
}
return false;
}
public static function has_credit_card_field( $form ) {
return self::has_field_by_type( $form, 'creditcard' );
}
/**
* Whether the form has a consent field.
*
* @since 2.4
*
* @param $form
*
* @return bool
*/
public static function has_consent_field( $form ) {
return self::has_field_by_type( $form, 'consent' );
}
private static function has_field_by_type( $form, $type ) {
if ( is_array( $form['fields'] ) ) {
foreach ( $form['fields'] as $field ) {
if ( RGFormsModel::get_input_type( $field ) == $type ) {
return true;
}
}
}
return false;
}
/***
* Determines if the current user has the proper cabalities to uninstall the plugin specified in $plugin_path.
* Plugins that have been network activated can only be uninstalled by a network admin.
*
* @since 2.3.1.12
* @access public
*
* @param string $caps Capabilities that current user must have to be able to uninstall the plugin.
* @param string $plugin_path Path of the plugin to be checked, relative to the plugins folder. i.e. "gravityforms/gravityforms.php"
*
* @return bool True if current user can uninstall the plugin. False otherwise
*/
public static function current_user_can_uninstall( $caps = 'gravityforms_uninstall', $plugin_path = 'gravityforms/gravityforms.php' ) {
$is_multisite = function_exists( 'is_multisite' ) && is_multisite();
$is_network_activated = is_plugin_active_for_network( $plugin_path );
//If an addon is network activated, it can only be uninstalled by a super admin.
if ( $is_multisite && $is_network_activated ) {
return is_super_admin();
} else {
return self::current_user_can_any( $caps );
}
}
public static function current_user_can_any( $caps ) {
if ( ! is_array( $caps ) ) {
$has_cap = current_user_can( $caps ) || current_user_can( 'gform_full_access' );
return $has_cap;
}
foreach ( $caps as $cap ) {
if ( current_user_can( $cap ) ) {
return true;
}
}
$has_full_access = current_user_can( 'gform_full_access' );
return $has_full_access;
}
public static function current_user_can_which( $caps ) {
foreach ( $caps as $cap ) {
if ( current_user_can( $cap ) ) {
return $cap;
}
}
return '';
}
/**
* Checks if the given type is a pricing field.
*
* @since 2.4.10 Added creditcard field.
* @since unknown
*
* @param string $field_type The value of the field type or inputType property.
*
* @return bool
*/
public static function is_pricing_field( $field_type ) {
$types = array( 'creditcard', 'donation' );
return in_array( $field_type, $types, true ) || self::is_product_field( $field_type );
}
/**
* Checks if a field is a product field.
*
* @access public
* @since 2.1.1.12 Added support for hiddenproduct, singleproduct, and singleshipping input types.
*
* @param string $field_type The field type.
*
* @return bool Returns true if it is a product field. Otherwise, false.
*/
public static function is_product_field( $field_type ) {
/**
* Filters the input types to use when checking if a field is a product field.
*
* @since 2.1.1.12 Added support for hiddenproduct, singleproduct, and singleshipping input types.
* @since 1.9.14
*
* @param $product_fields The product field types.
*/
$product_fields = apply_filters( 'gform_product_field_types', array(
'option',
'quantity',
'product',
'total',
'shipping',
'calculation',
'price',
'hiddenproduct',
'singleproduct',
'singleshipping'
) );
return in_array( $field_type, $product_fields );
}
/**
* Returns all the plugin capabilities.
*
* @since 2.4.18 Added gravityforms_logging and gravityforms_api_settings.
* @since 2.2.1.12 Added gravityforms_system_status.
* @since unknown
*
* @return array
*/
public static function all_caps() {
return array(
'gravityforms_edit_forms',
'gravityforms_delete_forms',
'gravityforms_create_form',
'gravityforms_view_entries',
'gravityforms_edit_entries',
'gravityforms_delete_entries',
'gravityforms_view_settings',
'gravityforms_edit_settings',
'gravityforms_export_entries',
'gravityforms_uninstall',
'gravityforms_view_entry_notes',
'gravityforms_edit_entry_notes',
'gravityforms_view_updates',
'gravityforms_view_addons',
'gravityforms_preview_forms',
'gravityforms_system_status',
'gravityforms_logging',
'gravityforms_api_settings',
);
}
public static function delete_directory( $dir ) {
if ( ! file_exists( $dir ) ) {
return;
}
if ( $handle = opendir( $dir ) ) {
$array = array();
while ( false !== ( $file = readdir( $handle ) ) ) {
if ( $file != '.' && $file != '..' ) {
if ( is_dir( $dir . $file ) ) {
if ( ! @rmdir( $dir . $file ) ) {
// Empty directory? Remove it
self::delete_directory( $dir . $file . '/' );
} // Not empty? Delete the files inside it
} else {
@unlink( $dir . $file );
}
}
}
closedir( $handle );
@rmdir( $dir );
}
}
public static function get_remote_message() {
return stripslashes( get_option( 'rg_gforms_message' ) );
}
public static function get_key() {
return get_option( 'rg_gforms_key' );
}
public static function has_update( $use_cache = true ) {
$version_info = GFCommon::get_version_info( $use_cache );
$version = rgar( $version_info, 'version' );
return empty( $version ) ? false : version_compare( GFCommon::$version, $version, '<' );
}
public static function get_key_info( $key ) {
$options = array( 'method' => 'POST', 'timeout' => 3 );
$options['headers'] = array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
'Referer' => get_bloginfo( 'url' )
);
$raw_response = self::post_to_manager( 'api.php', "op=get_key&key={$key}", $options );
if ( is_wp_error( $raw_response ) || $raw_response['response']['code'] != 200 ) {
return array();
}
$key_info = unserialize( trim( $raw_response['body'] ) );
return $key_info ? $key_info : array();
}
public static function get_version_info( $cache = true ) {
$version_info = get_option( 'gform_version_info' );
if ( ! $cache ) {
$version_info = null;
} else {
// Checking cache expiration
$cache_duration = DAY_IN_SECONDS; // 24 hours.
$cache_timestamp = $version_info && isset( $version_info['timestamp'] ) ? $version_info['timestamp'] : 0;
// Is cache expired ?
if ( $cache_timestamp + $cache_duration < time() ) {
$version_info = null;
}
}
if ( is_wp_error( $version_info ) || isset( $version_info['headers'] ) ) {
// Legacy ( < 2.1.1.14 ) version info contained the whole raw response.
$version_info = null;
}
if ( ! $version_info ) {
//Getting version number
$options = array( 'method' => 'POST', 'timeout' => 20 );
$options['headers'] = array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
'Referer' => get_bloginfo( 'url' ),
);
$options['body'] = self::get_remote_post_params();
$options['timeout'] = 15;
$nocache = $cache ? '' : 'nocache=1'; //disabling server side caching
$raw_response = self::post_to_manager( 'version.php', $nocache, $options );
if ( is_wp_error( $raw_response ) || rgars( $raw_response, 'response/code' ) != 200 ) {
$version_info = array( 'is_valid_key' => '1', 'version' => '', 'url' => '', 'is_error' => '1' );
} else {
$version_info = json_decode( $raw_response['body'], true );
if ( empty( $version_info ) ) {
$version_info = array( 'is_valid_key' => '1', 'version' => '', 'url' => '', 'is_error' => '1' );
}
}
$version_info['timestamp'] = time();
// Caching response.
update_option( 'gform_version_info', $version_info, false ); //caching version info
}
return $version_info;
}
public static function get_remote_request_params() {
global $wpdb;
return sprintf( 'of=GravityForms&key=%s&v=%s&wp=%s&php=%s&mysql=%s&version=2', urlencode( self::get_key() ), urlencode( self::$version ), urlencode( get_bloginfo( 'version' ) ), urlencode( phpversion() ), urlencode( $wpdb->db_version() ) );
}
public static function get_remote_post_params() {
global $wpdb;
if ( ! function_exists( 'get_plugins' ) ) {
require_once( ABSPATH . 'wp-admin/includes/plugin.php' );
}
$plugin_list = get_plugins();
$site_url = get_bloginfo( 'url' );
$plugins = array();
$active_plugins = get_option( 'active_plugins' );
foreach ( $plugin_list as $key => $plugin ) {
$is_active = in_array( $key, $active_plugins );
$slug = substr( $key, 0, strpos( $key, '/' ) );
if ( empty( $slug ) ) {
$slug = str_replace( '.php', '', $key );
}
$plugins[] = array(
'name' => str_replace( 'phpinfo()', 'PHP Info', $plugin['Name'] ),
'slug' => $slug,
'version' => $plugin['Version'],
'is_active' => $is_active,
);
}
$plugins = json_encode( $plugins );
//get theme info
$theme = wp_get_theme();
$theme_name = $theme->get( 'Name' );
$theme_uri = $theme->get( 'ThemeURI' );
$theme_version = $theme->get( 'Version' );
$theme_author = $theme->get( 'Author' );
$theme_author_uri = $theme->get( 'AuthorURI' );
$form_counts = GFFormsModel::get_form_count();
$active_count = $form_counts['active'];
$inactive_count = $form_counts['inactive'];
$fc = abs( $active_count ) + abs( $inactive_count );
$entry_count = GFFormsModel::get_entry_count_all_forms( 'active' );
$meta_counts = GFFormsModel::get_entry_meta_counts();
$im = is_multisite();
$lang = get_locale();
$post = array(
'of' => 'gravityforms',
'key' => self::get_key(),
'v' => self::$version,
'wp' => get_bloginfo( 'version' ),
'php' => phpversion(),
'mysql' => $wpdb->db_version(),
'version' => '2',
'plugins' => $plugins,
'tn' => $theme_name,
'tu' => $theme_uri,
'tv' => $theme_version,
'ta' => $theme_author,
'tau' => $theme_author_uri,
'im' => $im,
'fc' => $fc,
'ec' => $entry_count,
'emc' => self::get_emails_sent(),
'api' => self::get_api_calls(),
'emeta' => $meta_counts['meta'],
'ed' => $meta_counts['details'],
'en' => $meta_counts['notes'],
'lang' => $lang
);
return $post;
}
public static function ensure_wp_version() {
if ( ! GF_SUPPORTED_WP_VERSION ) {
echo "
" . sprintf( esc_html__( 'Gravity Forms requires WordPress %s or greater. You must upgrade WordPress in order to use Gravity Forms', 'gravityforms' ), GF_MIN_WP_VERSION ) . '
';
return false;
}
return true;
}
public static function check_update( $option, $cache = true ) {
if ( ! is_object( $option ) ) {
return $option;
}
$version_info = self::get_version_info( $cache );
if ( ! $version_info ) {
return $option;
}
$plugin_path = plugin_basename( GFCommon::get_base_path() ) . '/gravityforms.php';
if ( empty( $option->response[ $plugin_path ] ) ) {
$option->response[ $plugin_path ] = new stdClass();
}
$version = rgar( $version_info, 'version' );
$url = rgar( $version_info, 'url' );
$plugin = array(
'url' => 'https://gravityforms.com',
'slug' => 'gravityforms',
'plugin' => $plugin_path,
'package' => str_replace( '{KEY}', GFCommon::get_key(), $url ),
'new_version' => $version,
'id' => '0',
);
// Empty response means that the key is invalid. Do not queue for upgrade.
if ( ! rgar( $version_info, 'is_valid_key' ) || version_compare( GFCommon::$version, $version, '>=' ) ) {
unset( $option->response[ $plugin_path ] );
$option->no_update[ $plugin_path ] = (object) $plugin;
} else {
$option->response[ $plugin_path ] = (object) $plugin;
}
return $option;
}
public static function cache_remote_message() {
//Getting version number
$key = GFCommon::get_key();
$body = "key=$key";
$options = array( 'method' => 'POST', 'timeout' => 3, 'body' => $body );
$options['headers'] = array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=' . get_option( 'blog_charset' ),
'Content-Length' => strlen( $body ),
'User-Agent' => 'WordPress/' . get_bloginfo( 'version' ),
'Referer' => get_bloginfo( 'url' )
);
$raw_response = self::post_to_manager( 'message.php', GFCommon::get_remote_request_params(), $options );
if ( is_wp_error( $raw_response ) || 200 != $raw_response['response']['code'] ) {
$message = '';
} else {
$message = $raw_response['body'];
}
//validating that message is a valid Gravity Form message. If message is invalid, don't display anything
if ( substr( $message, 0, 10 ) != '' ) {
$message = '';
}
update_option( 'rg_gforms_message', $message );
}
/**
* Post request to Gravity Manager.
*
* @since unknown
* @since 2.5 Remove Gravity Manager Proxy.
*
* @param string $file The file.
* @param string $query The query string.
* @param array $options The options.
*
* @return array|WP_Error
*/
public static function post_to_manager( $file, $query, $options ) {
$request_url = GRAVITY_MANAGER_URL . '/' . $file . '?' . $query;
self::log_debug( __METHOD__ . '(): endpoint: ' . $request_url );
$raw_response = wp_remote_post( $request_url, $options );
self::log_remote_response( $raw_response );
return $raw_response;
}
/**
* Converts the given timestamp to a pseudo timestamp which has been adjusted for the timezone in the WordPress settings.
*
*
* @param int $timestamp
*
* @return int
*/
public static function get_local_timestamp( $timestamp = null ) {
if ( $timestamp == null ) {
$timestamp = time();
}
$gmt_datetime = gmdate( 'Y-m-d H:i:s', $timestamp );
return strtotime( get_date_from_gmt( $gmt_datetime ) );
}
public static function get_gmt_timestamp( $local_timestamp ) {
return $local_timestamp - ( get_option( 'gmt_offset' ) * 3600 );
}
public static function format_date( $gmt_datetime, $is_human = true, $date_format = '', $include_time = true ) {
if ( empty( $gmt_datetime ) ) {
return '';
}
//adjusting date to local configured Time Zone
$lead_gmt_time = mysql2date( 'G', $gmt_datetime );
$lead_local_time = self::get_local_timestamp( $lead_gmt_time );
if ( empty( $date_format ) ) {
$date_format = get_option( 'date_format' );
}
if ( $is_human ) {
$time_diff = time() - $lead_gmt_time;
if ( $time_diff > 0 && $time_diff < 24 * 60 * 60 ) {
$date_display = sprintf( esc_html__( '%s ago', 'gravityforms' ), human_time_diff( $lead_gmt_time ) );
} else {
$date_display = $include_time ? sprintf( esc_html__( '%1$s at %2$s', 'gravityforms' ), date_i18n( $date_format, $lead_local_time, true ), date_i18n( get_option( 'time_format' ), $lead_local_time, true ) ) : date_i18n( $date_format, $lead_local_time, true );
}
} else {
$date_display = $include_time ? sprintf( esc_html__( '%1$s at %2$s', 'gravityforms' ), date_i18n( $date_format, $lead_local_time, true ), date_i18n( get_option( 'time_format' ), $lead_local_time, true ) ) : date_i18n( $date_format, $lead_local_time, true );
}
return $date_display;
}
public static function get_selection_value( $value ) {
$ary = explode( '|', $value );
$val = $ary[0];
return $val;
}
public static function selection_display( $value, $field, $currency = '', $use_text = false ) {
if ( is_array( $value ) ) {
return '';
}
if ( $field !== null && $field->enablePrice ) {
$ary = explode( '|', $value );
$val = $ary[0];
$price = count( $ary ) > 1 ? $ary[1] : '';
} else {
$val = $value;
$price = '';
}
if ( $use_text ) {
$val = RGFormsModel::get_choice_text( $field, $val );
}
if ( ! empty( $price ) ) {
return "$val (" . self::to_money( $price, $currency ) . ')';
} else {
return $val;
}
}
public static function date_display( $value, $input_format = 'mdy', $output_format = false ) {
if ( ! $output_format ) {
$output_format = $input_format;
}
$date = self::parse_date( $value, $input_format );
if ( empty( $date ) ) {
return $value;
}
list( $position, $separator ) = rgexplode( '_', $output_format, 2 );
switch ( $separator ) {
case 'dash' :
$separator = '-';
break;
case 'dot' :
$separator = '.';
break;
default :
$separator = '/';
break;
}
switch ( $position ) {
case 'year' :
case 'month' :
case 'day' :
return $date[ $position ];
case 'ymd' :
return $date['year'] . $separator . $date['month'] . $separator . $date['day'];
break;
case 'dmy' :
return $date['day'] . $separator . $date['month'] . $separator . $date['year'];
break;
default :
return $date['month'] . $separator . $date['day'] . $separator . $date['year'];
break;
}
}
public static function parse_date( $date, $format = 'mdy' ) {
$date_info = array();
$position = substr( $format, 0, 3 );
if ( is_array( $date ) ) {
switch ( $position ) {
case 'mdy' :
$date_info['month'] = rgar( $date, 0 );
$date_info['day'] = rgar( $date, 1 );
$date_info['year'] = rgar( $date, 2 );
break;
case 'dmy' :
$date_info['day'] = rgar( $date, 0 );
$date_info['month'] = rgar( $date, 1 );
$date_info['year'] = rgar( $date, 2 );
break;
case 'ymd' :
$date_info['year'] = rgar( $date, 0 );
$date_info['month'] = rgar( $date, 1 );
$date_info['day'] = rgar( $date, 2 );
break;
}
return $date_info;
}
$date = preg_replace( "|[/\.]|", '-', $date );
if ( preg_match( '/^(\d{1,4})-(\d{1,2})-(\d{1,4})$/', $date, $matches ) ) {
if ( strlen( $matches[1] ) == 4 ) {
//format yyyy-mm-dd
$date_info['year'] = $matches[1];
$date_info['month'] = $matches[2];
$date_info['day'] = $matches[3];
} else if ( $position == 'mdy' ) {
//format mm-dd-yyyy
$date_info['month'] = $matches[1];
$date_info['day'] = $matches[2];
$date_info['year'] = $matches[3];
} else {
//format dd-mm-yyyy
$date_info['day'] = $matches[1];
$date_info['month'] = $matches[2];
$date_info['year'] = $matches[3];
}
}
return $date_info;
}
public static function truncate_url( $url ) {
// parse URL to break it out into pieces
$parsed_url = parse_url( $url );
if ( isset( $parsed_url['path'] ) ) {
if ( $parsed_url['path'] == '/' ) {
// In instances where the path is just /, set truncated URL to be the host.
$truncated_url = $parsed_url['host'];
} else {
// Get the basename from the URL Path
$truncated_url = basename( $parsed_url['path'] );
}
// Append a query string if necessary.
if ( isset( $parsed_url['query'] ) ) {
$truncated_url .= '/?...';
}
} else {
// Anything outside of the above will fall back to the old truncation logic.
$truncated_url = basename( $url );
if ( empty( $truncated_url ) ) {
$truncated_url = dirname( $url );
}
}
return $truncated_url;
}
public static function get_field_placeholder_attribute( $field ) {
$placeholder_value = GFCommon::replace_variables_prepopulate( $field->placeholder );
return ! empty( $placeholder_value ) ? sprintf( "placeholder='%s'", esc_attr( $placeholder_value ) ) : '';
}
public static function get_input_placeholder_attribute( $input ) {
$placeholder_value = self::get_input_placeholder_value( $input );
return ! empty( $placeholder_value ) ? sprintf( "placeholder='%s'", esc_attr( $placeholder_value ) ) : '';
}
public static function get_input_placeholder_value( $input ) {
$placeholder = rgar( $input, 'placeholder' );
return empty( $placeholder ) ? '' : GFCommon::replace_variables_prepopulate( $placeholder );
}
public static function get_tabindex() {
return GFCommon::$tab_index > 0 ? "tabindex='" . GFCommon::$tab_index ++ . "'" : '';
}
/**
* @deprecated
*
* @param GF_Field_Checkbox $field
* @param $value
* @param $disabled_text
*
* @return mixed
*/
public static function get_checkbox_choices( $field, $value, $disabled_text ) {
_deprecated_function( 'get_checkbox_choices', '1.9', 'GF_Field_Checkbox::get_checkbox_choices' );
return $field->get_checkbox_choices( $value, $disabled_text );
}
/**
* @deprecated Deprecated since 1.9. Use GF_Field_Checkbox::get_radio_choices() instead.
*
* @param GF_Field_Radio $field
* @param string $value
* @param $disabled_text
*
* @return mixed
*/
public static function get_radio_choices( $field, $value = '', $disabled_text ) {
_deprecated_function( 'get_radio_choices', '1.9', 'GF_Field_Checkbox::get_radio_choices' );
return $field->get_radio_choices( $value, $disabled_text );
}
public static function get_field_type_title( $type ) {
$gf_field = GF_Fields::get( $type );
if ( ! empty( $gf_field ) ) {
return $gf_field->get_form_editor_field_title();
}
return apply_filters( 'gform_field_type_title', $type, $type );
}
public static function get_select_choices( $field, $value = '', $support_placeholders = true ) {
$choices = '';
$placeholder = '';
if ( $support_placeholders && ! rgblank( $field->placeholder ) ) {
$placeholder = self::replace_variables_prepopulate( $field->placeholder );
}
if ( rgget( 'view' ) == 'entry' && empty( $value ) && rgblank( $placeholder ) ) {
$choices .= "";
}
if ( is_array( $field->choices ) ) {
if ( ! rgblank( $placeholder ) ) {
$selected = empty( $value ) ? "selected='selected'" : '';
$choices .= sprintf( "", $selected, esc_html( $placeholder) );
}
foreach ( $field->choices as $choice ) {
//needed for users upgrading from 1.0
$field_value = ! empty( $choice['value'] ) || $field->enableChoiceValue || $field->type == 'post_category' ? $choice['value'] : $choice['text'];
if ( $field->enablePrice ) {
$price = rgempty( 'price', $choice ) ? 0 : GFCommon::to_number( rgar( $choice, 'price' ) );
$field_value .= '|' . $price;
}
if ( ! isset( $_GET['gf_token'] ) && empty( $_POST ) && self::is_empty_array( $value ) && rgget('view') != 'entry' ) {
$selected = rgar( $choice, 'isSelected' ) ? "selected='selected'" : '';
} else {
if ( is_array( $value ) ) {
$is_match = false;
foreach ( $value as $item ) {
if ( RGFormsModel::choice_value_match( $field, $choice, $item ) ) {
$is_match = true;
break;
}
}
$selected = $is_match ? "selected='selected'" : '';
} else {
$selected = RGFormsModel::choice_value_match( $field, $choice, $value ) ? "selected='selected'" : '';
}
}
$choice_markup = sprintf( "", esc_attr( $field_value ), $selected, esc_html( $choice['text'] ) );
$choices .= gf_apply_filters( array(
'gform_field_choice_markup_pre_render',
$field->formId,
$field->id
), $choice_markup, $choice, $field, $value );
}
}
return $choices;
}
public static function is_section_empty( $section_field, $form, $entry ) {
$cache_key = "GFCommon::is_section_empty_{$form['id']}_{$section_field->id}";
$value = GFCache::get( $cache_key, $is_hit, false );
if ( $value !== false ) {
return $value == true;
}
$fields = self::get_section_fields( $form, $section_field->id );
if ( ! is_array( $fields ) ) {
GFCache::set( $cache_key, 1 );
return true;
}
foreach ( $fields as $field ) {
$value = GFFormsModel::get_lead_field_value( $entry, $field );
$value = GFCommon::get_lead_field_display( $field, $value, rgar( $entry, 'currency' ) );
if ( rgblank( $value ) ) {
continue;
}
// most fields are displayed in the section by default, exceptions are handled below
$is_field_displayed_in_section = true;
// by default, product fields are not displayed in their containing section (displayed in a product summary table)
// if the filter is used to disable this, product fields are displayed in the section like other fields
if ( self::is_product_field( $field->type ) ) {
/**
* By default, product fields are not displayed in their containing section (displayed in a product summary table). If the filter is used to disable this, product fields are displayed in the section like other fields
*
* @param array $field The Form Fields Object
* @param array $form The Form Object
* @param array $entry The Entry object
*
*/
$display_product_summary = apply_filters( 'gform_display_product_summary', true, $field, $form, $entry );
$is_field_displayed_in_section = ! $display_product_summary;
}
if ( $is_field_displayed_in_section ) {
GFCache::set( $cache_key, 0 );
return false;
}
}
GFCache::set( $cache_key, 1 );
return true;
}
public static function get_section_fields( $form, $section_field_id ) {
$fields = array();
$in_section = false;
foreach ( $form['fields'] as $field ) {
if ( in_array( $field->type, array( 'section', 'page' ) ) && $in_section ) {
return $fields;
}
if ( $field->id == $section_field_id ) {
$in_section = true;
}
if ( $in_section ) {
$fields[] = $field;
}
}
return $fields;
}
public static function get_us_state_code( $state_name ) {
return GF_Fields::get( 'address' )->get_us_state_code( $state_name );
}
public static function get_country_code( $country_name ) {
return GF_Fields::get( 'address' )->get_country_code( $country_name );
}
public static function get_us_states() {
return GF_Fields::get( 'address' )->get_us_states();
}
public static function get_canadian_provinces() {
return GF_Fields::get( 'address' )->get_canadian_provinces();
}
public static function is_post_field( $field ) {
return in_array( $field->type, array(
'post_title',
'post_tags',
'post_category',
'post_custom_field',
'post_content',
'post_excerpt',
'post_image'
) );
}
public static function get_fields_by_type( $form, $types ) {
return GFAPI::get_fields_by_type( $form, $types );
}
public static function has_pages( $form ) {
return sizeof( GFAPI::get_fields_by_type( $form, array( 'page' ) ) ) > 0;
}
public static function get_product_fields_by_type( $form, $types, $product_id ) {
global $_product_fields;
$key = json_encode( $types ) . '_' . $product_id . '_' . $form['id'];
if ( ! isset( $_product_fields[ $key ] ) ) {
$fields = array();
for ( $i = 0, $count = sizeof( $form['fields'] ); $i < $count; $i ++ ) {
$field = $form['fields'][ $i ];
if ( in_array( $field->type, $types ) && $field->productField == $product_id ) {
$fields[] = $field;
}
}
$_product_fields[ $key ] = $fields;
}
return $_product_fields[ $key ];
}
public static function form_page_title( $form ) {
$editable_class = GFCommon::current_user_can_any( 'gravityforms_edit_forms' ) ? ' gform_settings_page_title_editable' : '';
?>
";
}
}
/**
* Filters the field input markup.
*
* @since 2.1.2.14 Added form and field ID modifiers.
*
* @param string empty The markup. Defaults to an empty string.
* @param array $field The Field Object.
* @param int $lead_id The entry ID.
* @param string $value The field value.
* @param int $form_id The form ID.
*/
$field_input = gf_apply_filters( array( 'gform_field_input', $form_id, $field->id ), '', $field, $value, $lead_id, $form_id );
if ( $field_input ) {
return $field_input;
}
// Pricing fields are not editable.
if ( rgget('view') == 'entry' && self::is_pricing_field( $field->type ) ) {
return "
" . esc_html__( 'Pricing fields are not editable' , 'gravityforms' ) . '
';
}
// Add categories as choices for Post Category field
if ( $field->type == 'post_category' ) {
$field = self::add_categories_as_choices( $field, $value );
}
$type = RGFormsModel::get_input_type( $field );
switch ( $type ) {
case 'honeypot':
$autocomplete = RGFormsModel::is_html5_enabled() ? "autocomplete='off'" : '';
return "";
break;
case 'adminonly_hidden' :
$inputs = $field->get_entry_inputs();
if ( ! is_array( $inputs ) ) {
if ( is_array( $value ) ) {
$value = json_encode( $value );
}
return sprintf( "", $id, esc_attr( $field_id ), esc_attr( $value ) );
}
$fields = '';
foreach ( $inputs as $input ) {
$fields .= sprintf( "", $input['id'], esc_attr( rgar( $value, strval( $input['id'] ) ) ) );
}
return $fields;
break;
default :
if ( ! empty( $post_link ) ) {
return $post_link;
}
if ( $form === null ) {
$form = array( 'id' => 0 );
}
if ( ! isset( $lead ) ) {
$lead = null;
}
return $field->get_field_input( $form, $value, $lead );
break;
}
}
public static function is_ssl() {
global $wordpress_https;
$is_ssl = false;
$has_https_plugin = class_exists( 'WordPressHTTPS' ) && isset( $wordpress_https );
$has_is_ssl_method = $has_https_plugin && method_exists( 'WordPressHTTPS', 'is_ssl' );
$has_isSsl_method = $has_https_plugin && method_exists( 'WordPressHTTPS', 'isSsl' );
//Use the WordPress HTTPs plugin if installed
if ( $has_https_plugin && $has_is_ssl_method ) {
$is_ssl = $wordpress_https->is_ssl();
} else if ( $has_https_plugin && $has_isSsl_method ) {
$is_ssl = $wordpress_https->isSsl();
} else {
$is_ssl = is_ssl();
}
if ( ! $is_ssl && isset( $_SERVER['HTTP_CF_VISITOR'] ) && strpos( $_SERVER['HTTP_CF_VISITOR'], 'https' ) ) {
$is_ssl = true;
}
return apply_filters( 'gform_is_ssl', $is_ssl );
}
public static function is_preview() {
$url_info = parse_url( RGFormsModel::get_current_page_url() );
$file_name = basename( $url_info['path'] );
return $file_name == 'preview.php' || rgget( 'gf_page', $_GET ) == 'preview';
}
public static function clean_extensions( $extensions ) {
$count = sizeof( $extensions );
for ( $i = 0; $i < $count; $i ++ ) {
$extensions[ $i ] = str_replace( '.', '', str_replace( ' ', '', $extensions[ $i ] ) );
}
return $extensions;
}
public static function get_disallowed_file_extensions() {
$extensions = array(
'php',
'asp',
'aspx',
'cmd',
'csh',
'bat',
'html',
'htm',
'hta',
'jar',
'exe',
'com',
'js',
'lnk',
'htaccess',
'phtml',
'ps1',
'ps2',
'php3',
'php4',
'php5',
'php6',
'py',
'rb',
'tmp'
);
// Intended for internal use - not to be included in the documentation.
$extensions = apply_filters( 'gform_disallowed_file_extensions', $extensions );
return $extensions;
}
public static function match_file_extension( $file_name, $extensions ) {
if ( empty ( $extensions ) || ! is_array( $extensions ) ) {
return false;
}
$ext = strtolower( pathinfo( $file_name, PATHINFO_EXTENSION ) );
if ( in_array( $ext, $extensions ) ) {
return true;
}
return false;
}
public static function file_name_has_disallowed_extension( $file_name ) {
return self::match_file_extension( $file_name, self::get_disallowed_file_extensions() ) || strpos( strtolower( $file_name ), '.php.' ) !== false;
}
public static function check_type_and_ext( $file, $file_name = '' ) {
if ( empty( $file_name ) ) {
$file_name = $file['name'];
}
$tmp_name = $file['tmp_name'];
// Whitelist the mime type and extension
$wp_filetype = wp_check_filetype_and_ext( $tmp_name, $file_name );
$ext = empty( $wp_filetype['ext'] ) ? '' : $wp_filetype['ext'];
$type = empty( $wp_filetype['type'] ) ? '' : $wp_filetype['type'];
$proper_filename = empty( $wp_filetype['proper_filename'] ) ? '' : $wp_filetype['proper_filename'];
if ( $proper_filename ) {
return new WP_Error( 'invalid_file', esc_html__( 'There was an problem while verifying your file.' ) );
}
if ( ! $ext ) {
return new WP_Error( 'illegal_extension', esc_html__( 'Sorry, this file extension is not permitted for security reasons.' ) );
}
if ( ! $type ) {
return new WP_Error( 'illegal_type', esc_html__( 'Sorry, this file type is not permitted for security reasons.' ) );
}
return true;
}
public static function to_money( $number, $currency_code = '' ) {
if ( empty( $currency_code ) ) {
$currency_code = self::get_currency();
}
$currency = new RGCurrency( $currency_code );
return $currency->to_money( $number );
}
public static function to_number( $text, $currency_code = '' ) {
if ( empty( $currency_code ) ) {
$currency_code = self::get_currency();
}
$currency = new RGCurrency( $currency_code );
return $currency->to_number( $text );
}
public static function get_currency() {
$currency = get_option( 'rg_gforms_currency' );
$currency = empty( $currency ) ? 'USD' : $currency;
return apply_filters( 'gform_currency', $currency );
}
public static function get_simple_captcha() {
_deprecated_function( 'GFCommon::get_simple_captcha', '1.9', 'GFField_CAPTCHA::get_simple_captcha' );
$captcha = new ReallySimpleCaptcha();
$captcha->tmp_dir = RGFormsModel::get_upload_path( 'captcha' ) . '/';
return $captcha;
}
/**
* @deprecated
*
* @param GF_Field_CAPTCH $field
*
* @return mixed
*/
public static function get_captcha( $field ) {
_deprecated_function( 'GFCommon::get_captcha', '1.9', 'GFField_CAPTCHA::get_captcha' );
return $field->get_captcha();
}
/**
* @deprecated
*
* @param $field
* @param $pos
*
* @return mixed
*/
public static function get_math_captcha( $field, $pos ) {
_deprecated_function( 'GFCommon::get_math_captcha', '1.9', 'GFField_CAPTCHA::get_math_captcha' );
return $field->get_math_captcha( $pos );
}
/**
* @param GF_Field $field
* @param $value
* @param string $currency
* @param bool $use_text
* @param string $format
* @param string $media
*
* @return array|mixed|string
*/
public static function get_lead_field_display( $field, $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
if ( ! $field instanceof GF_Field ) {
$field = GF_Fields::create( $field );
}
if ( $field->type == 'post_category' ) {
$value = self::prepare_post_category_value( $value, $field );
}
return $field->get_value_entry_detail( $value, $currency, $use_text, $format, $media );
}
public static function get_product_fields( $form, $lead, $use_choice_text = false, $use_admin_label = false ) {
$products = array();
$product_info = null;
// retrieve static copy of product info (only for 'real' entries)
if ( ! rgempty( 'id', $lead ) ) {
$product_info = gform_get_meta( rgar( $lead, 'id' ), "gform_product_info_{$use_choice_text}_{$use_admin_label}" );
}
// if no static copy, generate from form/lead info
if ( ! $product_info ) {
foreach ( $form['fields'] as $field ) {
$id = $field->id;
$lead_value = RGFormsModel::get_lead_field_value( $lead, $field );
$quantity_field = self::get_product_fields_by_type( $form, array( 'quantity' ), $id );
$quantity = sizeof( $quantity_field ) > 0 && ! RGFormsModel::is_field_hidden( $form, $quantity_field[0], array(), $lead ) ? RGFormsModel::get_lead_field_value( $lead, $quantity_field[0] ) : 1;
switch ( $field->type ) {
case 'product' :
//ignore products that have been hidden by conditional logic
$is_hidden = RGFormsModel::is_field_hidden( $form, $field, array(), $lead );
if ( $is_hidden ) {
break;
}
//if single product, get values from the multiple inputs
if ( is_array( $lead_value ) ) {
$product_quantity = sizeof( $quantity_field ) == 0 && ! $field->disableQuantity ? rgget( $id . '.3', $lead_value ) : $quantity;
if ( empty( $product_quantity ) ) {
break;
}
if ( ! rgar( $products, $id ) ) {
$products[ $id ] = array();
}
$products[ $id ]['name'] = $use_admin_label && ! empty( $field->adminLabel ) ? $field->adminLabel : rgar( $lead_value, $id . '.1' );
$products[ $id ]['price'] = rgar( $lead_value, $id . '.2' );
$products[ $id ]['quantity'] = $product_quantity;
} elseif ( ! empty( $lead_value ) ) {
if ( empty( $quantity ) ) {
break;
}
if ( ! rgar( $products, $id ) ) {
$products[ $id ] = array();
}
$field_label = $use_admin_label && ! empty( $field->adminLabel ) ? $field->adminLabel : $field->label;
if ( $field->inputType == 'price' ) {
$name = $field_label;
$price = $lead_value;
} else {
list( $name, $price ) = explode( '|', $lead_value );
if ( $use_choice_text ) {
$name = RGFormsModel::get_choice_text( $field, $name );
}
/**
* Enables inclusion of the field label or admin label in the product name for choice based Product fields.
*
* @since 1.9.1
*
* @param bool $include_field_label Indicates if the label should be included in the product name. Default is false.
*/
$include_field_label = apply_filters( 'gform_product_info_name_include_field_label', false );
if ( $include_field_label ) {
$name = $field_label . " ({$name})";
}
}
$products[ $id ]['name'] = $name;
$products[ $id ]['price'] = $price;
$products[ $id ]['quantity'] = $quantity;
$products[ $id ]['options'] = array();
}
if ( isset( $products[ $id ] ) ) {
$option_fields = self::get_product_fields_by_type( $form, array( 'option' ), $id );
foreach ( $option_fields as $option_field ) {
$option_value = RGFormsModel::get_lead_field_value( $lead, $option_field );
$option_label = $use_admin_label && ! empty( $option_field->adminLabel ) ? $option_field->adminLabel : $option_field->label;
if ( is_array( $option_value ) ) {
foreach ( $option_value as $value ) {
$option_info = self::get_option_info( $value, $option_field, $use_choice_text );
if ( ! empty( $option_info ) ) {
$products[ $id ]['options'][] = array(
'id' => $option_field->id,
'field_label' => rgobj( $option_field, 'label' ),
'option_name' => rgar( $option_info, 'name' ),
'option_label' => $option_label . ': ' . rgar( $option_info, 'name' ),
'price' => rgar( $option_info, 'price' )
);
}
}
} elseif ( ! empty( $option_value ) ) {
$option_info = self::get_option_info( $option_value, $option_field, $use_choice_text );
$products[ $id ]['options'][] = array(
'id' => $option_field->id,
'field_label' => rgobj( $option_field, 'label' ),
'option_name' => rgar( $option_info, 'name' ),
'option_label' => $option_label . ': ' . rgar( $option_info, 'name' ),
'price' => rgar( $option_info, 'price' )
);
}
}
if ( empty( $products[ $id ]['options'] ) && empty( $products[ $id ]['name'] ) && rgblank( $products[ $id ]['price'] ) ) {
self::log_debug( __METHOD__ . "(): Product field #{$id} has no options, name, or price; removing." );
unset( $products[ $id ] );
}
}
break;
}
}
$shipping_fields = GFAPI::get_fields_by_type( $form, array( 'shipping' ) );
$shipping_price = $shipping_name = $shipping_field_id = '';
if ( ! empty( $shipping_fields ) && ! RGFormsModel::is_field_hidden( $form, $shipping_fields[0], array(), $lead ) ) {
$shipping_price = RGFormsModel::get_lead_field_value( $lead, $shipping_fields[0] );
$shipping_name = $use_admin_label && ! empty( $shipping_fields[0]->adminLabel ) ? $shipping_fields[0]->adminLabel : $shipping_fields[0]->label;
$shipping_field_id = $shipping_fields[0]->id;
if ( $shipping_fields[0]->inputType != 'singleshipping' && ! empty( $shipping_price ) ) {
list( $shipping_method, $shipping_price ) = explode( '|', $shipping_price );
if ( $use_choice_text ) {
$shipping_method = RGFormsModel::get_choice_text( $shipping_fields[0], $shipping_method );
}
$shipping_name .= " ($shipping_method)";
}
}
$shipping_price = self::to_number( $shipping_price, $lead['currency'] );
$product_info = array(
'products' => $products,
'shipping' => array(
'id' => $shipping_field_id,
'name' => $shipping_name,
'price' => $shipping_price
)
);
/**
* Allows the product info used by add-ons and when generating the entry order summary table to be overridden.
*
* @since 1.5.2.8
*
* @param array $product_info The selected products, options, and shipping details for the current entry.
* @param array $form The form object used to generate the current entry.
* @param array $lead The current entry object.
*/
$product_info = gf_apply_filters( array( 'gform_product_info', $form['id'] ), $product_info, $form, $lead );
// save static copy of product info (only for 'real' entries)
if ( ! rgempty( 'id', $lead ) && ! empty( $product_info['products'] ) ) {
gform_update_meta( $lead['id'], "gform_product_info_{$use_choice_text}_{$use_admin_label}", $product_info, $form['id'] );
}
}
return $product_info;
}
public static function get_order_total( $form, $lead ) {
$products = self::get_product_fields( $form, $lead, false );
return self::get_total( $products );
}
public static function get_total( $products ) {
$total = 0;
foreach ( $products['products'] as $product ) {
$price = self::to_number( $product['price'] );
if ( is_array( rgar( $product, 'options' ) ) ) {
foreach ( $product['options'] as $option ) {
$price += self::to_number( $option['price'] );
}
}
$quantity = self::to_number( $product['quantity'], GFCommon::get_currency() );
$subtotal = $quantity * $price;
$total += $subtotal;
}
$total += floatval( $products['shipping']['price'] );
return $total;
}
public static function get_option_info( $value, $option, $use_choice_text ) {
if ( empty( $value ) ) {
return array();
}
list( $name, $price ) = explode( '|', $value );
if ( $use_choice_text ) {
$name = RGFormsModel::get_choice_text( $option, $name );
}
return array( 'name' => $name, 'price' => $price );
}
/**
* Prints or enqueues form scripts and processes shortcodes found in the supplied content.
*
* @since unknown
*
* @param string $content The content to be processed.
*
* @return string
*/
public static function gform_do_shortcode( $content ) {
require_once self::get_base_path() . '/form_display.php';
$is_ajax = false;
$forms = GFFormDisplay::get_embedded_forms( $content, $is_ajax );
foreach ( $forms as $form ) {
/**
* Determine if scripts and stylesheets should be printed or enqueued when processing form shortcodes after headers have been sent.
*
* @since 2.0
*
* @param bool $disable_print_form_script Defaults to false.
* @param array $form The form object for the shortcode being processed.
* @param bool $is_ajax Indicates if ajax was enabled on the shortcode.
*/
$disable_print_form_script = apply_filters( 'gform_disable_print_form_scripts', false, $form, $is_ajax );
if ( headers_sent() && ! $disable_print_form_script ) {
GFFormDisplay::print_form_scripts( $form, $is_ajax );
} else {
GFFormDisplay::enqueue_form_scripts( $form, $is_ajax );
}
}
return do_shortcode( $content );
}
/**
* Determines if the supplied entry is spam.
*
* @since 2.4.17
*
* @param array $entry The entry currently being processed.
* @param array $form The form currently being processed.
*
* @return bool
*/
public static function is_spam_entry( $entry, $form ) {
$form_id = absint( $form['id'] );
$use_cache = class_exists( 'GFFormDisplay' );
if ( $use_cache ) {
$is_spam = rgars( GFFormDisplay::$submission, $form_id . '/is_spam' );
if ( is_bool( $is_spam ) ) {
return $is_spam;
}
}
$is_spam = false;
if ( self::akismet_enabled( $form_id ) ) {
$is_spam = self::is_akismet_spam( $form, $entry );
self::log_debug( __METHOD__ . '(): Result from Akismet: ' . json_encode( $is_spam ) );
}
if ( has_filter( 'gform_entry_is_spam' ) || has_filter( "gform_entry_is_spam_{$form_id}" ) ) {
/**
* Allows submissions to be flagged as spam by custom methods.
*
* @since 1.8.17
* @since 2.4.17 Moved from GFFormDisplay::handle_submission().
*
* @param bool $is_spam Indicates if the submission has been flagged as spam.
* @param array $form The form currently being processed.
* @param array $entry The entry currently being processed.
*/
$is_spam = gf_apply_filters( array( 'gform_entry_is_spam', $form_id ), $is_spam, $form, $entry );
self::log_debug( __METHOD__ . '(): Result from gform_entry_is_spam filter: ' . json_encode( $is_spam ) );
}
$log_is_spam = $is_spam ? 'Yes' : 'No';
self::log_debug( __METHOD__ . "(): Is submission considered spam? {$log_is_spam}." );
if ( $use_cache ) {
GFFormDisplay::$submission[ $form_id ]['is_spam'] = $is_spam;
}
return $is_spam;
}
public static function spam_enabled( $form_id ) {
$spam_enabled = self::akismet_enabled( $form_id ) || has_filter( 'gform_entry_is_spam' ) || has_filter( "gform_entry_is_spam_{$form_id}" );
return $spam_enabled;
}
public static function has_akismet() {
$akismet_exists = function_exists( 'akismet_http_post' ) || method_exists( 'Akismet', 'http_post' );
return $akismet_exists;
}
public static function akismet_enabled( $form_id ) {
if ( ! self::has_akismet() ) {
return false;
}
// if no option is set, leave akismet enabled; otherwise, use option value true/false
$enabled = get_option( 'rg_gforms_enable_akismet' ) === false ? true : get_option( 'rg_gforms_enable_akismet' ) == true;
/**
* Allows the Akismet integration to be enabled or disabled.
*
* @since 1.6.3
* @since 2.4.19 Added the $form_id param.
*
* @param bool $enabled Indicates if the Akismet integration is enabled.
* @param int $form_id The ID of the form being processed.
*/
return gf_apply_filters( array( 'gform_akismet_enabled', $form_id ), $enabled, $form_id );
}
public static function is_akismet_spam( $form, $lead ) {
global $akismet_api_host, $akismet_api_port;
$fields = self::get_akismet_fields( $form, $lead );
// Submitting info to Akismet
if ( defined( 'AKISMET_VERSION' ) && AKISMET_VERSION < 3.0 ) {
//Akismet versions before 3.0
$response = akismet_http_post( $fields, $akismet_api_host, '/1.1/comment-check', $akismet_api_port );
} else {
$response = Akismet::http_post( $fields, 'comment-check' );
}
$is_spam = trim( rgar( $response, 1 ) ) == 'true';
return $is_spam;
}
public static function mark_akismet_spam( $form, $lead, $is_spam ) {
global $akismet_api_host, $akismet_api_port;
$as = $is_spam ? 'spam' : 'ham';
$fields = self::get_akismet_fields( $form, $lead, $as );
// Submitting info to Akismet
if ( defined( 'AKISMET_VERSION' ) && AKISMET_VERSION < 3.0 ) {
//Akismet versions before 3.0
akismet_http_post( $fields, $akismet_api_host, '/1.1/submit-' . $as, $akismet_api_port );
} else {
Akismet::http_post( $fields, 'submit-' . $as );
}
}
/**
* Prepares a query string containing the data to be sent to Akismet.
*
* @since unknown
* @since 2.4.19 Added the $action param.
*
* @param array $form The form which created the entry.
* @param array $entry The entry being processed.
* @param string $action The action triggering the Akismet request: submit, spam, or ham.
*
* @return string
*/
private static function get_akismet_fields( $form, $entry, $action = 'submit' ) {
$is_form_editor = GFCommon::is_form_editor();
$is_entry_detail = GFCommon::is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
// Gathering Akismet information
$akismet_fields = array();
$akismet_fields['comment_type'] = 'gravity_form';
$akismet_fields['comment_author'] = self::get_akismet_field( 'name', $form, $entry );
$akismet_fields['comment_author_email'] = self::get_akismet_field( 'email', $form, $entry );
$akismet_fields['comment_author_url'] = self::get_akismet_field( 'website', $form, $entry );
$akismet_fields['comment_content'] = self::get_akismet_field( 'textarea', $form, $entry );
$akismet_fields['contact_form_subject'] = $form['title'];
$akismet_fields['comment_author_IP'] = rgar( $entry, 'ip' );
$akismet_fields['permalink'] = rgar( $entry, 'source_url' );
$akismet_fields['user_ip'] = preg_replace( '/[^0-9., ]/', '', rgar( $entry, 'ip' ) );
$akismet_fields['user_agent'] = rgar( $entry, 'user_agent' );
$akismet_fields['referrer'] = $is_admin ? '' : rgar( $_SERVER, 'HTTP_REFERER' );
$akismet_fields['blog'] = get_option( 'home' );
/**
* Allows the data to be sent to Akismet to be overridden.
*
* @since unknown
* @since 2.4.19 Added the $action param.
*
* @param array $akismet_fields The data to be sent to Akismet.
* @param array $form The form which created the entry.
* @param array $entry The entry being processed.
* @param string $action The action triggering the Akismet request: submit, spam, or ham.
*/
$akismet_fields = gf_apply_filters( array( 'gform_akismet_fields', $form['id'] ), $akismet_fields, $form, $entry, $action );
return http_build_query( $akismet_fields );
}
private static function get_akismet_field( $field_type, $form, $lead ) {
$fields = GFAPI::get_fields_by_type( $form, array( $field_type ) );
if ( empty( $fields ) ) {
return '';
}
$value = RGFormsModel::get_lead_field_value( $lead, $fields[0] );
switch ( $field_type ) {
case 'name' :
$value = GFCommon::get_lead_field_display( $fields[0], $value );
break;
}
return $value;
}
/**
* Get the placeholder to use for the radio button field other choice.
*
* @param null|GF_Field_Radio $field Null or the Field currently being prepared for display or being validated.
*
* @return string
*/
public static function get_other_choice_value( $field = null ) {
$placeholder = esc_html__( 'Other', 'gravityforms' );
/**
* Filter the default placeholder for the radio button field other choice.
*
* @since 2.1.1.6 Added the $field parameter.
* @since Unknown
*
* @param string $placeholder The placeholder to be filtered. Defaults to "Other".
* @param null|GF_Field_Radio $field Null or the Field currently being prepared for display or being validated.
*/
$placeholder = apply_filters( 'gform_other_choice_value', $placeholder, $field );
return $placeholder;
}
public static function get_browser_class() {
global $is_lynx, $is_gecko, $is_IE, $is_opera, $is_NS4, $is_safari, $is_chrome, $is_iphone, $post;
$classes = array();
//adding browser related class
if ( $is_lynx ) {
$classes[] = 'gf_browser_lynx';
} else if ( $is_gecko ) {
$classes[] = 'gf_browser_gecko';
} else if ( $is_opera ) {
$classes[] = 'gf_browser_opera';
} else if ( $is_NS4 ) {
$classes[] = 'gf_browser_ns4';
} else if ( $is_safari ) {
$classes[] = 'gf_browser_safari';
} else if ( $is_chrome ) {
$classes[] = 'gf_browser_chrome';
} else if ( $is_IE ) {
$classes[] = 'gf_browser_ie';
} else {
$classes[] = 'gf_browser_unknown';
}
//adding IE version
if ( $is_IE ) {
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 6' ) !== false ) {
$classes[] = 'gf_browser_ie6';
} else if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 7' ) !== false ) {
$classes[] = 'gf_browser_ie7';
}
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 8' ) !== false ) {
$classes[] = 'gf_browser_ie8';
}
if ( strpos( $_SERVER['HTTP_USER_AGENT'], 'MSIE 9' ) !== false ) {
$classes[] = 'gf_browser_ie9';
}
}
if ( $is_iphone ) {
$classes[] = 'gf_browser_iphone';
}
return implode( ' ', $classes );
}
public static function create_post( $form, &$lead ) {
$disable_post = gf_apply_filters( array( 'gform_disable_post_creation', $form['id'] ), false, $form, $lead );
$post_id = 0;
if ( ! $disable_post ) {
//creates post if the form has any post fields
$post_id = RGFormsModel::create_post( $form, $lead );
}
return $post_id;
}
public static function evaluate_conditional_logic( $logic, $form, $lead ) {
if ( ! $logic || ! is_array( rgar( $logic, 'rules' ) ) ) {
return true;
}
$entry_meta_keys = array_keys( GFFormsModel::get_entry_meta( $form['id'] ) );
$match_count = 0;
if ( is_array( $logic['rules'] ) ) {
foreach ( $logic['rules'] as $rule ) {
if ( in_array( $rule['fieldId'], $entry_meta_keys ) ) {
$is_value_match = GFFormsModel::is_value_match( rgar( $lead, $rule['fieldId'] ), $rule['value'], $rule['operator'], null, $rule, $form );
} else {
$source_field = GFFormsModel::get_field( $form, $rule['fieldId'] );
$field_value = empty( $lead ) ? GFFormsModel::get_field_value( $source_field, array() ) : GFFormsModel::get_lead_field_value( $lead, $source_field );
$is_value_match = GFFormsModel::is_value_match( $field_value, $rule['value'], $rule['operator'], $source_field, $rule, $form );
}
if ( $is_value_match ) {
$match_count ++;
}
}
}
$do_action = ( $logic['logicType'] == 'all' && $match_count == sizeof( $logic['rules'] ) ) || ( $logic['logicType'] == 'any' && $match_count > 0 );
return $do_action;
}
public static function get_card_types() {
$cards = array(
array(
'name' => 'American Express',
'slug' => 'amex',
'lengths' => '15',
'prefixes' => '34,37',
'checksum' => true,
),
array(
'name' => 'Discover',
'slug' => 'discover',
'lengths' => '16',
'prefixes' => '6011,622,64,65',
'checksum' => true,
),
array(
'name' => 'MasterCard',
'slug' => 'mastercard',
'lengths' => '16',
'prefixes' => '51,52,53,54,55,22,23,24,25,26,270,271,272',
'checksum' => true,
),
array(
'name' => 'Visa',
'slug' => 'visa',
'lengths' => '13,16',
'prefixes' => '4,417500,4917,4913,4508,4844',
'checksum' => true,
),
array(
'name' => 'JCB',
'slug' => 'jcb',
'lengths' => '16',
'prefixes' => '35',
'checksum' => true,
),
array(
'name' => 'Maestro',
'slug' => 'maestro',
'lengths' => '12,13,14,15,16,18,19',
'prefixes' => '5018,5020,5038,6304,6759,6761',
'checksum' => true,
),
);
$cards = apply_filters( 'gform_creditcard_types', $cards );
return $cards;
}
public static function get_card_type( $number ) {
//removing spaces from number
$number = str_replace( ' ', '', $number );
if ( empty( $number ) ) {
return false;
}
$cards = self::get_card_types();
$matched_card = false;
foreach ( $cards as $card ) {
if ( self::matches_card_type( $number, $card ) ) {
$matched_card = $card;
break;
}
}
if ( $matched_card && $matched_card['checksum'] && ! self::is_valid_card_checksum( $number ) ) {
$matched_card = false;
}
return $matched_card ? $matched_card : false;
}
private static function matches_card_type( $number, $card ) {
//checking prefix
$prefixes = explode( ',', $card['prefixes'] );
$matches_prefix = false;
foreach ( $prefixes as $prefix ) {
if ( preg_match( "|^{$prefix}|", $number ) ) {
$matches_prefix = true;
break;
}
}
//checking length
$lengths = explode( ',', $card['lengths'] );
$matches_length = false;
foreach ( $lengths as $length ) {
if ( strlen( $number ) == absint( $length ) ) {
$matches_length = true;
break;
}
}
return $matches_prefix && $matches_length;
}
private static function is_valid_card_checksum( $number ) {
$checksum = 0;
$num = 0;
$multiplier = 1;
// Process each character starting at the right
for ( $i = strlen( $number ) - 1; $i >= 0; $i -- ) {
//Multiply current digit by multiplier (1 or 2)
$num = $number[ $i ] * $multiplier;
// If the result is in greater than 9, add 1 to the checksum total
if ( $num >= 10 ) {
$checksum ++;
$num -= 10;
}
//Update checksum
$checksum += $num;
//Update multiplier
$multiplier = $multiplier == 1 ? 2 : 1;
}
return $checksum % 10 == 0;
}
public static function is_wp_version( $min_version ) {
return ! version_compare( get_bloginfo( 'version' ), "{$min_version}.dev1", '<' );
}
/**
* Checks if the logging plugin is active.
*
* @since 2.2
* @access public
*
* @used-by GFSettings::gravityforms_settings_page()
*
* @return bool If the logging plugin is active.
*/
public static function is_logging_plugin_active() {
if ( ! function_exists( 'is_plugin_active' ) ) {
require_once ABSPATH . 'wp-admin/includes/plugin.php';
}
// In some scenarios, is_plugin_active() will return true when plugin file has been manually deleted.
return is_plugin_active( 'gravityformslogging/logging.php' ) && file_exists( trailingslashit( WP_PLUGIN_DIR ) . 'gravityformslogging/logging.php' );
}
public static function add_categories_as_choices( $field, $value ) {
$choices = $inputs = array();
$is_post = isset( $_POST['gform_submit'] );
$has_placeholder = $field->categoryInitialItemEnabled && RGFormsModel::get_input_type( $field ) == 'select';
if ( $has_placeholder ) {
$choices[] = array( 'text' => $field->categoryInitialItem, 'value' => '', 'isSelected' => true );
}
$display_all = $field->displayAllCategories;
$args = array( 'hide_empty' => false, 'orderby' => 'name', 'taxonomy' => 'category' );
if ( ! $display_all ) {
foreach ( $field->choices as $field_choice_to_include ) {
$args['include'][] = $field_choice_to_include['value'];
}
}
$args = gf_apply_filters( array( 'gform_post_category_args', $field->id ), $args, $field );
$terms = get_terms( $args['taxonomy'], $args );
$terms_copy = unserialize( serialize( $terms ) ); // deep copy the terms to avoid repeating GFCategoryWalker on previously cached terms.
$walker = new GFCategoryWalker();
$categories = $walker->walk( $terms_copy, 0, array( 0 ) ); // 3rd parameter prevents notices triggered by $walker::display_element() function which checks $args[0]
foreach ( $categories as $category ) {
if ( $display_all ) {
$selected = $value == $category->term_id ||
(
empty( $value ) &&
get_option( 'default_category' ) == $category->term_id &&
RGFormsModel::get_input_type( $field ) == 'select' && // only preselect default category on select fields
! $is_post &&
! $has_placeholder
);
$choices[] = array(
'text' => $category->name,
'value' => $category->term_id,
'isSelected' => $selected
);
} else {
foreach ( $field->choices as $field_choice ) {
if ( $field_choice['value'] == $category->term_id ) {
$choices[] = array( 'text' => $category->name, 'value' => $category->term_id );
break;
}
}
}
}
if ( empty( $choices ) ) {
$choices[] = array( 'text' => 'You must select at least one category.', 'value' => '' );
}
$field->choices = $choices;
$is_form_editor = GFCommon::is_form_editor();
$is_entry_detail = GFCommon::is_entry_detail();
$is_admin = $is_form_editor || $is_entry_detail;
$form_id = $is_admin ? rgget( 'id' ) : $field->formId;
/**
* Allows you to filter (modify) the post category choices when using post fields.
*
* @param GF_Field $field The category choices field.
* @param int $form_id The current form ID.
*/
$field->choices = gf_apply_filters( array(
'gform_post_category_choices',
$form_id,
$field->id
), $field->choices, $field, $form_id );
if ( $field->get_input_type() == 'checkbox' ) {
$choice_number = 1;
foreach ( $field->choices as $choice ) {
if ( $choice_number % 10 == 0 ) {
//hack to skip numbers ending in 0. so that 5.1 doesn't conflict with 5.10
$choice_number ++;
}
$input_id = $field->id . '.' . $choice_number;
$inputs[] = array( 'id' => $input_id, 'label' => $choice['text'], 'name' => '' );
$choice_number ++;
}
$field->inputs = $inputs;
}
return $field;
}
public static function prepare_post_category_value( $value, $field, $mode = 'entry_detail' ) {
if ( ! is_array( $value ) ) {
$value = explode( ',', $value );
}
$cat_names = array();
$cat_ids = array();
foreach ( $value as $cat_string ) {
$ary = explode( ':', $cat_string );
$cat_name = count( $ary ) > 0 ? $ary[0] : '';
$cat_id = count( $ary ) > 1 ? $ary[1] : $ary[0];
if ( ! empty( $cat_name ) ) {
$cat_names[] = $cat_name;
}
if ( ! empty( $cat_id ) ) {
$cat_ids[] = $cat_id;
}
}
sort( $cat_names );
switch ( $mode ) {
case 'entry_list':
$value = self::implode_non_blank( ', ', $cat_names );
break;
case 'entry_detail':
$value = RGFormsModel::get_input_type( $field ) == 'checkbox' ? $cat_names : self::implode_non_blank( ', ', $cat_names );
break;
case 'conditional_logic':
$value = array_values( $cat_ids );
break;
}
return $value;
}
public static function calculate( $field, $form, $lead ) {
$number_format = $field->numberFormat;
if ( empty( $number_format ) ) {
$currency = RGCurrency::get_currency( rgar( $lead, 'currency' ) );
$number_format = self::is_currency_decimal_dot( $currency ) ? 'decimal_dot' : 'decimal_comma';
}
$formula = (string) apply_filters( 'gform_calculation_formula', $field->calculationFormula, $field, $form, $lead );
// replace multiple spaces and new lines with single space
// @props: http://stackoverflow.com/questions/3760816/remove-new-lines-from-string
$formula = trim( preg_replace( '/\s+/', ' ', $formula ) );
preg_match_all( '/{[^{]*?:(\d+(\.\d+)?)(:(.*?))?}/mi', $formula, $matches, PREG_SET_ORDER );
if ( is_array( $matches ) ) {
foreach ( $matches as $match ) {
list( $text, $input_id ) = $match;
$value = self::get_calculation_value( $input_id, $form, $lead, $number_format );
$value = apply_filters( 'gform_merge_tag_value_pre_calculation', $value, $input_id, rgar( $match, 4 ), $field, $form, $lead );
$formula = str_replace( $text, $value, $formula );
}
}
$result = false;
if ( preg_match( '/^[0-9 -\/*\(\)]+$/', $formula ) ) {
$prev_reporting_level = error_reporting( 0 );
try {
$result = eval( "return {$formula};" );
} catch ( ParseError $e ) {
GFCommon::log_debug( __METHOD__ . sprintf( '(): Formula could not be parsed: "%s".', $e->getMessage() ) );
$result = 0;
}
error_reporting( $prev_reporting_level );
}
$result = apply_filters( 'gform_calculation_result', $result, $formula, $field, $form, $lead );
if ( ! $result || ! is_numeric( $result ) || ! is_finite( $result ) ) {
GFCommon::log_debug( __METHOD__ . '(): No result or non-numeric result. Returning zero instead.' );
$result = 0;
}
return $result;
}
public static function round_number( $number, $rounding ) {
if ( is_numeric( $rounding ) && $rounding >= 0 ) {
$number = round( $number, $rounding );
}
return $number;
}
public static function get_calculation_value( $field_id, $form, $lead, $number_format = '' ) {
$filters = array( 'price', 'value', '' );
$value = false;
$field = RGFormsModel::get_field( $form, $field_id );
if ( empty( $field ) ) {
//return 0 if fields does not belong to form
return 0;
}
$is_pricing_field = $field ? self::has_currency_value( $field ) : false;
if ( $field && $field->numberFormat ) {
$number_format = $field->numberFormat;
} elseif ( empty( $number_format ) ) {
$number_format = 'decimal_dot';
}
foreach ( $filters as $filter ) {
if ( is_numeric( $value ) ) {
//value found, exit loop
break;
}
$replaced_value = GFCommon::replace_variables( "{:{$field_id}:$filter}", $form, $lead );
if ( $is_pricing_field ) {
$value = self::to_number( $replaced_value );
} else {
$value = self::clean_number( $replaced_value, $number_format );
}
}
if ( ! $value || ! is_numeric( $value ) ) {
GFCommon::log_debug( "GFCommon::get_calculation_value(): No value or non-numeric value available for field #{$field_id}. Returning zero instead." );
$value = 0;
}
return $value;
}
public static function has_currency_value( $field ) {
$has_currency = self::is_pricing_field( $field->type ) || rgobj( $field, 'numberFormat' ) == 'currency';
return $has_currency;
}
public static function conditional_shortcode( $attributes, $content = null ) {
extract(
shortcode_atts(
array(
'merge_tag' => '',
'condition' => '',
'value' => '',
), $attributes, 'gravityforms_conditional'
)
);
return RGFormsModel::matches_operation( $merge_tag, $value, $condition ) ? do_shortcode( $content ) : '';
}
public static function is_valid_for_calcuation( $field ) {
$supported_input_types = array(
'text',
'select',
'number',
'checkbox',
'radio',
'hidden',
'singleproduct',
'price',
'hiddenproduct',
'calculation',
'singleshipping'
);
$unsupported_field_types = array( 'category' );
$input_type = RGFormsModel::get_input_type( $field );
return in_array( $input_type, $supported_input_types ) && ! in_array( $input_type, $unsupported_field_types );
}
public static function log_error( $message ) {
if ( class_exists( 'GFLogging' ) ) {
GFLogging::include_logger();
GFLogging::log_message( 'gravityforms', $message, KLogger::ERROR );
}
}
public static function log_debug( $message ) {
if ( class_exists( 'GFLogging' ) ) {
GFLogging::include_logger();
GFLogging::log_message( 'gravityforms', $message, KLogger::DEBUG );
}
}
/**
* Log the remote request response.
*
* @since 2.2.2.1
*
* @param WP_Error|array $response The remote request response or WP_Error on failure.
*/
public static function log_remote_response( $response ) {
if ( is_wp_error( $response ) || isset( $_GET['gform_debug'] ) ) {
self::log_error( __METHOD__ . '(): ' . print_r( $response, 1 ) );
} else {
self::log_debug( sprintf( '%s(): code: %s; body: %s', __METHOD__, wp_remote_retrieve_response_code( $response ), wp_remote_retrieve_body( $response ) ) );
}
}
public static function echo_if( $condition, $text ) {
_deprecated_function( 'GFCommon::echo_if() is deprecated', '1.9.9', 'Use checked() or selected() instead.' );
switch ( $text ) {
case 'checked':
$text = 'checked="checked"';
break;
case 'selected':
$text = 'selected="selected"';
}
echo $condition ? $text : '';
}
/**
* Outputs the gf_global and returns either the gf_global var declaration or the array containing the gf_global values.
*
*
* @since 2.4.7 Added the $return_array parameter
* @since unknown
*
* @param bool $echo If true, outputs the inline gf_global var declaration.
* @param bool $return_array If true, returns the array containing the gf_global values.
*
* @return array|string
*/
public static function gf_global( $echo = true, $return_array = false ) {
$gf_global = array();
$gf_global['gf_currency_config'] = RGCurrency::get_currency( GFCommon::get_currency() );
$gf_global['base_url'] = GFCommon::get_base_url();
$gf_global['number_formats'] = array();
$gf_global['spinnerUrl'] = GFCommon::get_base_url() . '/images/spinner.gif';
$gf_global_json = 'var gf_global = ' . json_encode( $gf_global ) . ';';
if ( ! $echo ) {
return $return_array ? $gf_global : $gf_global_json;
}
echo $gf_global_json;
}
public static function gf_vars( $echo = true ) {
$gf_vars = array();
$gf_vars['active'] = esc_attr__( 'Active', 'gravityforms' );
$gf_vars['inactive'] = esc_attr__( 'Inactive', 'gravityforms' );
$gf_vars['save'] = esc_html__( 'Save', 'gravityforms' );
$gf_vars['update'] = esc_html__( 'Update', 'gravityforms' );
$gf_vars['previousLabel'] = esc_html__( 'Previous', 'gravityforms' );
$gf_vars['selectFormat'] = esc_html__( 'Select a format', 'gravityforms' );
$gf_vars['editToViewAll'] = esc_html__( '5 of %d items shown. Edit field to view all', 'gravityforms' );
$gf_vars['enterValue'] = esc_html__( 'Enter a value', 'gravityforms' );
$gf_vars['formTitle'] = esc_html__( 'Untitled Form', 'gravityforms' );
$gf_vars['formDescription'] = esc_html__( 'We would love to hear from you! Please fill out this form and we will get in touch with you shortly.', 'gravityforms' );
$gf_vars['formConfirmationMessage'] = esc_html__( 'Thanks for contacting us! We will get in touch with you shortly.', 'gravityforms' );
$gf_vars['buttonText'] = esc_html__( 'Submit', 'gravityforms' );
$gf_vars['loading'] = esc_html__( 'Loading...', 'gravityforms' );
$gf_vars['thisFieldIf'] = esc_html__( 'this field if', 'gravityforms' );
$gf_vars['thisSectionIf'] = esc_html__( 'this section if', 'gravityforms' );
$gf_vars['thisPage'] = esc_html__( 'this page', 'gravityforms' );
$gf_vars['thisFormButton'] = esc_html__( 'this form button if', 'gravityforms' );
$gf_vars['show'] = esc_html__( 'Show', 'gravityforms' );
$gf_vars['hide'] = esc_html__( 'Hide', 'gravityforms' );
$gf_vars['all'] = esc_html( _x( 'All', 'Conditional Logic', 'gravityforms' ) );
$gf_vars['any'] = esc_html( _x( 'Any', 'Conditional Logic', 'gravityforms' ) );
$gf_vars['ofTheFollowingMatch'] = esc_html__( 'of the following match:', 'gravityforms' );
$gf_vars['is'] = esc_html__( 'is', 'gravityforms' );
$gf_vars['isNot'] = esc_html__( 'is not', 'gravityforms' );
$gf_vars['greaterThan'] = esc_html__( 'greater than', 'gravityforms' );
$gf_vars['lessThan'] = esc_html__( 'less than', 'gravityforms' );
$gf_vars['contains'] = esc_html__( 'contains', 'gravityforms' );
$gf_vars['startsWith'] = esc_html__( 'starts with', 'gravityforms' );
$gf_vars['endsWith'] = esc_html__( 'ends with', 'gravityforms' );
$gf_vars['emptyChoice'] = wp_strip_all_tags( __( 'Empty (no choices selected)', 'gravityforms' ) );
$gf_vars['thisConfirmation'] = esc_html__( 'Use this confirmation if', 'gravityforms' );
$gf_vars['thisNotification'] = esc_html__( 'Send this notification if', 'gravityforms' );
$gf_vars['confirmationSave'] = esc_html__( 'Save', 'gravityforms' );
$gf_vars['confirmationSaving'] = esc_html__( 'Saving...', 'gravityforms' );
$gf_vars['confirmationAreYouSure'] = __( 'Are you sure you wish to cancel these changes?', 'gravityforms' );
$gf_vars['confirmationIssueSaving'] = __( 'There was an issue saving this confirmation.', 'gravityforms' );
$gf_vars['confirmationConfirmDelete'] = __( 'Are you sure you wish to delete this confirmation?', 'gravityforms' );
$gf_vars['confirmationIssueDeleting'] = __( 'There was an issue deleting this confirmation.', 'gravityforms' );
$gf_vars['confirmationConfirmDiscard'] = __( 'There are unsaved changes to the current confirmation. Would you like to discard these changes?', 'gravityforms' );
$gf_vars['confirmationDefaultName'] = __( 'Untitled Confirmation', 'gravityforms' );
$gf_vars['confirmationDefaultMessage'] = __( 'Thanks for contacting us! We will get in touch with you shortly.', 'gravityforms' );
$gf_vars['confirmationInvalidPageSelection'] = __( 'Please select a page.', 'gravityforms' );
$gf_vars['confirmationInvalidRedirect'] = __( 'Please enter a URL.', 'gravityforms' );
$gf_vars['confirmationInvalidName'] = __( 'Please enter a confirmation name.', 'gravityforms' );
$gf_vars['confirmationDeleteField'] = __( "Warning! Deleting this field will also delete all entry data associated with it. 'Cancel' to stop. 'OK' to delete.", 'gravityforms' );
$gf_vars['conditionalLogicDependency'] = __( "Warning! This form contains conditional logic dependent upon this field. Deleting this field will deactivate those conditional logic rules and also delete all entry data associated with the field. 'OK' to delete, 'Cancel' to abort.", 'gravityforms' );
$gf_vars['conditionalLogicDependencyChoice'] = __( "This form contains conditional logic dependent upon this choice. Are you sure you want to delete this choice? 'OK' to delete, 'Cancel' to abort.", 'gravityforms' );
$gf_vars['conditionalLogicDependencyChoiceEdit'] = __( "This form contains conditional logic dependent upon this choice. Are you sure you want to modify this choice? 'OK' to delete, 'Cancel' to abort.", 'gravityforms' );
$gf_vars['conditionalLogicDependencyAdminOnly'] = __( "This form contains conditional logic dependent upon this field. Are you sure you want to mark this field as Admin Only? 'OK' to confirm, 'Cancel' to abort.", 'gravityforms' );
$gf_vars['mergeTagsTooltip'] = '