Merge draggable view form in node edit form

Public

How to merge a view that contains a form (draggable views, maybe exposed input, etc) inside a node edit form.
Just calling views_embed_view or drupal_get_form wouldn't work, because the form_id's would clash, and the later one would be used.
Specifically for draggable views use-case, you have to get the form render array, and remove all the form_id's, tokens, etc. And also change the submit handler to decorated one, because it expects the first argument to be a view.

</> CopyGet raw version
php
  1. <?php
  2. function custom_form_alter(&$form, &$form_state, $form_id) {
  3. if ($form_id == 'product_node_form') {
  4. // Display draggable view inside node edit form, only if the node exists.
  5. if (isset($form['#node']->nid) && !empty($form['#node']->nid)) {
  6. // Execute the draggable view.
  7. $draggable_view = views_get_view('ref_design_sorter');
  8. $draggable_view->set_display('reference_design_sorter');
  9. $draggable_view->pre_execute(array($form['#node']->nid));
  10. $draggable_view->execute('reference_design_sorter');
  11.  
  12. // Get the markup without the form.
  13. $draggable_view_output = (!empty($draggable_view->result) || $draggable_view->style_plugin->even_empty())
  14. ? $draggable_view->style_plugin->render($draggable_view->result) : '';
  15.  
  16. // Get the form in array form (not rendered html). This is needed so we strip the form build id's, and what not, so merging the forms works,
  17. // meaning the original form id will be used.
  18. $sorter_form = drupal_get_form(views_form_id($draggable_view), $draggable_view, $draggable_view_output);
  19.  
  20. // Strip lots of unnecessary stuff stuff.
  21. unset($sorter_form['#action']);
  22. unset($sorter_form['#form_id']);
  23. unset($sorter_form['#build_id']);
  24. unset($sorter_form['#token']);
  25. unset($sorter_form['#method']);
  26. unset($sorter_form['form_id']);
  27. unset($sorter_form['form_token']);
  28. unset($sorter_form['form_build_id']);
  29.  
  30. // Change the default draggable_views_submit handler with our own, because it expects a views object argument, which is not properly sent.
  31. $sorter_form['actions']['submit']['#submit'][0] = 'custom_ref_design_draggable_views_submit';
  32.  
  33. // Save the view we will send as an argument, in build_info key.
  34. $form_state['build_info']['draggable_views'][$draggable_view->name] = $draggable_view;
  35.  
  36. // Change the save button to the name set in the options, because whenever the view is empty, views sets its own Save label.
  37. if (isset($reference_design_sorter_view->field['draggableviews']->options['draggableviews']['save_button_label'])) {
  38. $label = $reference_design_sorter_view->field['draggableviews']->options['draggableviews']['save_button_label'];
  39.  
  40. // It is important that the label is not one of the labels that are present on node edit page, like Save, Edit, Delete.
  41. if (in_array($label, array(t('Save'), t('Edit'), t('Preview'), t('Delete'), t('View Changes')))) {
  42. $message = t('The draggable views submit label should be set to something other than Save, Edit, or any other button present,\
  43. otherwise the node edit page will not work correctly. eg. Save Order. The label can be set in the field settings of the draggable view <a href="!link">here</a>.',
  44. array('!link' => url('admin/structure/views/view/' . $reference_design_sorter_view->name)));
  45. drupal_set_message($message, 'warning');
  46.  
  47. }
  48. $sorter_form['actions']['submit']['#value'] = $label;
  49. }
  50.  
  51. // Change the type of the item from 'form' to 'container', so no additional form submit handling is executed besides the main form.
  52. $sorter_form['#type'] = 'container';
  53.  
  54. // Add the draggable views form elements into the node edit form.
  55. $form['ref_design_sorter_wrapper'] = array(
  56. '#type' => 'fieldset',
  57. '#title' => t('Reference Design Category Sorter'),
  58. 'ref_design_sorter' => $sorter_form,
  59. '#weight' => 100,
  60. );
  61.  
  62. // Put it inside the field-group, so we don't clutter the form.
  63. if (isset($form['#fieldgroups']['group_references'])) {
  64. $form['#fieldgroups']['group_references']->children[] = 'ref_design_sorter_wrapper';
  65. $form['#group_children']['ref_design_sorter_wrapper'] = 'group_references';
  66. }
  67. }
  68. }
  69. }
  70.  
  71.  
  72. /**
  73.  * Submit handler that prepares a view object to send to the draggable views submit handler.
  74.  *
  75.  * @param $form
  76.  * @param $form_state
  77.  */
  78. function custom_ref_design_draggable_views_submit($form, &$form_state) {
  79. // Get the view object.
  80. $view_object = current($form_state['build_info']['draggable_views']);
  81.  
  82. // Save the original argument, if it exists.
  83. if (isset($form_state['build_info']['args'][0])) {
  84. $original_argument = $form_state['build_info']['args'][0];
  85. }
  86.  
  87. // Temporarily set the view object as the new argument, and call the draggable views handler.
  88. $form_state['build_info']['args'][0] = $view_object;
  89. draggableviews_views_submit($form, $form_state);
  90.  
  91. // Restore original argument, if it existed.
  92. if (isset($original_argument)) {
  93. $form_state['build_info']['args'][0] = $original_argument;
  94. }
  95. }