Split node edit tab in several tabs with panels (or programmatically) I have a content type with many fields, so that loading node/%node/edit is a pain ! In order to split node edit form in smaller forms (menu tabs), I used Page Manager.

What I did so far


Enable the Node add/edit form coming with Page Manager, with selection rule node being edited is from foo_type
Add three new custom panels pages in admin/structure/pages, with paths /node/%node/photos, /node/%node/prices, /node/%node/fd ; with selection rule node being edited is from foo_type
Define its menu as local menu tab. 
Share foo_type fields between these forms, and add a submit node form to each.


This renders correctly three node edit forms accessible in new local task menu tabs :



The buggy part

If I edit the node from any of these forms :


the fields present in it are saved
the data from other fields saved before is still in the database, and also readable in the form fields if I show up the other forms (except for pictures), but it is not displayed anymore in the node.


As per @Letharion comments : " [...] while Panels happens to let you output only half the form as well, that is not supported by form api. One way or another, every field must be present. If not, form api will interpret it as "the user deleted the content of those fields" [...]

The question

I'm searching a way to patch the current solution, or a fully programmatic way to split node edit into tabs. Thanks for your contribution!

Edit:

Most of the issue is solved thanks to flexiform, except for inline entity commerce products. So I'm trying with MrD answer for this specific field, as exposed below. 

The commerce product is saved (corresponding DB tables commerce_product, field_data_commerce_price and so on have a new record), but not attached to its product display (and no record in field_data_field_product). No error is returned.

How to correctly save that commerce product so that it is attached to its node display ?

function vts_nodedit_menu() {
  $items = array();

  $items['node/%node/prices'] = array(
    'title' =&gt; 'Prix et dates',
    'page callback' =&gt; 'node_page_prices',
    'page arguments' =&gt; array(1),
    'access callback' =&gt; 'node_access',
    'access arguments' =&gt; array('update', 1),
    'weight' =&gt; 4,
    'type' =&gt; MENU_LOCAL_TASK,
    'context' =&gt; MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
  );

  return $items;
}

function node_page_prices($node) {
  $form = drupal_get_form('vts_nodedit_form', $node, 'field_product');
  return $form;
}

function vts_nodedit_form($form, &amp;$form_state, $node, $field_name) {
  $form = array();
  field_attach_form('node', $node, $form, $form_state, NULL, array('field_name' =&gt; $field_name));
  $form['submit'] = array(
    '#type' =&gt; 'submit',
    '#value' =&gt; t('Save')
  );
  return $form;
}

function vts_nodedit_form_submit($form, &amp;$form_state) {
  $node = $form_state['build_info']['args'][0];

  //retrieve commerce product to be saved... NON DRUPAL way... :(
  $item = key($form_state['inline_entity_form']);
  $entities = end($form_state['inline_entity_form'][$item]['entities']);
  $product =$entities['entity'];//this is the correct product entity
  //SAVE THE COMMERCE PRODUCT
  commerce_product_save($product);
  //MrD solution 
  field_attach_submit('node', $node, $form, $form_state);
}
It sounds like you have done a lot of work already, and this continues to be a learning experience.  Since the form is now managed how you want it and it is only the data management in the save process that is causing you trouble, I would suggest a few code additions.  Using hook_form_ID_alter there are two methods you can try.

Method 1 Add a custom validation callback to the form.  

$form['#validate'][] = 'MYMODULE_node_data_validate';


Then in your new validation function I suggest loading the node ($node = node_load(nid);) and propagating the data into the form_state.  I am not sure this will work, but I have it listed as method 1 because it is the less disruptive path of the two that I have in mind at the moment.

Method 2 Replace the submit handler with your own.  Similar to the validate function mentioned above, the idea here is to load the node to get the data that was not present on the form that you edited.  However, this time you are going to invoke node_save yourself.  Also you will need to end with a drupal_goto or some other method of sending the user someplace.  Yes you could add an additional handler to the #submit array in the form variable, but either it will be too late to prevent the change the form is doing or it would just be a different name for method 1.

function hook_form_ID_alter(&amp;$form, &amp;$form_state, $form_id) {
    $form['#submit'] = array( 'hook_something_submit');
}
/**
 * Implements hook_form_FORM_ID_alter();
 */
function vts_nodedit_form_accompagn__node_form_alter(&amp;$form, &amp;$form_state, $form_id) {
    $form['#submit'] = array( 'vts_nodedit_data_submit');
}

function vts_nodedit_data_submit($form, &amp;$form_state) {
  // possible cause of missing data is that the form build populates
  $original = node_load( $form_state['node']-&gt;nid );

  // this drupal core function does the work of a full node edit save
  // but we have to have the node to hand it
  // and I do not trust all of $form['node'] in your instance
  field_attach_submit('node', $original, $form, $form_state);

  drupal_set_message(t('The changes have been saved.'));

  if( isset( $form_state['redirect']) ){
    drupal_goto( $form_state['redirect'] );
  } else {
    drupal_goto( '/home' );
  }
}


EDIT
The difference between form_state['input'] and form_state['values'] is that input is the raw $_POST from the user.  I think it would be a security concern to use that directly.  The other validators that are running (why we use $form['#validate'][] and append instead of replace) are taking the new data from input, cleaning it, and putting it in values.  Then if there are blank spots, they fill values with #default_value of the node.  Default is typically the existing value.  Therefore, a submit handler can ignore form_state[input] and have the benefits of drupal in just the form_state[values] array.
Input vs Values