Campo de formularios de gravedad personalizados con entradas múltiples

13 minutos de lectura

avatar de usuario
trevor geene

He estado trabajando en una extensión de Gravity Forms para un cliente. El concepto es agregar un nuevo tipo de campo con 4 entradas. Probé alrededor de 10 variaciones diferentes sobre cómo las personas construyen campos de formulario de gravedad personalizados, pero sigo encontrando el mismo problema.

Al crear un campo personalizado, si uso solo 1 entrada según la convención de nomenclatura de input_{field_id} el formulario se guardará y validará correctamente. Pero en el momento en que trato de agregar más de un campo usando los nombres input_{field_id}.{i} al igual que los campos incorporados, el formulario ya no guardará mis datos.

<?php if ( ! class_exists( 'GFForms' ) ) { die(); }

class GF_Field_Attendees extends GF_Field {

    public $type="attendees";

    public function get_form_editor_field_title() { return esc_attr__( 'Attendees', 'gravityforms' ); }

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

    public function get_form_editor_field_settings() {
        return array(
            'conditional_logic_field_setting',
            'prepopulate_field_setting',
            'error_message_setting',
            'label_setting',
            'admin_label_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 ) {
        $form_id    = $form['id'];
        $field_id   = intval( $this->id );

        $first  = esc_attr( GFForms::get( 'input_' . $this->id . '_1', $value ) );
        $last   = esc_attr( GFForms::get( 'input_' . $this->id . '_2', $value ) );
        $email  = esc_attr( GFForms::get( 'input_' . $this->id . '_3', $value ) );
        $phone  = esc_attr( GFForms::get( 'input_' . $this->id . '_4', $value ) );

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

        $first_tabindex = GFCommon::get_tabindex();
        $last_tabindex  = GFCommon::get_tabindex();
        $email_tabindex = GFCommon::get_tabindex();
        $phone_tabindex = GFCommon::get_tabindex();

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

        $first_markup = '<span id="input_'.$field_id.'_'.$form_id.'.1_container" class="attendees_first">';
            $first_markup .= '<input type="text" name="input_'.$field_id.'.1" id="input_'.$field_id.'_'.$form_id.'_1" value="'.$first.'" aria-label="First Name" '.$first_tabindex.' '.$disabled_text.' '.$required_attribute.' '.$invalid_attribute.'>';
            $first_markup .= '<label for="input_'.$field_id.'_'.$form_id.'_1">First Name</label>';
        $first_markup .= '</span>';

        $last_markup = '<span id="input_'.$field_id.'_'.$form_id.'.2_container" class="attendees_last">';
            $last_markup .= '<input type="text" name="input_'.$field_id.'.2" id="input_'.$field_id.'_'.$form_id.'_2" value="'.$last.'" aria-label="Last Name" '.$last_tabindex.' '.$disabled_text.' '.$required_attribute.' '.$invalid_attribute.'>';
            $last_markup .= '<label for="input_'.$field_id.'_'.$form_id.'_2">Last Name</label>';
        $last_markup .= '</span>';

        $email_markup = '<span id="input_'.$field_id.'_'.$form_id.'.3_container" class="attendees_email">';
            $email_markup .= '<input type="text" name="input_'.$field_id.'.3" id="input_'.$field_id.'_'.$form_id.'_3" value="'.$email.'" aria-label="Email" '.$email_tabindex.' '.$disabled_text.' '.$required_attribute.' '.$invalid_attribute.'>';
            $email_markup .= '<label for="input_'.$field_id.'_'.$form_id.'_3">Email</label>';
        $email_markup .= '</span>';

        $phone_markup = '<span id="input_'.$field_id.'_'.$form_id.'.4_container" class="attendees_phone">';
            $phone_markup .= '<input type="text" name="input_'.$field_id.'.4" id="input_'.$field_id.'_'.$form_id.'_4" value="'.$phone.'" aria-label="Phone #" '.$phone_tabindex.' '.$disabled_text.' '.$required_attribute.' '.$invalid_attribute.'>';
            $phone_markup .= '<label for="input_'.$field_id.'_'.$form_id.'_4">Phone #</label>';
        $phone_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}'>
                    {$first_markup}
                    {$last_markup}
                    {$email_markup}
                    {$phone_markup}
                    <div class="gf_clear gf_clear_complex"></div>
                </div>";
    }

    public function get_css_class() {
        $first_input = GFFormsModel::get_input( $this, $this->id . '_2' );
        $last_input  = GFFormsModel::get_input( $this, $this->id . '_3' );
        $email_input = GFFormsModel::get_input( $this, $this->id . '_4' );
        $phone_input   = GFFormsModel::get_input( $this, $this->id . '_5' );

        $css_class="";
        $visible_input_count = 0;

        if ( $first_input && ! rgar( $first_input, 'isHidden' ) ) {
            $visible_input_count++;
            $css_class .= 'has_first_name ';
        } else {
            $css_class .= 'no_first_name ';
        }

        if ( $last_input && ! rgar( $last_input, 'isHidden' ) ) {
            $visible_input_count++;
            $css_class .= 'has_last_name ';
        } else {
            $css_class .= 'no_last_name ';
        }

        if ( $email_input && ! rgar( $email_input, 'isHidden' ) ) {
            $visible_input_count++;
            $css_class .= 'has_email ';
        } else {
            $css_class .= 'no_email ';
        }

        if ( $phone_input && ! rgar( $phone_input, 'isHidden' ) ) {
            $visible_input_count++;
            $css_class .= 'has_phone ';
        } else {
            $css_class .= 'no_phone ';
        }

        $css_class .= "gf_attendees_has_{$visible_input_count} ginput_container_attendees ";

        return trim( $css_class );
    }

    public function get_value_submission( $field_values, $get_from_post ) {
        if(!$get_from_post) {
            return $field_values;
        }

        return $_POST;
    }
}

GF_Fields::register( new GF_Field_Attendees() );

Pasé alrededor de 20 horas probando diferentes arreglos y buscando en Internet para que esto funcionara, sin suerte para mostrarlo. En un momento pude hacer que los campos del formulario se guardaran usando un método diferente (ver más abajo), pero no pude hacer que el campo fuera obligatorio ni usar el inicio de sesión condicional en él, lo cual es obligatorio.

$group_title = "Attendees";
$group_name = "attendees";
$group_fields = array(
    'attendee_first' => 'First Name',
    'attendee_last' => 'Last Name',
    'attendee_email' => 'Email',
    'attendee_phone' => 'Phone'
);
$group_values = array();

add_filter('gform_add_field_buttons', add_field);
function add_field($field_group)
{
  global $group_title, $group_name;

  foreach ($field_group as &$group) {

    if ($group['name'] == 'advanced_fields') {
      $group['fields'][] = array (
        'class'     => 'button',
        'value'     => __($group_title, 'gravityforms'),
        'onclick'   => "StartAddField('".$group_name."');",
        'data-type' => $group_name
      );
      break;
    }
  }

  return $field_group;
}

add_filter('gform_field_type_title', add_field_title, 10, 2);
function add_field_title($title, $field_type)
{
  global $group_title, $group_name;

  if ($field_type == $group_name) {
    $title = __($group_title, 'gravityforms');
  }

  return $title;
}

add_filter('gform_field_input', 'render_fields', 10, 5);
function render_fields($input, $field, $value, $entry_id, $form_id)
{
  global $group_name, $group_fields;

  if ($field->type == $group_name)
  {
    $i = 1;
    $input="<div class="ginput_complex ginput_container">";
    foreach ($group_fields as $key => $val) {
        $input .= '<span id="input_'.$field['id'].'_'.$form_id.'_'.$i.'_container" class="name_suffix ">';
            $input .= '<input type="text" name="input_'.$field['id'].'_'.$i.'" id="input_'.$field['id'].'_'.$form_id.'_'.$i.'" value="'.$value[$field['id'].'.'.$i].'" class="'.esc_attr($key).'" aria-label="'.$val.'">';
            $input .= '<label for="input_'.$field['id'].'_'.$form_id.'_'.$i.'">'.$val.'</label>';
        $input .= '</span>';
        $i ++;
        if ($i % 10 == 0) { $i++; }
    }
    $input .= '</div>';
  }

  return $input;
}

add_action('gform_editor_js_set_default_values', set_default_values);
function set_default_values()
{
  global $group_title, $group_name, $group_fields;
  ?>
  case '<?php echo $group_name; ?>' :
    field.label="<?php _e($group_title, "gravityforms'); ?>';
    field.inputs = [
        <?php
        $i = 1;
        foreach ($group_fields as $key => $val) { ?>
            new Input(field.id + 0.<?php echo $i; ?>, '<?php echo esc_js(__($val, 'gravityforms')); ?>'),
        <?php
            $i++;
            if ($i % 10 == 0) { $i++; }
        } ?>
    ];
    break;
  <?php
}

add_filter( 'gform_entry_field_value', 'category_names', 10, 4 );
function category_names( $value, $field, $lead, $form )
{
  global $group_name, $group_values;

  if($field->type == $group_name)
  {
    $array = array();
    $output = "";
    foreach($field->inputs as $input)
    {
      $array[$input['label']] = $value[$input['id']];

      $output .= "<strong>".$input['label'].":</strong> ";
      $output .= $value[$input['id']]."<br>";
    }
    $group_values[] = $array;

    return $output;
  }

  return $value;
}

Si alguien me puede ayudar con cualquiera de los dos problemas, se lo agradecería mucho.

Actualización de clase:

  • Limpiado get_field_input

  • Adicional get_value_submission

  • Todavía no he encontrado ninguna respuesta a mi pregunta. Si alguien alguna vez resuelve esto, me encantaría saberlo.

    – Trevor Genene

    29 de marzo de 2017 a las 22:15

Después de trabajar con el equipo de soporte de Gravity Forms durante unos días, pudimos encontrar esta solución. Todo parece estar funcionando ahora. Espero que esto ayude a alguien en el futuro.

class GF_Field_Attendees extends GF_Field {

    public $type="attendees";

    public function get_form_editor_field_title() {
        return esc_attr__( 'Attendees', 'gravityforms' );
    }

    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',
            'error_message_setting',
            'label_setting',
            'admin_label_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 );

        $first = $last = $email = $phone="";

        if ( is_array( $value ) ) {
            $first = esc_attr( rgget( $this->id . '.1', $value ) );
            $last  = esc_attr( rgget( $this->id . '.2', $value ) );
            $email = esc_attr( rgget( $this->id . '.3', $value ) );
            $phone = esc_attr( rgget( $this->id . '.4', $value ) );
        }

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

        $first_tabindex = GFCommon::get_tabindex();
        $last_tabindex  = GFCommon::get_tabindex();
        $email_tabindex = GFCommon::get_tabindex();
        $phone_tabindex = GFCommon::get_tabindex();

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

        $first_markup = '<span id="input_' . $field_id . '_' . $form_id . '.1_container" class="attendees_first">';
        $first_markup .= '<input type="text" name="input_' . $field_id . '.1" id="input_' . $field_id . '_' . $form_id . '_1" value="' . $first . '" aria-label="First Name" ' . $first_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $first_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_1">First Name</label>';
        $first_markup .= '</span>';

        $last_markup = '<span id="input_' . $field_id . '_' . $form_id . '.2_container" class="attendees_last">';
        $last_markup .= '<input type="text" name="input_' . $field_id . '.2" id="input_' . $field_id . '_' . $form_id . '_2" value="' . $last . '" aria-label="Last Name" ' . $last_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $last_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_2">Last Name</label>';
        $last_markup .= '</span>';

        $email_markup = '<span id="input_' . $field_id . '_' . $form_id . '.3_container" class="attendees_email">';
        $email_markup .= '<input type="text" name="input_' . $field_id . '.3" id="input_' . $field_id . '_' . $form_id . '_3" value="' . $email . '" aria-label="Email" ' . $email_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $email_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_3">Email</label>';
        $email_markup .= '</span>';

        $phone_markup = '<span id="input_' . $field_id . '_' . $form_id . '.4_container" class="attendees_phone">';
        $phone_markup .= '<input type="text" name="input_' . $field_id . '.4" id="input_' . $field_id . '_' . $form_id . '_4" value="' . $phone . '" aria-label="Phone #" ' . $phone_tabindex . ' ' . $disabled_text . ' ' . $required_attribute . ' ' . $invalid_attribute . '>';
        $phone_markup .= '<label for="input_' . $field_id . '_' . $form_id . '_4">Phone #</label>';
        $phone_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}'>
                    {$first_markup}
                    {$last_markup}
                    {$email_markup}
                    {$phone_markup}
                    <div class="gf_clear gf_clear_complex"></div>
                </div>";
    }

    public function get_css_class() {
        $first_input = GFFormsModel::get_input( $this, $this->id . '.1' );
        $last_input  = GFFormsModel::get_input( $this, $this->id . '.2' );
        $email_input = GFFormsModel::get_input( $this, $this->id . '.3' );
        $phone_input = GFFormsModel::get_input( $this, $this->id . '.4' );

        $css_class="";
        $visible_input_count = 0;

        if ( $first_input && ! rgar( $first_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_first_name ';
        } else {
            $css_class .= 'no_first_name ';
        }

        if ( $last_input && ! rgar( $last_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_last_name ';
        } else {
            $css_class .= 'no_last_name ';
        }

        if ( $email_input && ! rgar( $email_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_email ';
        } else {
            $css_class .= 'no_email ';
        }

        if ( $phone_input && ! rgar( $phone_input, 'isHidden' ) ) {
            $visible_input_count ++;
            $css_class .= 'has_phone ';
        } else {
            $css_class .= 'no_phone ';
        }

        $css_class .= "gf_attendees_has_{$visible_input_count} ginput_container_attendees ";

        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'), new Input(field.id + '.4', '%s')];
        }", $this->type, $this->get_form_editor_field_title(), 'First Name', 'Last Name', 'Email', 'Phone' ) . PHP_EOL;

        return $script;
    }

    public function get_value_entry_detail( $value, $currency = '', $use_text = false, $format="html", $media="screen" ) {
        if ( is_array( $value ) ) {
            $first = trim( rgget( $this->id . '.1', $value ) );
            $last  = trim( rgget( $this->id . '.2', $value ) );
            $email = trim( rgget( $this->id . '.3', $value ) );
            $phone = trim( rgget( $this->id . '.4', $value ) );

            $return = $first;
            $return .= ! empty( $return ) && ! empty( $last ) ? " $last" : $last;
            $return .= ! empty( $return ) && ! empty( $email ) ? " $email" : $email;
            $return .= ! empty( $return ) && ! empty( $phone ) ? " $phone" : $phone;

        } else {
            $return = '';
        }

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

        return $return;
    }

}

GF_Fields::register( new GF_Field_Attendees() );

  • Gracias por compartir

    – chris

    6 de abril de 2018 a las 1:25

  • Bestia gloriosa, esto es exactamente lo que necesitaba. Sin embargo, necesitaba hacer que ciertos campos fueran obligatorios y otros no. Acabo de usar una validación similar a la name campo: pastebin.com/raw/HjdDytLJ

    – Xhynk

    15 de junio de 2019 a las 1:18

  • Gracias por compartir. Lástima que la documentación oficial sea tan pobre.

    –Marek Mauricio

    hace 2 días

¿Ha sido útil esta solución?