I got an example working at least to the point where a form is viewed. But there are still lots of issues, like the AJAX in the form not working and also the Next/Prev buttons do nothing. If someone has a really working example I would be happy for a reference.

My current version can be found at https://github.com/marcusx/ct_wizard_content_entity_example

Original Problem Description

I want to build a multistep form with content entity forms using the ctools wizard API. In addition to the normal process of adding a new entity with the default add/edit form (with is very complex and suitable for admins only), an additional route shall display variants of the edit form in multiple steps.

So my-entity/add/my-bundle shows the normal add/edit form. And my-entity/wizard/my-bundle should display the first step of the wizard with a simplified version of the my-entity edit form.

As far I can see from the ctools_wizard_test module See:(ctools_wizard_test code) this involves the following tasks:

  • Implement a wizard form class by extending EntityFormWizardBase.
  • Add wizard annotation to the entity class.
  • Add routing for the wizard form.
  • Add forms for each step in the wizard and reference them in the $steps array returned by getOperations in my wizard class.

My implementation is working till the point where the WizardFactory is building the content entity form. Here I get lots of errors because the $entity on the entity form is not set. On regular content entity forms this gets set in \Drupal\Core\Entity\HtmlEntityFormController::getFormObject. As wizard forms bring their own controller this doesn't happen.

Where is the appropriate place to set the entity in the form class?

  • We have the entity in the wizard class but there seems no way to pass it on to the form properly.
  • It gets added to the $form_state in \Drupal\ctools\Wizard\WizardFactory::getFormState where you could theoretically get it in the form class from $form_state->getTemporaryValue.
  • Whatever method of the entity form I overwrite to call $this->setEntity() it seems always too late. I get sooner or later a Fatal error: Call to a member function whatever on null as the entity is not set early enough.

Entity Annotation

 *     "wizard" = {
 *       "add" = "Drupal\my_custom_entity\Wizard\MyEntityAddWizard",
 *     },

My Wizard Class:

namespace Drupal\my_custom_entity\Wizard;

use Drupal\ctools\Wizard\EntityFormWizardBase;
use Drupal\ctools\Event\WizardEvent;
use Drupal\ctools\Wizard\FormWizardInterface;

class MyEntityAddWizard extends EntityFormWizardBase {

   * The entity.
   * @var \Drupal\my_custom_entity\Entity\MyEntityInterface
  public $entity;

   * {@inheritdoc}
  public function getWizardLabel() {
    return $this->t('My Entity');

   * {@inheritdoc}
  public function getMachineLabel() {
    return $this->t('Label');

   * {@inheritdoc}
  public function getEntityType() {
    return 'my_entity';

   * {@inheritdoc}
  public function exists() {
    return '\Drupal\my_custom_entity\Entity\MyEntity::load';

   * {@inheritdoc}
  public function initValues() {
    $storage = $this->entityManager->getStorage($this->getEntityType());

    $content_entity_type = $this->routeMatch->getParameter('my_entity_type');
    $entity = $storage->create(['type' => $content_entity_type->id()]);
    $values[$this->getEntityType()] = $entity;
    $this->entity = $entity;

    $event = new WizardEvent($this, $values);
    $this->dispatcher->dispatch(FormWizardInterface::LOAD_VALUES, $event);
    return $event->getValues();

   * {@inheritdoc}
  public function getOperations($cached_values) {

    $steps = [
      'create' => [
        'form' => 'Drupal\my_custom_entity\Form\MyEntityWizardForm',
        'title' => $this->t('Create'),
      'content' => [
        'form' => 'Drupal\my_custom_entity\Form\MyEntityForm',
        'title' => $this->t('Content'),

    return $steps;

My Form for the first wizard step:

namespace Drupal\my_custom_entity\Form;

use Drupal\Core\Entity\ContentEntityForm;
use Drupal\Core\Form\FormStateInterface;

 * Form controller for MyEntity edit forms.
 * @ingroup my_custom_entity
class MyEntityWizardForm extends MyEntityForm {

   * Initialize the form state and the entity before the first form build.
  protected function init(FormStateInterface $form_state) {
    /* @var $entity \Drupal\my_custom_entity\Entity\MyEntity */
    $entity = $form_state->getTemporaryValue('wizard')['my_entity'];



  path: '/my-entity/wizard/{my_entity_type}'
    _entity_wizard: 'my_entity.add'
    _title: 'Add My Entity'
    tempstore_id: 'my_custom_entity.my_entity'
    _permission: 'administer site configuration'
        type: entity:my_entity_type
  • I am looking for the same solution. Were you able to resolve your issue? – Sukhjinder Singh Jan 24 '18 at 13:50

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.