Making a new field via module
I found another great example in the book "Drupal 7 Module Development", having worked through this example I am now able to alter it to my own purposes and the data is persistent. 

Below is a working 3 field example. 

function prodlist_field_info() {
  return array(
    'productorder' =&gt; array( 
      'label' =&gt; t('Product Code'),
      'description' =&gt; t('Used to assign product codes'),
      'default_widget' =&gt; 'prodlist_text',
      'default_formatter' =&gt; 'field_example_simple_text',
    ),
  );
}


function prodlist_field_schema($field) {
  if ($field['type'] =='productorder') {
      $schema['columns']['code'] = array(
        'type' =&gt; 'varchar',
        'length' =&gt; 10,
        'not null' =&gt; FALSE,
      );
      $schema['columns']['description'] = array(
        'type' =&gt; 'varchar',
        'length' =&gt; 10,
        'not null' =&gt; FALSE,
      );
      $schema['columns']['amount'] = array(
        'type' =&gt; 'int',
        'not null' =&gt; FALSE,
      );


      $schema['indexes'] = array(
        'code' =&gt; array('code'),
        'description' =&gt; array('description'),
        'amount' =&gt; array('amount'),
      );

      return $schema;
  }

}

function prodlist_field_is_empty($item, $field) {
  if ($field['type'] == 'productorder') {
    if (empty($item['code']) &amp;&amp; empty($item['description']) &amp;&amp; empty($item['amount']) ) {
      return TRUE;
    }
  }
  return FALSE;

}


function prodlist_field_widget_info() {
  return array(
     'prodlist_text' =&gt; array(
      'label' =&gt; t('Prodcode entry fields'),
      'field types' =&gt; array('productorder'), 

    ),

  );
}

function prodlist_field_widget_form(&amp;$form, &amp;$form_state, $field, $instance, $langcode, $items, $delta, $element) {
  $base = $element;

  if ($instance['widget']['type'] == 'prodlist_text') {
    $element['code'] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Code'),
      '#default_value' =&gt; isset($items[$delta]['code']) ? $items[$delta]['code'] : NULL) + $base;
    $element['description'] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Description'),
      '#default_value' =&gt; isset($items[$delta]['description']) ? $items[$delta]['description'] : NULL) + $base;
    $element['amount'] = array(
      '#type' =&gt; 'textfield',
      '#title' =&gt; t('Amount'),
      '#default_value' =&gt; isset($items[$delta]['amount']) ? $items[$delta]['amount'] : NULL) + $base;

  }
  return $element;

}