21

I'm interested in embedding a Field Widget Form out side the context of the whole node edit form.

I have displayed full forms in the past using drupal_get_form but that doesn't seem to apply for solitary Field Forms.

Is displaying a working Field Widget Form possible? What would be the best way to do so?

Both field widgets and "normal" forms seem very alike, so if this is not possible, what would be required to "change" a widget form into a normal form?

This question appears to be asking for something similar but I don't understand the answer. That answer specifies using hook_field_widget_form_alter; what I don't understand is how to get the Field Form to be displayed not how to hook it once it is being created.

5 Answers 5

18
+100

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.

2
  • Awesome answer. I spent the better part of a day working with this, and it worked just like I wanted. Bounty awarded, and I recommend the OP accept this as the correct answer. I ended up creating a dummy content type so that I can control my fields like any other content type, instead of setting #access = FALSE which seemed hacky in this context.
    – Letharion
    Mar 20, 2012 at 10:32
  • Thanks for confirming what I had feared: that the single field widget is not practically usable on it's own.
    – SMTF
    Mar 20, 2012 at 21:14
7

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!

5

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.

2

I was unable to get the ctools method working and decided to do it this way instead.

This code would be inside of a form function, so $form and $form_state would be passed in already.

function form_function($form, &$form_state) {

First create an empty node of a type that has the field that you're looking to render.

    $entity = new stdClass();
    $entity->title = "Temp Object";
    $entity->type = "node_type";
    node_object_prepare($entity);

I duplicated the form variables so I wouldn't clobber the original.

    $temp_form       = $form;
    $temp_form_state = $form_state;
    field_attach_form("node", $entity, $temp_form, $temp_form_state);

Pull out the field you are looking for and add it to the form.

    $form["field"] = $temp_form["existing_field"];
}

I used this method to render the taxonomy select widget, taxonomy checkboxes widget and the Hierarchical Select widget on a custom form. (Taxonomy Autocomplete widget renders but throws an error on submit)

Finally render and print

drupal_render(drupal_get_form("form_function"))
1
  • This seems to be an easy way to use a field widget in a custom form. It depends on an existing Bundle though. In my case I use a dummy Content Type where I create and configure fields as needed. That's a bit hacky but necessary for the other methods too. Just to note: The ctools_field_invoke_field() method described above works as well. Oct 8, 2015 at 8:57
0

I have created forms from indivisual fields using

field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $form, $form_state);

this should return the required widget form which can be used in any form like

 $custom_form['form_element_to_display'] = field_default_form('entity_type', $entity, $field,$field_instance,LANGUAGE_NONE,$default_value, $custom_form, $custom_form_state);

To get the values for the 2 parameter above use:

$field = field_info_field($field_name);
$field_instance = field_info_instance('node', $field_name, $node_type);

For other parameters you can check the api link here

This returns the default widget form defined on the content types field.

Hope this helps someone :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.