Multiple inputs in a custom field [RESOLVED]

Hi all

I’m trying to create a custom field that collects 3 data points for a direct debit payment method.

Here’s the class:

<?php

/**
 * @author BAKKBONE Australia
 * @package ddmwgfFields
 * @license GNU General Public License (GPL) 3.0
**/

defined("DDMWGF_EXEC") or die("Silence is golden");

class DDMWGF_Field_Bank extends GF_Field {
    
    public $type = 'direct_debit_account';
    
	public function get_field_container_tag( $form ) {

		if ( GFCommon::is_legacy_markup_enabled( $form ) ) {
			return parent::get_field_container_tag( $form );
		}

		return 'fieldset';

	}
    
    public function get_form_editor_field_title() {
        return esc_attr__('Direct Debit Account', 'direct-debit-merchant-warrior-for-gravity-forms');
    }
    
	public function get_form_editor_field_description() {
		return esc_attr__( 'Allows users to enter bank details for a Direct Debit with Merchant Warrior.', 'direct-debit-merchant-warrior-for-gravity-forms' );
	}
	
	public function get_form_editor_field_icon() {
		return 'gform-icon--total';
	}
	
    public function is_conditional_logic_supported() {
		return true;
	}
	
	public function get_required_inputs_ids() {
		return array( '1', '2', '3' );
	}
    
    public function get_form_editor_button() {
        return array(
            'group' => 'pricing_fields',
            'text'  => $this->get_form_editor_field_title()
        );
    }
    
    function get_form_editor_field_settings() {
        return array(
            'label_setting',
            'description_setting',
            'rules_setting',
            'label_placement_setting',
            'error_message_setting',
            'css_class_setting',
            'admin_label_setting',
            'visibility_setting',
            'conditional_logic_field_setting',
        );
    }
    
    public function is_value_submission_array() {
    	return true;
    }
    
	public function get_field_input( $form, $value = '', $entry = null ) {

		$is_entry_detail = $this->is_entry_detail();
		$is_form_editor  = $this->is_form_editor();
		$is_admin = $is_entry_detail || $is_form_editor;

		$form_id  = $form['id'];
		$id       = intval( $this->id );
		$field_id = $is_entry_detail || $is_form_editor || $form_id == 0 ? "input_$id" : 'input_' . $form_id . "_$id";
		$form_id  = ( $is_entry_detail || $is_form_editor ) && empty( $form_id ) ? rgget( 'id' ) : $form_id;

		$class_suffix = rgget('view') == 'entry' ? '_admin' : '';
		$class        = $class_suffix;
		$class        = esc_attr( $class );

		$disabled_text = $is_form_editor ? "disabled='disabled'" : '';
		$class_suffix  = $is_entry_detail ? '_admin' : '';

		$form_sub_label_placement = rgar( $form, 'subLabelPlacement' );
		$field_sub_label_placement = $this->subLabelPlacement;
		$is_sub_label_above       = $field_sub_label_placement == 'above' || ( empty( $field_sub_label_placement ) && $form_sub_label_placement == 'above' );
		$sub_label_class          = $field_sub_label_placement == 'hidden_label' ? "hidden_sub_label screen-reader-text" : '';

		$bsb = '';
		$acc  = '';
		$name = '';

		if ( is_array( $value ) ) {
			$bsb = esc_attr( GFForms::get( $this->id['bsb'], $value ) );
			$acc = esc_attr( GFForms::get( $this->id['acc'], $value ) );
			$name = esc_attr( GFForms::get( $this->id['name'], $value ) );
		}

		$bsb_input = GFFormsModel::get_input( $this, $this->id . '.1' );
		$acc_input = GFFormsModel::get_input( $this, $this->id . '.2' );
		$name_input = GFFormsModel::get_input( $this, $this->id . '.3' );

		// ARIA labels.
		$required_attribute     = $this->isRequired ? 'aria-required="true"' : '';
		$invalid_attribute      = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';
		$describedby_attribute  = $this->get_aria_describedby();
		$input_aria_describedby = '';

		$bsb_tabindex = GFCommon::get_tabindex();
		$acc_tabindex  = GFCommon::get_tabindex();
		$name_tabindex = GFCommon::get_tabindex();

		$bsb_sub_label = DDMWGF_BSB;
		$acc_sub_label = DDMWGF_ACC;
		$name_sub_label = DDMWGF_NAME;

		$bsb_markup = '';
		$acc_markup  = '';
		$name_markup = '';

		if ( $is_sub_label_above ) {

			$style = ( $is_admin && rgar( $bsb_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $bsb_input, 'isHidden' ) ) {
				$bsb_markup = "<span id='{$field_id}_bsb_container' class='dd_bsb gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <label for='{$field_id}_bsb' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$bsb_sub_label}</label>
                                            <input type='text' name='input_{$id}.1' id='{$field_id}_bsb' value='{$bsb}' {$bsb_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                        </span>";
			}

			$style = ( $is_admin && rgar( $acc_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $acc_input, 'isHidden' ) ) {
				$acc_markup = "<span id='{$field_id}_acc_container' class='dd_acc gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <label for='{$field_id}_acc' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$acc_sub_label}</label>
                                            <input type='text' name='input_{$id}.2' id='{$field_id}_acc' value='{$acc}' {$acc_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                        </span>";
			}

			$style = ( $is_admin && rgar( $name_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $name_input, 'isHidden' ) ) {
				$name_markup = "<span id='{$field_id}_name_container' class='dd_name gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <label for='{$field_id}_name' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$name_sub_label}</label>
                                            <input type='text' name='input_{$id}.3' id='{$field_id}_name' value='{$name}' {$name_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                        </span>";
			}

		} else {
			$style = ( $is_admin && rgar( $bsb_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $bsb_input, 'isHidden' ) ) {
				$bsb_markup = "<span id='{$field_id}_bsb_container' class='dd_bsb gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <input type='text' name='input_{$id}.1' id='{$field_id}_bsb' value='{$bsb}' {$bsb_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                            <label for='{$field_id}_bsb' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$bsb_sub_label}</label>
                                        </span>";
			}

			$style = ( $is_admin && rgar( $acc_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $acc_input, 'isHidden' ) ) {
				$acc_markup = "<span id='{$field_id}_acc_container' class='dd_acc gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <input type='text' name='input_{$id}.2' id='{$field_id}_acc' value='{$acc}' {$acc_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                            <label for='{$field_id}_acc' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$acc_sub_label}</label>
                                        </span>";
			}

			$style = ( $is_admin && rgar( $name_input, 'isHidden' ) ) ? "style='display:none;'" : '';
			if ( $is_admin || ! rgar( $name_input, 'isHidden' ) ) {
				$name_markup = "<span id='{$field_id}_name_container' class='dd_name gform-grid-col gform-grid-col--size-auto' {$style}>
                                            <input type='text' name='input_{$id}.3' id='{$field_id}_name' value='{$name}' {$name_tabindex} {$disabled_text} {$required_attribute} {$invalid_attribute} {$describedby_attribute} {$input_aria_describedby}/>
                                            <label for='{$field_id}_name' class='gform-field-label gform-field-label--type-sub {$sub_label_class}'>{$name_sub_label}</label>
                                        </span>";
			}

		}
		$css_class = $this->get_css_class();

		return "<div class='ginput_complex{$class_suffix} ginput_container ginput_container--dda {$css_class} gform-grid-row' id='{$field_id}'>
                    {$bsb_markup}
                    {$acc_markup}
                    {$name_markup}
                    <div class='gf_clear gf_clear_complex'></div>
                </div>";
	}
	
	public function get_css_class() {

		$css_class = "ginput_container_dd ";

		return trim( $css_class );
	}
    
    public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
		if ( is_array( $value ) ) {
			$bsb = trim( rgget( $this->id . '.1', $value ) );
			$acc  = trim( rgget( $this->id . '.2', $value ) );
			$name = trim( rgget( $this->id . '.3', $value ) );

			$return = DDMWGF_BSB . ': ' . $bsb . ', ' . DDMWGF_ACC . ': ' . $acc . ', ' . DDMWGF_NAME . ': ' . $name;

		} else {
			$return = $value;
		}

		if ( $format === 'html' ) {
			$return = esc_html( $return );
		}
		return $return;
	}
	
	public function sanitize_settings() {
		parent::sanitize_settings();
		if ( is_array( $this->inputs ) ) {
			foreach ( $this->inputs as &$input ) {
				if ( isset ( $input['choices'] ) && is_array( $input['choices'] ) ) {
					$input['choices'] = $this->sanitize_settings_choices( $input['choices'] );
				}
			}
		}
	}
	
	public function get_value_export( $entry, $input_id = '', $use_text = false, $is_csv = false ) {
		if ( empty( $input_id ) ) {
			$input_id = $this->id;
		}

		if ( absint( $input_id ) == $input_id ) {
			$return = rgar( $entry, $input_id );
			if ( ! empty( $return ) ) {
				return $return;
			}

			$bsb = trim( rgget( $this->id . '.1', $value ) );
			$acc  = trim( rgget( $this->id . '.2', $value ) );
			$name = trim( rgget( $this->id . '.3', $value ) );

			$return = DDMWGF_BSB . ': ' . $bsb . ', ' . DDMWGF_ACC . ': ' . $acc . ', ' . DDMWGF_NAME . ': ' . $name;

			return $return;
		} else {

			return rgar( $entry, $input_id );
		}
	}
	
}

GF_Fields::register( new DDMWGF_Field_Bank() );

(For reference, the constants referred to pull localised strings)

When testing, absolutely no data from any of the 3 fields even attempts to save. Can anyone point me in the right direction re: what I’m missing here?

Thanks :slight_smile:

Here’s what I ended up with instead:

<?php

/**
 * @author BAKKBONE Australia
 * @package ddmwgfFields
 * @license GNU General Public License (GPL) 3.0
**/

defined("DDMWGF_EXEC") or die("Silence is golden");

class DDMWGF_Field_Bank extends GF_Field {

    public $type = 'direct_debit_account';

    public function get_form_editor_field_title() {
        return esc_attr(DDMWGF_TITLE_SHORT);
    }

    public function get_form_editor_button() {
        return array(
            'group' => 'advanced_fields',
            'text'  => $this->get_form_editor_field_title(),
        );
    }

    public function get_form_editor_field_settings() {
        return array(
            'conditional_logic_field_setting',
            'prepopulate_field_setting',
            'label_setting',
            'admin_label_setting',
            'placeholder_setting',
            'rules_setting',
            'duplicate_setting',
            'description_setting',
            'css_class_setting',
        );
    }

    public function is_conditional_logic_supported() {
        return true;
    }

    public function get_field_input( $form, $value = '', $entry = null ) {
        $is_entry_detail = $this->is_entry_detail();
        $is_form_editor  = $this->is_form_editor();

        $form_id  = $form['id'];
        $field_id = intval( $this->id );

        $bsb = $acc = $name = '';

        if ( is_array( $value ) ) {
            $bsb = esc_attr( rgget( $this->id . '.1', $value ) );
            $acc  = esc_attr( rgget( $this->id . '.2', $value ) );
            $name = esc_attr( rgget( $this->id . '.3', $value ) );
        }

        $disabled_text = $is_form_editor ? "disabled='disabled'" : '';
        $class_suffix  = $is_entry_detail ? '_admin' : '';

        $bsb_tabindex = GFCommon::get_tabindex();
        $acc_tabindex  = GFCommon::get_tabindex();
        $name_tabindex = GFCommon::get_tabindex();

        $required_attribute = $this->isRequired ? 'aria-required="true"' : '';
        $invalid_attribute  = $this->failed_validation ? 'aria-invalid="true"' : 'aria-invalid="false"';

        $bsb_markup = '<span id="input_' . $field_id . '_' . $form_id . '.1_container" class="direct_debit_account_bsb">';
        $bsb_markup .= '<input type="text" name="input_' . $field_id . '.1" id="input_' . $field_id . '_' . $form_id . '_1" value="' . $bsb . '" aria-label="'.DDMWGF_BSB.'" ' . $bsb_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $bsb_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_1">'.DDMWGF_BSB.'</label>';
        $bsb_markup .= '</span>';

        $acc_markup = '<span id="input_' . $field_id . '_' . $form_id . '.2_container" class="direct_debit_account_acc">';
        $acc_markup .= '<input type="text" name="input_' . $field_id . '.2" id="input_' . $field_id . '_' . $form_id . '_2" value="' . $acc . '" aria-label="'.DDMWGF_ACC.'" ' . $acc_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $acc_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_2">'.DDMWGF_ACC.'</label>';
        $acc_markup .= '</span>';

        $name_markup = '<span id="input_' . $field_id . '_' . $form_id . '.3_container" class="direct_debit_account_name">';
        $name_markup .= '<input type="text" name="input_' . $field_id . '.3" id="input_' . $field_id . '_' . $form_id . '_3" value="' . $name . '" aria-label="'.DDMWGF_NAME.'" ' . $name_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $name_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_3">'.DDMWGF_NAME.'</label>';
        $name_markup .= '</span>';

        $css_class = $this->get_css_class();

        return "<div class='ginput_complex{$class_suffix} ginput_container {$css_class} gfield_trigger_change' id='{$field_id}'>
                    {$bsb_markup}
                    {$acc_markup}
                    {$name_markup}
                    <div class='gf_clear gf_clear_complex'></div>
                </div>";
    }

    public function get_css_class() {
        $bsb_input = GFFormsModel::get_input( $this, $this->id . '.1' );
        $acc_input  = GFFormsModel::get_input( $this, $this->id . '.2' );
        $name_input = GFFormsModel::get_input( $this, $this->id . '.3' );

        $css_class           = '';
        $visible_input_count = 0;

        if ( $bsb_input && ! rgar( $bsb_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_bsb ';
        } else {
            $css_class .= 'no_bsb ';
        }

        if ( $acc_input && ! rgar( $acc_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_acc ';
        } else {
            $css_class .= 'no_acc ';
        }

        if ( $name_input && ! rgar( $name_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_name ';
        } else {
            $css_class .= 'no_name ';
        }

        $css_class .= "gf_direct_debit_account_has_{$visible_input_count} ginput_container_direct_debit_account ";

        return trim( $css_class );
    }

    public function get_form_editor_inline_script_on_page_render() {

        // set the default field label for the field
        $script = sprintf( "function SetDefaultValues_%s(field) {
        field.label = '%s';
        field.inputs = [new Input(field.id + '.1', '%s'), new Input(field.id + '.2', '%s'), new Input(field.id + '.3', '%s')];
        }", $this->type, $this->get_form_editor_field_title(), DDMWGF_BSB, DDMWGF_ACC, DDMWGF_NAME ) . PHP_EOL;

        return $script;
    }

    public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format = 'html', $media = 'screen' ) {
        if ( is_array( $value ) ) {
            $bsb = trim( rgget( $this->id . '.1', $value ) );
            $acc  = trim( rgget( $this->id . '.2', $value ) );
            $name = trim( rgget( $this->id . '.3', $value ) );

            $return = DDMWGF_BSB.": ".$bsb;
            $return .= ! empty( $return ) && ! empty( $acc ) ? " $acc" : $acc;
            $return .= ! empty( $return ) && ! empty( $name ) ? " $name" : $name;

        } else {
            $return = '';
        }

        if ( $format === 'html' ) {
            $return = esc_html( $return );
        }

        return $return;
    }
	
	public function validate( $value, $form ){
		$bsb = $value[$this->id.'.1'];
		$acc = $value[$this->id.'.2'];
		$name = $value[$this->id.'.3'];
		
		$bsbregex = '/^\d{6}$/';
		$accregex = '/^\d{4,10}$/';
		$nameregex = '/^\w[\w\s-]{1,30}\w$/';
		$validation_message = array();
		
		if(!preg_match($bsbregex, $bsb)){
	        $this->failed_validation = true;
	        $validation_message[] = DDMWGF_BSB_ERROR;
		}
		if(!preg_match($accregex, $acc)){
	        $this->failed_validation = true;
	        $validation_message[] = DDMWGF_ACC_ERROR;
		}
		if(!preg_match($nameregex, $name)){
	        $this->failed_validation = true;
	        $validation_message[] = DDMWGF_NAME_ERROR;
		}
		
		if(!empty($validation_message)){
			$this->validation_message = implode('<br>',$validation_message);
		}

	}

}

GF_Fields::register( new DDMWGF_Field_Bank() );

This worked :slight_smile:

Thank you for sharing your solution!

1 Like