I created a simple content type and a form mode for this content type. Where can I view this form mode after creating it? I see no option for form modes when creating a content type. I would have expected an option to be presented when clicking on "Add Content" to select "Add xy content with xy form mode"?

Perhaps with a simple get var like
add/page/?form=light
add/page/?form=heavy

Issue fork drupal-2530086

Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

giorgio79’s picture

Issue summary: View changes
yched’s picture

@giorgio79 : Right, form modes can only be leveraged via custom code in custom controllers - at least at the moment nothing in core makes use of custom-defined form modes.
(unlike custom view modes, that can be selected in Views, or in entity_reference formatters - but those features have no equivalent on the form side)

The feature you mention seems like something a contrib module could provide, as it might not be a desired behavior on all sites.

Berdir’s picture

Category: Support request » Feature request

Yes. At the moment, this simply doesn't exist. https://www.drupal.org/project/issues/entityform_block is one thing that will eventually leverage it.

stevector’s picture

singularo’s picture

I need to create a form that has different fields present for different roles. I thought that using the new form modes would be more sensible than trying to hide fields via a form_alter as in d6/d7, and I think that I've almost worked it out. I have a node type 'custom_profile' and a new display mode 'administrator_profile_form' with all the fields visible, and on the 'default' display mode, most of the fields hidden. Then this code in a custom module to get the new display mode to show (conditional role stuff yet to be done):

function custom_form_alter(&$form, &$form_state, $form_id) {
  if ($form_id == 'node_custom_profile_form') {
    $entity= $form_state->getFormObject()->getEntity();
    $form_display = \Drupal\Core\Entity\Entity\EntityFormDisplay::collectRenderDisplay($entity, 'administrator_profile_form');
    $form_state->set('form_display', $form_display);
    $form_state->setRebuild();
  }
}

Using phpstorm+xdebug, I can see that the form_state is updated, and everything looks like it should display with the new display mode but I still get the 'default' form.

Any pointers as to where I'm going wrong?

stevector’s picture

Hi Singularo, I think you should approach this task with the mindset of asking for the form mode you want, rather than overriding/altering a form mode once the processing has started.

For instance if you are looking to change the form at node/add/page then look at the controller for that path.

http://cgit.drupalcode.org/drupal/tree/core/modules/node/src/Controller/...

The relevant chunk of code is

$form = $this->entityFormBuilder()->getForm($node);

I think you'd want to override that method/route and replace it with something like

if ($some_condition) {
   $form = $this->entityFormBuilder()->getForm($node, 'custom_profile');
}
else if ($some_other_condition) {
   $form = $this->entityFormBuilder()->getForm($node, 'administrator_profile_form');
}
 

Also look at #2511720: Allow form modes to use default operation if a form operation is not explicitly set to make sure the form mode does not throw an error when it is called.

Berdir’s picture

Showing/Hiding fields but keep them otherwise the same is IMHO a perfect use case for hook_entity_field_access() not switching out the form display. I'd only try to do something like that when you want to show different widgets based on the user roles.

stevector’s picture

Good point Berdir. I agree. Field access is a better fit if per-field visibility by role is the only difference between the forms.

Field Permissions module module has handled that use case well. There is not yet a Drupal 8 version: #2196303: Port field permissions to drupal 8

rattusrattus’s picture

Re #6 I do not believe that the second argument to the EntityFormBuilder getForm method is the form mode; this is the operation and, from what I can tell from the interface doc block, it concerns the crud operation rather than the form mode. When passing the my form mode key to getForm I get the following error:

Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException: The "node" entity type did not specify a "admin" form class. in Drupal\Core\Entity\EntityTypeManager->getFormObject() (line 182 of /var/www/drupal/web/core/lib/Drupal/Core/Entity/EntityTypeManager.php).

So I'm still looking for a way to render an entity form with a particular form mode...

Any pointers greatly appreciated.

jacov’s picture

i too was looking for something like:

add/page/?form=light
add/page/?form=$form_mode

imho this should be native to the functionality of the core module and should not depend on entityform_block

farald’s picture

I agree with jacov. What I would want to do, is have a separate form configured to do a separate task.

Scenario: You have a node which two roles should have access to.

1: Content proposer: /node/add/content-> Add title and node field content only.
2: Content promoter: /node/X/promotion -> Edit the same node, have no access to fields above, but two other fields, "Promote" checkbox and "Promotions comments" field.

A scenario like this should "easily" be handled natively through UI.

robertwb’s picture

IMO a way to access alternate form modes via URL. Rather than GET params, I think they should be added as routes, admins should be able to enable a route in admin/structure/display-modes/form/manage/[display mode machine name] (disabled by default to reflect @yched concern in #2 ).

dench0’s picture

1. create needed form modes, for example I created for content custom form mode - "my_mode" (machine name node.my_mode )
2. implement hook:

function hook_entity_type_build(array &$entity_types) {
  $entity_types['node']->setFormClass('my_mode', 'Drupal\node\NodeForm');
}

3. build form ($node - is loaded node object):

$entity_form_builder = new entityFormBuilder($container->get('entity.manager'), $container->get('form_builder'))
$form = $entity_form_builder->getForm($node, 'my_mode');

Version: 8.0.x-dev » 8.1.x-dev

Drupal 8.0.6 was released on April 6 and is the final bugfix release for the Drupal 8.0.x series. Drupal 8.0.x will not receive any further development aside from security fixes. Drupal 8.1.0-rc1 is now available and sites should prepare to update to 8.1.0.

Bug reports should be targeted against the 8.1.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.2.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

DuneBL’s picture

@dench0 (#13)
I couldn't understand where to put the chunk of code defined in "3. build form"

eloivaque’s picture

Meanwhile you can try this modules.

https://www.drupal.org/project/form_mode_control
https://www.drupal.org/project/form_mode_manager

I prefer form_mode_control. Form_mode_manager create view form mode for all content types.

Version: 8.1.x-dev » 8.2.x-dev

Drupal 8.1.9 was released on September 7 and is the final bugfix release for the Drupal 8.1.x series. Drupal 8.1.x will not receive any further development aside from security fixes. Drupal 8.2.0-rc1 is now available and sites should prepare to upgrade to 8.2.0.

Bug reports should be targeted against the 8.2.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.3.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

taggartj’s picture

Hello Well after some time of messing with this i seem to have it working:
and here is how

1) create your form display and get id from url
at :admin/structure/display-modes/form/manage/

"Test This" gives m name ... node.test_this

in your modules
my_module.routing.yml

#admin/structure/display-modes/form/manage/node.test_this
#node.test_this is the name !
my_module.test_this:
 path: '/some-path/{node}/test_this'
 defaults:
   _entity_form: node.test_this
 requirements:
   _permission: 'some perm'

#Symfony\Component\Routing\Exception\RouteNotFoundException: Route "entity.node.test_this" fix
#when you go to www.site.com/node/NID  or save from your form mode
#yes you need this !!!!!! or you will have a bad time try with out lol!
entity.node.test_this:
 path: 'node/{node}'
 defaults:
  _controller: '\Drupal\node\Controller\NodeViewController::view'
 requirements:
   _permission: 'access content'

.... now in your module
my_module.module

/**
 * Implements hook_entity_type_alter().
 * inspiration from  form_mode_manager_entity_type_alter (THANK YOU !!!). 
 */
function my_module_entity_type_alter(array &$entity_types) {
  $form_modes = \Drupal::service('entity_display.repository')->getAllFormModes();
  foreach ($form_modes as $entity_type => $display_modes) {
    /* @var \Drupal\Core\Entity\EntityTypeInterface $entity */
    $entity = $entity_types[$entity_type];
    foreach ($display_modes as $machine_name => $form_display) {
      if ($machine_name != 'register') {
        // Get the correct canonical path to add operation.
        $path = $entity->getLinkTemplate('canonical') . "/$machine_name";
        $default_handler_class = $entity->getHandlerClasses()['form']['default'];
        $entity->setFormClass($machine_name, $default_handler_class)
          ->setLinkTemplate($machine_name, $path);
      }
    }
  }
}

function my_module_form_alter(&$form, FormStateInterface $form_state, $form_id) {
  //dump($form_id);
}

now you can go to the path www.site.com/some-path/{nodeID}/test_this
and try to not have your chin hit the floor.

the cool thing as it gives a new form id to then alter

chriscalip’s picture

This was a PITA! For this feature to be operational for nodes.

$node = \Drupal::entityTypeManager()->getStorage('node')->create(array('type' => 'NODE-BUNDLE-HERE'));
$block_form = \Drupal::service('entity.form_builder')->getForm($node, 'FORM-MODE-HERE');

Add this to your module.

/**
 * Implements hook_entity_type_alter().
 */
function chriscalip_entity_type_alter(array &$entity_types) {
  $entity_type = 'node';
  $entity = $entity_types[$entity_type];
  /** @var \Drupal\Core\Entity\EntityDisplayRepository[] $display_modes_list for node */
  $form_modes = \Drupal::service('entity_display.repository')->getFormModes($entity_type);
  foreach ($form_modes as $machine_name => $form_display) {
    // Get the correct canonical path to add operation.
    $path = $entity->getLinkTemplate('canonical') . "/$machine_name";
    $default_handler_class = $entity->getHandlerClasses()['form']['default'];
    $entity->setFormClass($machine_name, $default_handler_class)->setLinkTemplate($machine_name, $path);
  }
}

This #19 has bugs and as well as #18. For custom forms use #13 instead.

grumpy74’s picture

#18 works perfectly

With some improvments like adding tasks tabs as on usual node form pages and adding some custom permissions, it's easy to create a per permission access to different form display.

Thanks a lot taggartj.

I'm working on a dynamic way to generate form modes routes and permissions (like "form mode manager" and "form display control" modules should do, but both are broken in Drupal 8.2.3 version)..

UPDATE : aftr testing the module "form mode manager" works perfectly.

SteffenR’s picture

@chriscalip: Thanks for posting a working solution - works fine in my case.

Version: 8.2.x-dev » 8.3.x-dev

Drupal 8.2.6 was released on February 1, 2017 and is the final full bugfix release for the Drupal 8.2.x series. Drupal 8.2.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.3.0 on April 5, 2017. (Drupal 8.3.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.3.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.4.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

tim.plunkett’s picture

Status: Active » Needs review
FileSize
1.84 KB

Just a proof of concept, and this has backwards compatibility issues, but this would allow custom code to use form modes correctly AFAICS

Pavan B S’s picture

Re rolled the patch, please review.

MaskOta’s picture

NewZeal’s picture

Another way to solve this problem is as follows:

/**
 * Implements hook_entity_form_display_alter().
 */

function MYMODULE_entity_form_display_alter(&$form_display, $context) {

  switch ($form_display->id()) {
    case 'ENTITY_TYPE.BUNDLE.FORM_MODE':
      $storage = \Drupal::entityManager()->getStorage('entity_form_display');
      $form_display = $storage->load('ENTITY_TYPE.BUNDLE.FORM_MODE');
  }

}

Replace items in caps with own values.

woprrr’s picture

You can use FormModeManager module too for use form-mode onto ALL entities compatibles + media/file entity (and your custom).

You can too inspirate you with our method to make you custom implement or with help of FormModeManager services.

kalidasan’s picture

Tried hook_entity_type_alter, hook_entity_type_build but no luck.
Ref: https://www.webomelette.com/render-custom-entity-form-modes-programatica... (Not worked)

But #26 is working fine after spending so much time.

Link to add form modes : admin/structure/display-modes/form

Thanks @New Zeal for your solution :)

Version: 8.3.x-dev » 8.4.x-dev

Drupal 8.3.6 was released on August 2, 2017 and is the final full bugfix release for the Drupal 8.3.x series. Drupal 8.3.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.4.0 on October 4, 2017. (Drupal 8.4.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.4.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.5.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

joachim’s picture

+++ b/core/lib/Drupal/Core/Entity/EntityFormBuilder.php
@@ -40,8 +40,8 @@ public function __construct(EntityManagerInterface $entity_manager, FormBuilderI
+  public function getForm(EntityInterface $entity, $operation = 'default', array $form_state_additions = array(), $form_class = NULL) {
+    $form_object = $this->entityManager->getFormObject($entity->getEntityTypeId(), $operation, $form_class);

Rather than adding a parameter, what about having the mode in $form_state_additions, so this works:

$form = \Drupal::service('entity.form_builder')->getForm($entity, 'edit', ['form_display' => 'my_mode']);

At the moment, it gets clobbered by ContentEntityForm::init()'s call to setFormDisplay()

giorgio79’s picture

woprrr’s picture

So I IMHO we need to planned a port of form mode manager features/usages in core (in display reposittory). If core team is interested I purpose prépare that and see with field/core team and make an experimental module instead of continue to maintain form mode manager.

julius95’s picture

@woprr This definitely makes sense! It is strange that you have to write a module just to link to a form mode,

Version: 8.4.x-dev » 8.5.x-dev

Drupal 8.4.4 was released on January 3, 2018 and is the final full bugfix release for the Drupal 8.4.x series. Drupal 8.4.x will not receive any further development aside from critical and security fixes. Sites should prepare to update to 8.5.0 on March 7, 2018. (Drupal 8.5.0-alpha1 is available for testing.)

Bug reports should be targeted against the 8.5.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.6.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

sukh.singh’s picture

I tried form_mode_manager as suggested by many over here but didn't work for profiles. In Readme.txt they written specifically that

Profile : Not compatible with Profile ATM please follow #2834749 issue to have more precision.

I also tried

hook_entity_type_alter, hook_entity_type_build

, but they also didn't work. Lastly I tried #26 solutions and it worked for me.

Thanks ton New Zeal for providing this solutions.

woprrr’s picture

Hi sukh with 2.x branch and issue listed you can use fmm with profiles.

taggartj’s picture

https://www.drupal.org/project/form_mode_routing
can be a quick solution as well

yseki’s picture

Business Rules module now allows changing the form view mode based on any condition.

Let me know how it works for you.

Version: 8.5.x-dev » 8.6.x-dev

Drupal 8.5.6 was released on August 1, 2018 and is the final bugfix release for the Drupal 8.5.x series. Drupal 8.5.x will not receive any further development aside from security fixes. Sites should prepare to update to 8.6.0 on September 5, 2018. (Drupal 8.6.0-rc1 is available for testing.)

Bug reports should be targeted against the 8.6.x-dev branch from now on, and new development or disruptive changes should be targeted against the 8.7.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

kenton.r’s picture

I have used Business Rules to switch form modes with conditions and it works. I also like the proposed direction that the Form_mode_routing module is going too. But to see a working solution based on routing and permissions in core would be good.

woprrr’s picture

@kenton.r you will love form mode manager then ;) lot of old user of br and form mode routing have migrated here.

Actually we need a standard in routing, form mode manager try to purpose that and work hard to provide a solution that match whit all usages. Actually we can be compatible with every entities and provide also lot of feature like br.

vacho’s picture

Issue tags: +Needs reroll
vacho’s picture

Version: 8.6.x-dev » 8.8.x-dev
Issue tags: -Needs reroll

Version: 8.8.x-dev » 8.9.x-dev

Drupal 8.8.0-alpha1 will be released the week of October 14th, 2019, which means new developments and disruptive changes should now be targeted against the 8.9.x-dev branch. (Any changes to 8.9.x will also be committed to 9.0.x in preparation for Drupal 9’s release, but some changes like significant feature additions will be deferred to 9.1.x.). For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 8.9.x-dev » 9.1.x-dev

Drupal 8.9.0-beta1 was released on March 20, 2020. 8.9.x is the final, long-term support (LTS) minor release of Drupal 8, which means new developments and disruptive changes should now be targeted against the 9.1.x-dev branch. For more information see the Drupal 8 and 9 minor version schedule and the Allowed changes during the Drupal 8 and 9 release cycles.

Version: 9.1.x-dev » 9.2.x-dev

Drupal 9.1.0-alpha1 will be released the week of October 19, 2020, which means new developments and disruptive changes should now be targeted for the 9.2.x-dev branch. For more information see the Drupal 9 minor version schedule and the Allowed changes during the Drupal 9 release cycle.

pcambra’s picture

Not sure if mentioned already but this is what Commerce uses (thanks @facine for the tip)

$form_display = EntityFormDisplay::collectRenderDisplay($entity, 'form_mode');
$form_display->buildForm($entity, $form, $form_state);

Btw seems core uses collectRenderDisplay with both form mode and operation because there's a fallback, it could be standardized a little bit?

Version: 9.2.x-dev » 9.3.x-dev

Drupal 9.2.0-alpha1 will be released the week of May 3, 2021, which means new developments and disruptive changes should now be targeted for the 9.3.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.3.x-dev » 9.4.x-dev

Drupal 9.3.0-rc1 was released on November 26, 2021, which means new developments and disruptive changes should now be targeted for the 9.4.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

Version: 9.4.x-dev » 9.5.x-dev

Drupal 9.4.0-alpha1 was released on May 6, 2022, which means new developments and disruptive changes should now be targeted for the 9.5.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

ady1503 made their first commit to this issue’s fork.

ady1503’s picture

Hello. In the end, is there the option that the control of the modes works? functional example? Thanks.

Version: 9.5.x-dev » 10.1.x-dev

Drupal 9.5.0-beta2 and Drupal 10.0.0-beta2 were released on September 29, 2022, which means new developments and disruptive changes should now be targeted for the 10.1.x-dev branch. For more information see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

smustgrave’s picture

This could use an issue summary update about the proposed solution.

smustgrave’s picture

Status: Needs review » Needs work

Should of moved it to NW 2 months ago sorry.

pooja saraah’s picture

Fixed failed commands on #43
Attached patch against Drupal 10.1.x
Attached reroll patch

Prem Suthar’s picture

Fixed The Custom CMD Failed Patch Of #57

Prem Suthar’s picture

Status: Needs work » Needs review
joachim’s picture

Status: Needs review » Needs work
Issue tags: +Needs change record
+++ b/core/lib/Drupal/Core/Entity/EntityTypeManager.php
@@ -202,9 +202,12 @@ public function getListBuilder($entity_type_id) {
+  public function getFormObject($entity_type, $operation, $form_class = NULL) {

New parameters on both functions need to be documented!!!!!!!

Also, why change the name of $entity_type_id?

Prem Suthar’s picture

Reroll the Patch as per Suggestion of #60.

Prem Suthar’s picture

Status: Needs work » Needs review
smustgrave’s picture

Status: Needs review » Needs work

@Prem Suthar please read the comments and tags.

This was tagged for IS update and a change record and question in #60

Also upload an interdiff with patches please

Version: 10.1.x-dev » 11.x-dev

Drupal core is moving towards using a “main” branch. As an interim step, a new 11.x branch has been opened, as Drupal.org infrastructure cannot currently fully support a branch named main. New developments and disruptive changes should now be targeted for the 11.x branch, which currently accepts only minor-version allowed changes. For more information, see the Drupal core minor version schedule and the Allowed changes during the Drupal core release cycle.

earthangelconsulting’s picture

i just want to add some confirmation, for the benefit of those who have found this page while trying to use form modes from custom code (rather than anything to do with actual code changes to Core)

those modules form_mode_control and form_mode_manager may be very handy, but if you are just trying to generate a node form from php, with an alternate (but already defined) form mode for that node type, then ALL you need is what is mentioned in #13 ! thanks, @dench0 that was very helpful!

i tried this in Drupal 9.4.15 and it still works just fine :-)

ady1503’s picture

@earthangelconsulting

Can you show an real example?

Where did did you implement the code.

Thanks

Gracias

earthangelconsulting’s picture

foo_posting is the machine name of a node type
foo_specialform is the machine name of a custom form mode, for nodes of type foo_posting
foomodule is the module that handles this

this is in the src/FooController.php script, within foomodule: (note that this use case is for a path that calls a node/add form, using form mode foo_posting ... if you need to edit existing nodes, it would be a bit different)

namespace Drupal\foomodule\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\node\Entity\Node;

class FooController extends ControllerBase {

  /**
   * Function to call the Foo Posting form
   *
   * @return array
   *   A renderable array
   */
  public function postFoo() {
  
    $node = Node::create(array(
    'type' => 'foo_posting',
    ));
	
    $form = \Drupal::service('entity.form_builder')->getForm($node, 'foo_specialform');  
    
    return [
      'form' => $form
    ];
  }

}

this is in foomodule.routing.yml (nothing out of the ordinary here! )

foomodule.fooposting:
  path: '/foo-posting'
  defaults:
    _controller: 'Drupal\foomodule\Controller\FooController::postFoo'
    _title: 'Post an instance of Foo'
  requirements:
    _access: 'TRUE'

and this is part of foomodule.module

function foomodule_entity_type_build(array &$entity_types) {
  $entity_types['node']->setFormClass('foo_specialform', 'Drupal\node\NodeForm');
}

there are definitely other ways to do this, eg: https://www.webomelette.com/how-switch-out-entity-form-mode-dynamically-... https://www.drupal.org/docs/drupal-apis/entity-api/how-to-create-an-enti... this is just one of them.

ady1503’s picture

@earthangelconsulting

Thank you so much.

Gracias