Drupal - Is displaying a working Field Widget Form on its own possible?

VBO does something like this in modify.action.inc:

$form_key = 'bundle_' . $bundle_name;
$form[$form_key] = array(
  '#type' => 'fieldset',
  '#title' => $label,
  '#parents' => array($form_key),
);  
field_attach_form($context['entity_type'], $entity, $form[$form_key], $form_state, LANGUAGE_NONE);  

So, you need the entity type, the entity (which can be a blank object with just the bundle key set, that's what's actually used), the form where the widgets are added, and the language. If you want to embed the widgets deeper into the form (not in $form, but in $form[$form_key] as I did, or even deeper), then that form array needs to have #parents set.

Of course, notice that this will embed the widgets of all fields belonging to that entity type & bundle. This is how the attach functions were written. Going around that would require you to reinvent quite a lot of code; see the actual code that does the heavy lifting. What I do is go through field instances, get each $field_name, and if that field type doesn't interest me, I set $form[$form_key][$field_name]['#access'] = FALSE; which hides those widgets from sight.

EDIT: Okay, ctools has ctools_field_invoke_field() which could in theory allow you to work on a per-field basis. I've never used it though. The text above is my direct experience.


I was intensively using the function suggested by ttk, but I think that a recent update messed things up...

Here is a new version of the previous solution that works well with Drupal 7.22 and ctools 7.x-1.3.

So, like in the previous post, you call your custom function like this:

my_field_attach_form('field_body', 'node', 'blog',  $node, $form, $form_state, LANGUAGE_NONE);

Notice that the entity bundle is now a parameter. I did this because I was also using this function to edit users. This way, it can also be used for taxonomy term, or any other entity.

And the my_field_attach_form is defined as:

function my_field_attach_form($field_name, $entity_type, $bundle, $entity, &$form, &$form_state, $langcode = NULL) {

  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );

  // Append to the form
  ctools_include('fields');
  $field_instance = field_info_instance($entity_type, $field_name, $bundle);
  $form += (array) ctools_field_invoke_field($field_instance, 'form', $entity_type, $entity, $form, $form_state, $options);
}

This function saved me a lot of time, hope it will for you too!


Here is the solution using the ctools_field_invoke_field() method. In your custom form function, add:

$form = array();
$node = new stdClass();
$node->type = 'blog';
my_field_attach_form('field_body', 'node', $node, $form, $form_state, LANGUAGE_NONE);

where the my_field_attach_form function is defined as

function my_field_attach_form($field_name, $entity_type, $entity, &$form, &$form_state, $langcode = NULL) {
  // Set #parents to 'top-level' if it doesn't exist.
  $form += array('#parents' => array());

  // If no language is provided use the default site language.
  $options = array(
    'language' => field_valid_language($langcode),
    'default' => TRUE,
  );
  module_load_include("inc","ctools","includes/fields");
  $form += (array) ctools_field_invoke_field($field_name, 'form', $entity_type, $entity, $form, $form_state, $options);
}

Note, that your site need to have ctools enabled. It's too bad that Drupal doesn't include a helper function like this by default.

Tags:

Entities

7