How to build widget with arrays inside arrays?

get_field_id prepare prefix for field id, within one widget instance it’s always the same. Your form fields probably look similar to these:

// -- $element[0] --
  // $field[icontxt]
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][0]" value="%4$s">
  // $field[iconlnk]
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][0]" value="%4$s">
  //$field[iconlnktrgt]
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][0]" value="%4$s">

// -- $element[1] --
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][1]" value="%4$s">
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][1]" value="%4$s">
<input class="widefat" id="widget-baseid-instance-inner_elements" name="widget-baseid[instance][inner_elements][1]" value="%4$s">

You need use diffrent id/name for each field.
Additionally, number the group of fields (txt, lnk and lnktrgt) and add this number to the end of the field ID. The same should be done after clicking on “+” button.

$fields['icontxt'] = sprintf(
    '<input class="widefat" id="%1$s" name="%2$s[%3$s]" value="%4$s">',
    $this->get_field_id('icontxt' . $elements_counter),
    $this->get_field_name('icontxt'),
    $elements_counter,
    esc_attr($inner_elements['icontxt'])
);
$fields['iconlnk'] = sprintf(
    '<input class="widefat" id="%1$s" name="%2$s[%3$s]" value="%4$s">',
    $this->get_field_id('iconlnk' . $elements_counter),
    $this->get_field_name('iconlnk'),
    $elements_counter,
    esc_attr($inner_elements['iconlnk'])
);
$fields['iconlnktrgt'] = sprintf(
    '<input class="widefat" id="%1$s" name="%2$s[%3$s]" value="%4$s">',
    $this->get_field_id('iconlnktrgt' . $elements_counter),
    $this->get_field_name('iconlnktrgt'),
    $elements_counter,
    esc_attr($inner_elements['iconlnktrgt'])
);

<input class="widefat" id="widget-baseid-instance-icontxt0" name="widget-baseid[instance][icontxt][0]" value="%4$s">
<input class="widefat" id="widget-baseid-instance-iconlnk0" name="widget-baseid[instance][iconlnk][0]" value="%4$s">
<input class="widefat" id="widget-baseid-instance-iconlnktrgt0" name="widget-baseid[instance][iconlnktrgt][0]" value="%4$s">

Should not $elements[$element_num] be here? You leave one index.

$elements_num = count($elements);
$elements[$element_num + 1] = '';

Update
In update() function, $new_instance parameres contains keys used in form() – ‘icontxt’, ‘iconlnk’, ‘iconlnktrgt’:

$new_instance[icontxt][ 
      0 => "some value from field no. 1", 
      1 => "value from field no. 2", 
];
$new_instance[iconlnk][ 
      0 => "link from first field ", 
      1 => "second link", 
]; 

To read data from field

//name= $this->get_field_name('icontxt')" ...> 
<input class="widefat" id="..." name="" ...>  

inside update() function use $value = $new_instance['icontxt'][0];.

You can try code like this to collect form data into array $elements['inner_elements']:

// arrays initialization
$tmp_elements = [ 'inner_elements' => [] ];
if ( isset($new_instance['icontxt']) ) {
    for($i = 0; $i < count( $new_instance['icontxt'] ); ++$i)
        $tmp_elements['inner_elements' . $i]['icontxt'] = $new_instance['icontxt'][$i];
    unset($new_instance['icontxt']);
}
// ...
$new_instance['elements'] = $tmp_elements;

Leave a Comment