class ET_Builder_Module_Contact_Form extends ET_Builder_Module_Type_WithSpamProtection {
$this->name = esc_html__( 'Contact Form', 'et_builder' );
$this->plural = esc_html__( 'Contact Forms', 'et_builder' );
$this->slug = 'et_pb_contact_form';
$this->vb_support = 'on';
$this->child_slug = 'et_pb_contact_field';
$this->child_item_text = esc_html__( 'Field', 'et_builder' );
$this->main_css_element = '%%order_class%%.et_pb_contact_form_container';
$this->settings_modal_toggles = array(
'main_content' => et_builder_i18n( 'Text' ),
'email' => esc_html__( 'Email', 'et_builder' ),
'elements' => et_builder_i18n( 'Elements' ),
'redirect' => esc_html__( 'Redirect', 'et_builder' ),
'spam' => esc_html__( 'Spam Protection', 'et_builder' ),
$this->advanced_fields = array(
'border_radii' => sprintf( '%1$s .input, %1$s .input[type="checkbox"] + label i, %1$s .input[type="radio"] + label i', $this->main_css_element ),
'border_styles' => sprintf( '%1$s .input, %1$s .input[type="checkbox"] + label i, %1$s .input[type="radio"] + label i', $this->main_css_element ),
'important' => 'plugin_only',
'label_prefix' => esc_html__( 'Inputs', 'et_builder' ),
'label' => et_builder_i18n( 'Title' ),
'main' => "{$this->main_css_element} h1, {$this->main_css_element} h2.et_pb_contact_main_title, {$this->main_css_element} h3.et_pb_contact_main_title, {$this->main_css_element} h4.et_pb_contact_main_title, {$this->main_css_element} h5.et_pb_contact_main_title, {$this->main_css_element} h6.et_pb_contact_main_title",
'label' => esc_html__( 'Captcha', 'et_builder' ),
'main' => "{$this->main_css_element} .et_pb_contact_right p",
'hide_text_align' => true,
'%%order_class%% .et_pb_contact_field input',
'%%order_class%% .et_pb_contact_field select',
'%%order_class%% .et_pb_contact_field textarea',
'%%order_class%% .et_pb_contact_field .et_pb_contact_field_options_list label > i',
'%%order_class%% input.et_pb_contact_captcha',
'label' => et_builder_i18n( 'Button' ),
'main' => "{$this->main_css_element}.et_pb_module .et_pb_button",
'limited_main' => "{$this->main_css_element}.et_pb_module .et_pb_button",
'main' => '%%order_class%% .et_pb_contact_submit',
'margin_padding' => array(
'margin_padding' => array(
'important' => array( 'custom_margin' ), // needed to overwrite last module margin-bottom styling
'module_alignment' => '%%order_class%%.et_pb_contact_form_container.et_pb_module',
'text_orientation' => '%%order_class%% input, %%order_class%% textarea, %%order_class%% label',
'text_shadow' => '%%order_class%%, %%order_class%% input, %%order_class%% textarea, %%order_class%% label, %%order_class%% select',
'label' => esc_html__( 'Fields', 'et_builder' ),
'main' => '%%order_class%% .input',
'background_color' => '%%order_class%% .input, %%order_class%% .input[type="checkbox"] + label i, %%order_class%% .input[type="radio"] + label i',
'background_color_hover' => '%%order_class%% .input:hover, %%order_class%% .input[type="checkbox"]:hover + label i, %%order_class%% .input[type="radio"]:hover + label i',
'focus_background_color' => '%%order_class%% .input:focus, %%order_class%% .input[type="checkbox"]:active + label i, %%order_class%% .input[type="radio"]:active + label i',
'focus_background_color_hover' => '%%order_class%% .input:focus:hover, %%order_class%% .input[type="checkbox"]:active:hover + label i, %%order_class%% .input[type="radio"]:active:hover + label i',
'placeholder_focus' => '%%order_class%% p .input:focus::-webkit-input-placeholder, %%order_class%% p .input:focus::-moz-placeholder, %%order_class%% p .input:focus:-ms-input-placeholder, %%order_class%% p textarea:focus::-webkit-input-placeholder, %%order_class%% p textarea:focus::-moz-placeholder, %%order_class%% p textarea:focus:-ms-input-placeholder',
'padding' => '%%order_class%% .et_pb_contact_field .input',
'margin' => '%%order_class%% .et_pb_contact_field',
'form_text_color' => '%%order_class%% .input, %%order_class%% .input[type="checkbox"] + label, %%order_class%% .input[type="radio"] + label, %%order_class%% .input[type="checkbox"]:checked + label i:before',
'form_text_color_hover' => '%%order_class%% .input:hover, %%order_class%% .input[type="checkbox"]:hover + label, %%order_class%% .input[type="radio"]:hover + label, %%order_class%% .input[type="checkbox"]:checked:hover + label i:before',
'focus_text_color' => '%%order_class%% .input:focus, %%order_class%% .input[type="checkbox"]:active + label, %%order_class%% .input[type="radio"]:active + label, %%order_class%% .input[type="checkbox"]:checked:active + label i:before',
'focus_text_color_hover' => '%%order_class%% .input:focus:hover, %%order_class%% .input[type="checkbox"]:active:hover + label, %%order_class%% .input[type="radio"]:active:hover + label, %%order_class%% .input[type="checkbox"]:checked:active:hover + label i:before',
'border_styles' => false,
"{$this->main_css_element} .input",
"{$this->main_css_element} .input::placeholder",
"{$this->main_css_element} .input::-webkit-input-placeholder",
"{$this->main_css_element} .input::-moz-placeholder",
"{$this->main_css_element} .input:-ms-input-placeholder",
"{$this->main_css_element} .input[type=checkbox] + label",
"{$this->main_css_element} .input[type=radio] + label",
"{$this->main_css_element} .input:hover",
"{$this->main_css_element} .input:hover::placeholder",
"{$this->main_css_element} .input:hover::-webkit-input-placeholder",
"{$this->main_css_element} .input:hover::-moz-placeholder",
"{$this->main_css_element} .input:hover:-ms-input-placeholder",
"{$this->main_css_element} .input[type=checkbox]:hover + label",
"{$this->main_css_element} .input[type=radio]:hover + label",
'margin_padding' => array(
'main' => '%%order_class%% .input',
'padding' => '%%order_class%% .et_pb_contact_field .input',
'margin' => '%%order_class%% .et_pb_contact_field',
$this->custom_css_fields = array(
'contact_title' => array(
'label' => esc_html__( 'Contact Title', 'et_builder' ),
'selector' => '.et_pb_contact_main_title',
'contact_button' => array(
'label' => esc_html__( 'Contact Button', 'et_builder' ),
'selector' => '.et_pb_contact_form_container .et_contact_bottom_container .et_pb_contact_submit.et_pb_button',
'no_space_before_selector' => true,
'contact_fields' => array(
'label' => esc_html__( 'Form Fields', 'et_builder' ),
'label' => esc_html__( 'Message Field', 'et_builder' ),
'selector' => 'textarea.et_pb_contact_message',
'captcha_field' => array(
'label' => esc_html__( 'Captcha Field', 'et_builder' ),
'selector' => 'input.et_pb_contact_captcha',
'captcha_label' => array(
'label' => esc_html__( 'Captcha Text', 'et_builder' ),
'selector' => '.et_pb_contact_right p',
$this->help_videos = array(
'name' => esc_html__( 'An introduction to the Contact Form module', 'et_builder' ),
* Get form map containing essential info (form number, field id/type/required) based on
* et_pb_contact_field's shortcode layout
* @param string $content_shortcode
* @param int $contact_form_number
* @param array $hidden_form_fields
* @type int $form_number Contact form number.
* @type string[] $fields {
* @type string $field_type Field type
* @type string $field_id Field id
* @type string $required_mark Required field status. Accepts 'on', 'off'.
function get_form_map( $content_shortcode = '', $contact_form_number = 0, $hidden_form_fields = array() ) {
$pattern = get_shortcode_regex( array( 'et_pb_contact_field' ) );
'form_number' => (int) $contact_form_number,
preg_match_all( "/$pattern/", $content_shortcode, $contact_fields, PREG_SET_ORDER );
foreach ( $contact_fields as $contact_field ) {
$contact_field_attrs = shortcode_parse_atts( $contact_field[3] );
$field_id = strtolower( self::$_->array_get( $contact_field_attrs, 'field_id' ) );
$conditional_logic = self::$_->array_get( $contact_field_attrs, 'conditional_logic', 'off' );
// Only allow to disable fields for which conditional logic has been enabled
if ( 'on' === $conditional_logic && in_array( $field_id, $hidden_form_fields ) ) {
$map['fields'][] = array(
'field_type' => self::$_->array_get( $contact_field_attrs, 'field_type', 'input' ),
'required_mark' => self::$_->array_get( $contact_field_attrs, 'required_mark', 'on' ),
self::_get_spam_provider_fields(),
'label' => esc_html__( 'Use Basic Captcha', 'et_builder' ),
'type' => 'yes_no_button',
'option_category' => 'configuration',
'on' => et_builder_i18n( 'Yes' ),
'off' => et_builder_i18n( 'No' ),
'description' => esc_html__( 'Turn the captcha on or off using this option.', 'et_builder' ),
'default_on_front' => 'on',
'use_spam_service' => 'off',
'label' => esc_html__( 'Email Address', 'et_builder' ),
'option_category' => 'basic_option',
'description' => et_get_safe_localization(
__( 'Input the email address where messages should be sent.<br /><br /> Note: email delivery and spam prevention are complex processes. We recommend using a delivery service such as <a href="%1$s">Mandrill</a>, <a href="%2$s">SendGrid</a>, or other similar service to ensure the deliverability of messages that are submitted through this form', 'et_builder' ),
'toggle_slug' => 'email',
'label' => et_builder_i18n( 'Title' ),
'option_category' => 'basic_option',
'description' => esc_html__( 'Define a title for your contact form.', 'et_builder' ),
'toggle_slug' => 'main_content',
'dynamic_content' => 'text',
'mobile_options' => true,
'custom_message' => array(
'label' => esc_html__( 'Message Pattern', 'et_builder' ),
'option_category' => 'configuration',
'description' => et_get_safe_localization( __( 'Here you can define the custom pattern for the email Message. Fields should be included in following format - <strong>%%field_id%%</strong>. For example if you want to include the field with id = <strong>phone</strong> and field with id = <strong>message</strong>, then you can use the following pattern: <strong>My message is %%message%% and phone number is %%phone%%</strong>. Leave blank for default.', 'et_builder' ) ),
'toggle_slug' => 'email',
'label' => esc_html__( 'Enable Redirect URL', 'et_builder' ),
'type' => 'yes_no_button',
'option_category' => 'configuration',
'off' => et_builder_i18n( 'No' ),
'on' => et_builder_i18n( 'Yes' ),
'toggle_slug' => 'redirect',
'description' => esc_html__( 'Redirect users after successful form submission.', 'et_builder' ),
'default_on_front' => 'off',
'label' => esc_html__( 'Redirect URL', 'et_builder' ),
'option_category' => 'configuration',
'depends_show_if' => 'on',
'toggle_slug' => 'redirect',
'description' => esc_html__( 'Type the Redirect URL', 'et_builder' ),
'success_message' => array(
'label' => esc_html__( 'Success Message', 'et_builder' ),
'option_category' => 'configuration',
'description' => esc_html__( 'Type the message you want to display after successful form submission. Leave blank for default', 'et_builder' ),
'toggle_slug' => 'main_content',
'dynamic_content' => 'text',
'submit_button_text' => array(
'label' => esc_html__( 'Submit Button', 'et_builder' ),
'option_category' => 'basic_option',
'description' => esc_html__( 'Define the text of the form submit button.', 'et_builder' ),
'toggle_slug' => 'main_content',
'dynamic_content' => 'text',
'mobile_options' => true,
public function get_transition_fields_css_props() {
$fields = parent::get_transition_fields_css_props();
$fields['form_field_background_color'] = array(
'background-color' => implode(
'%%order_class%% .input',
'%%order_class%% .input[type="checkbox"]+label i',
'%%order_class%% .input[type="radio"]+label i',
function predefined_child_modules() {
'[et_pb_contact_field field_title="%1$s" field_type="input" field_id="Name" required_mark="on" fullwidth_field="off" /][et_pb_contact_field field_title="%2$s" field_type="email" field_id="Email" required_mark="on" fullwidth_field="off" /][et_pb_contact_field field_title="%3$s" field_type="text" field_id="Message" required_mark="on" fullwidth_field="on" /]',
esc_attr__( 'Name', 'et_builder' ),
esc_attr__( 'Email Address', 'et_builder' ),
esc_attr__( 'Message', 'et_builder' )
* Renders the module output.
* @param array $attrs List of attributes.
* @param string $content Content being processed.
* @param string $render_slug Slug of module that is used for rendering output.
public function render( $attrs, $content, $render_slug ) {
parent::render( $attrs, $content, $render_slug );
global $et_pb_half_width_counter, $et_pb_contact_form_num;
$et_pb_half_width_counter = 0;
$multi_view = et_pb_multi_view_options( $this );
$multi_view->set_default_value( 'submit_button_text', __( 'Submit', 'et_builder' ) );
$captcha = $this->props['captcha'];
$email = $this->props['email'];
$title = $multi_view->render_element(
'tag' => et_pb_process_header_level( $this->props['title_level'], 'h1' ),
'content' => '{{title}}',
'class' => 'et_pb_contact_main_title',
$form_field_text_color = $this->props['form_field_text_color'];
$button_custom = $this->props['custom_button'];
$custom_message = $this->props['custom_message'];
$use_redirect = $this->props['use_redirect'];
$redirect_url = $this->props['redirect_url'];
$success_message = $this->_esc_attr( 'success_message' );
$header_level = $this->props['title_level'];
$use_spam_service = $this->prop( 'use_spam_service', 'off' );
$field_text_color_hover = $this->get_hover_value( 'form_field_text_color' );
$field_text_color_values = et_pb_responsive_options()->get_property_values( $this->props, 'form_field_text_color' );
$field_focus_text_color_hover = $this->get_hover_value( 'form_field_focus_text_color' );
$field_focus_text_color_values = et_pb_responsive_options()->get_property_values( $this->props, 'form_field_focus_text_color' );
$custom_icon_values = et_pb_responsive_options()->get_property_values( $this->props, 'button_icon' );
$custom_icon = isset( $custom_icon_values['desktop'] ) ? $custom_icon_values['desktop'] : '';
$custom_icon_tablet = isset( $custom_icon_values['tablet'] ) ? $custom_icon_values['tablet'] : '';
$custom_icon_phone = isset( $custom_icon_values['phone'] ) ? $custom_icon_values['phone'] : '';
$video_background = $this->video_background();
$parallax_image_background = $this->get_parallax_image_background();
// Form Field Text Color - Radio Checked.
$field_text_color_important = et_builder_has_limitation( 'force_use_global_important' ) ? ' !important' : '';
et_pb_responsive_options()->generate_responsive_css( $field_text_color_values, '%%order_class%% .input[type="radio"]:checked + label i:before', 'background-color', $render_slug, $field_text_color_important, 'color' );
if ( et_builder_is_hover_enabled( 'form_field_text_color', $this->props ) ) {
ET_Builder_Element::set_style(
'selector' => '%%order_class%% .input[type="radio"]:checked:hover + label i:before',
'declaration' => sprintf(
'background-color: %1$s%2$s;',
esc_html( $field_text_color_hover ),
$field_text_color_important
// Form Field Text Color on Focus - Radio Checked.
et_pb_responsive_options()->generate_responsive_css( $field_focus_text_color_values, '%%order_class%% .input[type="radio"]:checked:active + label i:before', 'background-color', $render_slug, $field_text_color_important, 'color' );
if ( et_builder_is_hover_enabled( 'form_field_focus_text_color', $this->props ) ) {
ET_Builder_Element::set_style(
'selector' => '%%order_class%% .input[type="radio"]:checked:active:hover + label i:before',
'declaration' => sprintf(
'background-color: %1$s%2$s;',
esc_html( $field_focus_text_color_hover ),
$field_text_color_important
$success_message = '' !== $success_message ? $success_message : esc_html__( 'Thanks for contacting us', 'et_builder' );
$et_pb_contact_form_num = $this->render_count();
$hidden_form_fields_key = "et_pb_contact_email_hidden_fields_{$et_pb_contact_form_num}";
$hidden_form_fields = self::$_->array_get( $_POST, $hidden_form_fields_key, array() );
$shortcode_content = $content;
if ( ! empty( $hidden_form_fields ) ) {
$hidden_form_fields = str_replace( '\\', '', $hidden_form_fields );
$hidden_form_fields = json_decode( $hidden_form_fields );
$content = $this->content;
$et_contact_error = false;
$current_form_fields = isset( $_POST[ 'et_pb_contact_email_fields_' . $et_pb_contact_form_num ] ) ? $_POST[ 'et_pb_contact_email_fields_' . $et_pb_contact_form_num ] : '';
$processed_fields_values = array();
$nonce_result = isset( $_POST[ '_wpnonce-et-pb-contact-form-submitted-' . $et_pb_contact_form_num ] ) && wp_verify_nonce( $_POST[ '_wpnonce-et-pb-contact-form-submitted-' . $et_pb_contact_form_num ], 'et-pb-contact-form-submit' ) ? true : false;
// check that the form was submitted and et_pb_contact_et_number field is empty to protect from spam
if ( $nonce_result && isset( $_POST[ 'et_pb_contactform_submit_' . $et_pb_contact_form_num ] ) && empty( $_POST[ 'et_pb_contact_et_number_' . $et_pb_contact_form_num ] ) ) {
if ( '' !== $current_form_fields ) {
$fields_data_json = str_replace( '\\', '', $current_form_fields );
$fields_data_array = json_decode( $fields_data_json, true );
// check whether captcha field is not empty
if ( 'on' === $captcha && 'off' === $use_spam_service && ( ! isset( $_POST[ 'et_pb_contact_captcha_' . $et_pb_contact_form_num ] ) || empty( $_POST[ 'et_pb_contact_captcha_' . $et_pb_contact_form_num ] ) ) ) {
$et_error_message .= sprintf( '<p class="et_pb_contact_error_text">%1$s</p>', esc_html__( 'Make sure you entered the captcha.', 'et_builder' ) );
$et_contact_error = true;
} elseif ( 'on' === $use_spam_service && $this->is_spam_submission() ) {