Embed Fields of an Entity to a Form in Drupal 7

Entities are one of the most important concepts introduced in Drupal 7. It is clear now that, it got further expanded in Drupal 8.

Sometimes requirements may arise that want you to embed/add fields for an entity within a another form, possibly custom form you created in your module. With this article I am trying to show you how to achieve it. I will show it by embedding fields for a page node within a custom form. To keep things simple, the custom form do nothing other than just showing a text input field and allows to add/edit a page node.

For the sake of having requirement, these are the requirement we try to achieve here.

  • The system needs to keep reference to a particular page to show it somewhere at special place.
  • Form is required to allow to add (for first time) and edit (continue with same page created already) a page node.

It will keep node id for the created page in a system variable and show existing values for the fields when form is opened next time, then save changes when submitted.

There are mainly three functions that we need to call for this task: field_attach_form(), field_attach_form_validate() and field_attach_submit().

field_attach_form() helps us to add the fields for an entity to given form. So, we don't need to write bunch of code to add each fields in the entity in our form. field_attach_form_validate() will validate the submitted values according to the exact field constraints. By calling field_attach_submit() we can fill the submitted values for the fields within actual entity object.

Here is the example showing this:

/**
 * Implements hook_menu().
 */
function MY_MODULE_menu() {
  $items = array();
  $items['my-special-form'] = array(
    'title' => 'Special Form',
    'description' => 'Special configuration form.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array('MY_MODULE_special_form'),
    'access arguments' => array('administer site configuration'),
  );

  return $items;
}

/**
 * Form allowing create/edit a special page node inline along with other fields.
 */
function MY_MODULE_special_form($form, $form_state) {
  $form['test_field'] = array(
    '#type' => 'textfield',
    '#title' => t('Test'),
  );

  $form['#node'] = node_load(variable_get('MY_MODULE_page'));
  if (!$form['#node']) {
    $form['#node'] = entity_create('node', array('type' => 'page'));
  }
  // Add page's field to a continer on the form.
  $form['page'] = array(
    '#type' => 'container',
    '#parents' => array('page'),
    '#tree' => TRUE,
  );

  field_attach_form('node', $form['#node'], $form['page'], $form_state);

  $form['submit'] = array(
    '#type' => 'submit',
    '#value' => t('Submit'),
  );
  return $form;
}

/**
 * Validation handler for MY_MODULE_special_form().
 */
function MY_MODULE_special_form_validate($form, &$form_state) {
  field_attach_form_validate('page', $form['#node'], $form['page'], $form_state);
}

/**
 * Submit handler for MY_MODULE_special_form().
 */
function MY_MODULE_special_form_submit($form, &$form_state) {
  field_attach_submit('node', $form['#node'], $form['page'], $form_state);
  node_save($form['#node']);
  variable_set('MY_MODULE_page', $form['#node']->nid);
}

In MY_MODULE_special_form(), we check whether a page node already exist? If it does exist, then we load it otherwise we create a new page node entity by calling entity_create(). We have to keep the node object along with form structure, here it is kept in variable $form['#node']. So, it will be available while validating and submitting.