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' => 'Prix et dates',
'page callback' => 'node_page_prices',
'page arguments' => array(1),
'access callback' => 'node_access',
'access arguments' => array('update', 1),
'weight' => 4,
'type' => MENU_LOCAL_TASK,
'context' => 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, &$form_state, $node, $field_name) {
$form = array();
field_attach_form('node', $node, $form, $form_state, NULL, array('field_name' => $field_name));
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Save')
);
return $form;
}
function vts_nodedit_form_submit($form, &$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);
}