Discussions

Embedding and altering Commerce entity forms

In this issue we've been making changes to the structure of code to further separate API concerns from the default UI. We've moved entity forms to the API modules, like the product and order edit and delete forms. Then from the UI modules we're instantiating these forms at specific paths using "form wrapper" page callback functions that set the breadcrumbs and display the forms using a form ID unique to the module.

So, the product edit form's generic ID (as determined by the name of the form builder function in commerce_product.module) is commerce_product_product_form. The Product UI module uses the ID commerce_product_ui_product_form to get this form, essentially creating an alias for the generic form using hook_forms(). We can then use hook_form_alter() on the unique form ID to do things like add extra buttons, cancel links, and redirects to the form.

Any modules wanting to embed these forms would follow a similar pattern. This allows us to keep path assumptions completely separate from form definitions, so you can create your own Drupal Commerce UI without having to override any logic baked into the form itself.

However, there will be modules that will need to do things like add elements to every instance of a product edit form. If every instance has a unique form ID, these modules cannot alter the forms based on the ID. The node module accommodates this by adding a special property to node forms called #node_edit_form set to TRUE for any node form. I don't like this approach, as it requires users to know about a form attribute that can't be documented near as easily as a specific API function.

To that end, I've also added the commerce_form_callback() function that will return the callback function for a given form ID. Modules could then use this function in hook_form_alter() to find out if the form being edited is an instance of a generic entity form. For example:

<?php
// Implements hook_form_alter() for any product edit form.
function example_form_alter(&$form, &$form_state, $form_id) {
  if (
commerce_form_callback($form_id, $form_state) == 'commerce_product_product_form') {
   
// Add some element...
 
}
}
?>

I don't know how this will accommodate forms using a wrapper_callback, and maybe we'll just need a separate function for that. Time will tell...

Ryan Szrama
Posted: Jul 13, 2010

Comments

drupalista-br on December 20, 2012

Perhaps implementing hook_inline_entity_form_entity_form_alter() should be the way to go.

Here is an example of how to make the title field available on the Product Variation form embedded into the node edit form:

<?php
function MYMODULE_inline_entity_form_entity_form_alter(&$entity_form, &$form_state) {
  if (
$entity_form['#entity_type'] == 'commerce_product') {
   
$entity_form['title_field']['#access'] = TRUE;
  }
}
?>