diff --git a/islandora.routing.yml b/islandora.routing.yml
index 9215a360..e2cb7d35 100644
--- a/islandora.routing.yml
+++ b/islandora.routing.yml
@@ -37,16 +37,6 @@ islandora.add_member_to_node_page:
     _entity_create_any_access: 'node'
 
 islandora.upload_children:
-  path: '/node/{node}/members/upload_old'
-  defaults:
-    _form: '\Drupal\islandora\Form\AddChildrenForm'
-    _title: 'Upload Children'
-  options:
-    _admin_route: 'TRUE'
-  requirements:
-    _custom_access: '\Drupal\islandora\Form\AddChildrenForm::access'
-
-islandora.upload_children_wizard:
   path: '/node/{node}/members/upload/{step}'
   defaults:
     _wizard: '\Drupal\islandora\Form\AddChildrenWizard\Form'
@@ -55,8 +45,7 @@ islandora.upload_children_wizard:
   options:
     _admin_route: 'TRUE'
   requirements:
-    #_custom_access: '\Drupal\islandora\Form\AddChildrenWizard\Form::access'
-    _custom_access: '\Drupal\islandora\Form\AddChildrenForm::access'
+    _custom_access: '\Drupal\islandora\Form\AddChildrenWizard\Access::checkAccess'
 
 islandora.add_media_to_node_page:
   path: '/node/{node}/media/add'
diff --git a/src/Form/AddChildrenForm.php b/src/Form/AddChildrenForm.php
index 528b4283..adad9dae 100644
--- a/src/Form/AddChildrenForm.php
+++ b/src/Form/AddChildrenForm.php
@@ -12,6 +12,8 @@ use Symfony\Component\HttpKernel\Exception\HttpException;
 
 /**
  * Form that lets users upload one or more files as children to a resource node.
+ *
+ * @deprecated Replaced with the "wizard" appraach.
  */
 class AddChildrenForm extends AddMediaForm {
 
diff --git a/src/Form/AddChildrenWizard/Access.php b/src/Form/AddChildrenWizard/Access.php
new file mode 100644
index 00000000..2a5cdbe2
--- /dev/null
+++ b/src/Form/AddChildrenWizard/Access.php
@@ -0,0 +1,63 @@
+<?php
+
+namespace Drupal\islandora\Form\AddChildrenWizard;
+
+use Drupal\Core\Access\AccessResult;
+use Drupal\Core\Access\AccessResultInterface;
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\Routing\RouteMatch;
+use Drupal\islandora\IslandoraUtils;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Access checker.
+ *
+ * The _wizard/_form route enhancers do not really allow for access checking
+ * things, so let's roll it separately for now.
+ */
+class Access implements ContainerInjectionInterface {
+
+  /**
+   * The Islandora utils service.
+   *
+   * @var \Drupal\islandora\IslandoraUtils
+   */
+  protected IslandoraUtils $utils;
+
+  /**
+   * Constructor.
+   */
+  public function __construct(IslandoraUtils $utils) {
+    $this->utils = $utils;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) : self {
+    return new static(
+      $container->get('islandora.utils')
+    );
+  }
+
+  /**
+   * Check if the user can create any "Islandora" nodes and media.
+   *
+   * @param \Drupal\Core\Routing\RouteMatch $route_match
+   *   The current routing match.
+   *
+   * @return \Drupal\Core\Access\AccessResultInterface
+   *   Whether we can or cannot show the "thing".
+   */
+  public function checkAccess(RouteMatch $route_match) : AccessResultInterface {
+    $can_create_media = $this->utils->canCreateIslandoraEntity('media', 'media_type');
+    $can_create_node = $this->utils->canCreateIslandoraEntity('node', 'node_type');
+
+    if ($can_create_media && $can_create_node) {
+      return AccessResult::allowed();
+    }
+
+    return AccessResult::forbidden();
+  }
+
+}
diff --git a/src/Form/AddChildrenWizard/FileSelectionForm.php b/src/Form/AddChildrenWizard/FileSelectionForm.php
index 5fb29c43..8d29bab3 100644
--- a/src/Form/AddChildrenWizard/FileSelectionForm.php
+++ b/src/Form/AddChildrenWizard/FileSelectionForm.php
@@ -7,48 +7,66 @@ use Drupal\Core\Batch\BatchBuilder;
 use Drupal\Core\Database\Connection;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
-use Drupal\Core\Field\Entity\BaseFieldOverride;
 use Drupal\Core\Field\FieldDefinitionInterface;
 use Drupal\Core\Field\FieldItemList;
 use Drupal\Core\Field\FieldStorageDefinitionInterface;
 use Drupal\Core\Field\WidgetInterface;
-use Drupal\Core\Field\WidgetPluginManager;
 use Drupal\Core\Form\FormBase;
-use Drupal\Core\Form\FormState;
 use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Queue\QueueFactory;
-use Drupal\Core\Queue\QueueInterface;
 use Drupal\Core\Session\AccountProxyInterface;
 use Drupal\Core\Url;
-use Drupal\file\FileInterface;
 use Drupal\islandora\IslandoraUtils;
-use Drupal\media\MediaInterface;
-use Drupal\media\MediaSourceInterface;
 use Drupal\media\MediaTypeInterface;
 use Drupal\node\NodeInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
 use Symfony\Component\HttpKernel\Exception\HttpException;
 use Symfony\Component\HttpKernel\Exception\HttpExceptionInterface;
 
+/**
+ * Children addition wizard's second step.
+ */
 class FileSelectionForm extends FormBase {
 
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface|null
+   */
   protected ?EntityTypeManagerInterface $entityTypeManager;
 
   /**
    * The widget plugin manager service.
    *
-   * @var WidgetPluginManager
+   * @var \Drupal\Core\Field\WidgetPluginManager|null
    */
   protected ?PluginManagerInterface $widgetPluginManager;
 
+  /**
+   * The entity field manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityFieldManagerInterface|null
+   */
   protected ?EntityFieldManagerInterface $entityFieldManager;
 
+  /**
+   * The database connection serivce.
+   *
+   * @var \Drupal\Core\Database\Connection|null
+   */
   protected ?Connection $database;
 
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface|null
+   */
   protected ?AccountProxyInterface $currentUser;
 
+  /**
+   * {@inheritdoc}
+   */
   public static function create(ContainerInterface $container): self {
-    $instance =  parent::create($container);
+    $instance = parent::create($container);
 
     $instance->entityTypeManager = $container->get('entity_type.manager');
     $instance->widgetPluginManager = $container->get('plugin.manager.field.widget');
@@ -59,20 +77,57 @@ class FileSelectionForm extends FormBase {
     return $instance;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getFormId() {
     return 'islandora_add_children_wizard_file_selection';
   }
 
-  protected function getMediaType(FormStateInterface $form_state) : MediaTypeInterface {
+  /**
+   * Helper; get the media type, based off discovering from form state.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   *
+   * @return \Drupal\media\MediaTypeInterface
+   *   The target media type.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
+  protected function getMediaType(FormStateInterface $form_state): MediaTypeInterface {
     return $this->doGetMediaType($form_state->getTemporaryValue('wizard'));
   }
 
-  protected function doGetMediaType(array $values) : MediaTypeInterface {
-    /** @var MediaTypeInterface $media_type */
-    return  $this->entityTypeManager->getStorage('media_type')->load($values['media_type']);
+  /**
+   * Helper; get media type, given our required values.
+   *
+   * @param array $values
+   *   An associative array which must contain at least:
+   *   - media_type: The machine name of the media type to load.
+   *
+   * @return \Drupal\media\MediaTypeInterface
+   *   The loaded media type.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
+  protected function doGetMediaType(array $values): MediaTypeInterface {
+    /** @var \Drupal\media\MediaTypeInterface $media_type */
+    return $this->entityTypeManager->getStorage('media_type')->load($values['media_type']);
   }
 
-  protected function getField(FormStateInterface $form_state) : FieldDefinitionInterface {
+  /**
+   * Helper; get field instance, based off discovering from form state.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   *
+   * @return \Drupal\Core\Field\FieldDefinitionInterface
+   *   The field definition.
+   */
+  protected function getField(FormStateInterface $form_state): FieldDefinitionInterface {
     $cached_values = $form_state->getTemporaryValue('wizard');
 
     $field = $this->doGetField($cached_values);
@@ -81,23 +136,49 @@ class FileSelectionForm extends FormBase {
     return $field;
   }
 
-  protected function doGetField(array $values) : FieldDefinitionInterface {
+  /**
+   * Helper; get field instance, given our required values.
+   *
+   * @param array $values
+   *   See ::doGetMediaType() for which values are required.
+   *
+   * @return \Drupal\Core\Field\FieldDefinitionInterface
+   *   The target field.
+   */
+  protected function doGetField(array $values): FieldDefinitionInterface {
     $media_type = $this->doGetMediaType($values);
     $media_source = $media_type->getSource();
     $source_field = $media_source->getSourceFieldDefinition($media_type);
 
     $fields = $this->entityFieldManager->getFieldDefinitions('media', $media_type->id());
 
-    return isset($fields[$source_field->getFieldStorageDefinition()->getName()]) ?
-      $fields[$source_field->getFieldStorageDefinition()->getName()] :
+    return $fields[$source_field->getFieldStorageDefinition()->getName()] ??
       $media_source->createSourceField();
   }
 
-  protected function getWidget(FormStateInterface $form_state) : WidgetInterface {
+  /**
+   * Helper; get widget for the field, based on discovering from form state.
+   *
+   * @param \Drupal\Core\Form\FormStateInterface $form_state
+   *   The form state.
+   *
+   * @return \Drupal\Core\Field\WidgetInterface
+   *   The widget.
+   */
+  protected function getWidget(FormStateInterface $form_state): WidgetInterface {
     return $this->doGetWidget($this->getField($form_state));
   }
 
-  protected function doGetWidget(FieldDefinitionInterface $field) : WidgetInterface {
+  /**
+   * Helper; get the base widget for the given field.
+   *
+   * @param \Drupal\Core\Field\FieldDefinitionInterface $field
+   *   The field for which get obtain the widget.
+   *
+   * @return \Drupal\Core\Field\WidgetInterface
+   *   The widget.
+   */
+  protected function doGetWidget(FieldDefinitionInterface $field): WidgetInterface {
     return $this->widgetPluginManager->getInstance([
       'field_definition' => $field,
       'form_mode' => 'default',
@@ -105,11 +186,13 @@ class FileSelectionForm extends FormBase {
     ]);
   }
 
-  public function buildForm(array $form, FormStateInterface $form_state) : array {
-    // TODO: Using the media type selected in the previous step, grab the
+  /**
+   * {@inheritdoc}
+   */
+  public function buildForm(array $form, FormStateInterface $form_state): array {
+    // Using the media type selected in the previous step, grab the
     // media bundle's "source" field, and create a multi-file upload widget
     // for it, with the same kind of constraints.
-
     $field = $this->getField($form_state);
     $items = FieldItemList::createInstance($field, $field->getName(), $this->getMediaType($form_state)->getTypedData());
 
@@ -131,11 +214,6 @@ class FileSelectionForm extends FormBase {
   public function submitForm(array &$form, FormStateInterface $form_state) {
     $cached_values = $form_state->getTemporaryValue('wizard');
 
-    dsm($form);
-    dsm($form_state);
-    dsm($this->doGetField($cached_values));
-    dsm($this->doGetField($cached_values)->getName());
-
     $widget = $this->getWidget($form_state);
     $builder = (new BatchBuilder())
       ->setTitle($this->t('Creating children...'))
@@ -143,24 +221,26 @@ class FileSelectionForm extends FormBase {
       ->setFinishCallback([$this, 'batchProcessFinished']);
     $values = $form_state->getValue($this->doGetField($cached_values)->getName());
     $massaged_values = $widget->massageFormValues($values, $form, $form_state);
-    dsm($values);
-    dsm($massaged_values);
     foreach ($massaged_values as $delta => $file) {
-      dsm($file);
-      $builder->addOperation([$this, 'batchProcess'], [$delta, $file, $form, $form_state, $cached_values]);
+      $builder->addOperation(
+        [$this, 'batchProcess'],
+        [$delta, $file, $cached_values]
+      );
     }
     batch_set($builder->toArray());
     $form_state->setRedirectUrl(Url::fromUri("internal:/node/{$cached_values['node']}/members"));
   }
 
-  public function batchProcess($delta, $info, array $form, FormStateInterface $form_state, array $values, &$context) {
-    $transaction = \Drupal::database()->startTransaction();
+  /**
+   * Implements callback_batch_operation() for our child addition batch.
+   */
+  public function batchProcess($delta, $info, array $values, &$context) {
+    $transaction = $this->database->startTransaction();
 
     try {
       $taxonomy_term_storage = $this->entityTypeManager->getStorage('taxonomy_term');
 
-      dsm(func_get_args());
-      /** @var FileInterface $file */
+      /** @var \Drupal\file\FileInterface $file */
       $file = $this->entityTypeManager->getStorage('file')->load($info['target_id']);
       $file->setPermanent();
       if ($file->save() !== SAVED_UPDATED) {
@@ -170,36 +250,35 @@ class FileSelectionForm extends FormBase {
       $node_storage = $this->entityTypeManager->getStorage('node');
       $parent = $node_storage->load($values['node']);
 
-      // Create a node (with the filename?) (and also belonging to the target node).
+      // Create a node (with the filename?) (and also belonging to the target
+      // node).
+      /** @var \Drupal\node\NodeInterface $node */
       $node = $node_storage->create([
         'type' => $values['bundle'],
         'title' => $file->getFilename(),
         IslandoraUtils::MEMBER_OF_FIELD => $parent,
         'uid' => $this->currentUser->id(),
         'status' => NodeInterface::PUBLISHED,
-        IslandoraUtils::MODEL_FIELD => $values['model'] ?
+        IslandoraUtils::MODEL_FIELD => ($values['model'] ?
           $taxonomy_term_storage->load($values['model']) :
-          NULL,
+          NULL),
       ]);
+
       if ($node->save() !== SAVED_NEW) {
         throw new \Exception("Failed to create node for file '{$file->id()}'.");
       }
 
       // Create a media with the file attached and also pointing at the node.
       $field = $this->doGetField($values);
-      $widget = $this->doGetWidget($field);
-      $items = FieldItemList::createInstance($field, $field->getName(), $this->getMediaType($form_state)->getTypedData());
-      $items->setValue([0 => $info]);
-      //$items->setValue([$delta => $info]);
 
       $media_values = array_merge(
         [
           'bundle' => $values['media_type'],
           'name' => $file->getFilename(),
           IslandoraUtils::MEDIA_OF_FIELD => $node,
-          IslandoraUtils::MEDIA_USAGE_FIELD => $values['use'] ?
+          IslandoraUtils::MEDIA_USAGE_FIELD => ($values['use'] ?
             $taxonomy_term_storage->loadMultiple($values['use']) :
-            NULL,
+            NULL),
           'uid' => $this->currentUser->id(),
           // XXX: Published... no constant?
           'status' => 1,
@@ -210,11 +289,19 @@ class FileSelectionForm extends FormBase {
           ],
         ]
       );
-      dsm($media_values);
       $media = $this->entityTypeManager->getStorage('media')->create($media_values);
       if ($media->save() !== SAVED_NEW) {
         throw new \Exception("Failed to create media for file '{$file->id()}.");
       }
+
+      $context['results'] = array_merge_recursive($context['results'], [
+        'validation_violations' => $this->validationClassification([
+          $file,
+          $media,
+          $node,
+        ]),
+      ]);
+      $context['results']['count'] += 1;
     }
     catch (HttpExceptionInterface $e) {
       $transaction->rollBack();
@@ -226,8 +313,52 @@ class FileSelectionForm extends FormBase {
     }
   }
 
-  public function batchProcessFinished() {
-    // TODO: Dump out status message of some sort?
+  /**
+   * @param array $entities
+   *
+   * @return array
+   */
+  protected function validationClassification(array $entities) {
+    $violations = [];
+
+    foreach ($entities as $entity) {
+      $entity_violations = $entity->validate();
+      if ($entity_violations->count() > 0) {
+        $violations[$entity->getEntityTypeId()][$entity->id()] = $entity_violations->count();
+      }
+    }
+
+    return $violations;
+  }
+
+  /**
+   * Implements callback_batch_finished() for our child addition batch.
+   */
+  public function batchProcessFinished($success, $results, $operations): void {
+    if ($success) {
+      $this->messenger()->addMessage($this->formatPlural(
+        $results['count'],
+        'Added 1 child node.',
+        'Added @count child nodes.'
+      ));
+      foreach ($results['validation_violations'] ?? [] as $entity_type => $info) {
+        foreach ($info as $id => $count) {
+          $this->messenger()->addWarning($this->formatPlural(
+            $count,
+            '1 validation error present in <a href=":uri">bulk created entity of type %type, with ID %id</a>.',
+            '@count validation errors present in <a href=":uri">bulk created entity of type %type, with ID %id</a>.',
+            [
+              '%type' => $entity_type,
+              ':uri' => Url::fromRoute("entity.{$entity_type}.canonical", [$entity_type => $id])->toString(),
+              '%id' => $id,
+            ]
+          ));
+        }
+      }
+    }
+    else {
+      $this->messenger()->addError($this->t('Encountered an error when adding children.'));
+    }
   }
 
 }
diff --git a/src/Form/AddChildrenWizard/Form.php b/src/Form/AddChildrenWizard/Form.php
index bd2b92ae..68489f18 100644
--- a/src/Form/AddChildrenWizard/Form.php
+++ b/src/Form/AddChildrenWizard/Form.php
@@ -5,8 +5,6 @@ namespace Drupal\islandora\Form\AddChildrenWizard;
 use Drupal\Core\Access\AccessResult;
 use Drupal\Core\DependencyInjection\ClassResolverInterface;
 use Drupal\Core\Form\FormBuilderInterface;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\Render\RendererInterface;
 use Drupal\Core\Routing\RouteMatch;
 use Drupal\Core\Routing\RouteMatchInterface;
 use Drupal\Core\Session\AccountProxyInterface;
@@ -14,14 +12,38 @@ use Drupal\Core\TempStore\SharedTempStoreFactory;
 use Drupal\ctools\Wizard\FormWizardBase;
 use Drupal\islandora\IslandoraUtils;
 use Symfony\Component\EventDispatcher\EventDispatcherInterface;
-use Symfony\Component\HttpFoundation\Request;
-use Symfony\Component\HttpFoundation\RequestStack;
 
+/**
+ * Bulk children addition wizard base form.
+ */
 class Form extends FormWizardBase {
 
+  /**
+   * The Islandora Utils service.
+   *
+   * @var \Drupal\islandora\IslandoraUtils
+   */
   protected IslandoraUtils $utils;
+
+  /**
+   * The current node ID.
+   *
+   * @var string|mixed|null
+   */
   protected string $nodeId;
+
+  /**
+   * The current route match.
+   *
+   * @var \Drupal\Core\Routing\RouteMatchInterface
+   */
   protected RouteMatchInterface $currentRoute;
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountProxyInterface
+   */
   protected AccountProxyInterface $currentUser;
 
   /**
@@ -58,7 +80,6 @@ class Form extends FormWizardBase {
       [
         'utils' => \Drupal::service('islandora.utils'),
         'tempstore_id' => 'islandora.upload_children',
-        //'machine_name' => 'islandora_add_children_wizard',
         'current_route_match' => \Drupal::service('current_route_match'),
         'current_user' => \Drupal::service('current_user'),
       ]
@@ -79,35 +100,38 @@ class Form extends FormWizardBase {
    * {@inheritdoc}
    */
   public function getOperations($cached_values) {
-    return [
-      'child_type' => [
-        'title' => $this->t('Type of children'),
-        'form' => TypeSelectionForm::class,
-        'values' => [
-          'node' => $this->nodeId,
-        ]
+    $ops = [];
+
+    $ops['child_type'] = [
+      'title' => $this->t('Type of children'),
+      'form' => TypeSelectionForm::class,
+      'values' => [
+        'node' => $this->nodeId,
+      ],
+    ];
+    $ops['child_files'] = [
+      'title' => $this->t('Files for children'),
+      'form' => FileSelectionForm::class,
+      'values' => [
+        'node' => $this->nodeId,
       ],
-      'child_files' => [
-        'title' => $this->t('Files for children'),
-        'form' => FileSelectionForm::class,
-        'values' => [
-          'node' => $this->nodeId,
-        ]
-      ]
     ];
+
+    return $ops;
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getNextParameters($cached_values) {
     return parent::getNextParameters($cached_values) + ['node' => $this->nodeId];
   }
 
+  /**
+   * {@inheritdoc}
+   */
   public function getPreviousParameters($cached_values) {
     return parent::getPreviousParameters($cached_values) + ['node' => $this->nodeId];
   }
 
-  public function finish(array &$form, FormStateInterface $form_state) {
-    parent::finish($form, $form_state); // TODO: Change the autogenerated stub
-    dsm($form_state->getTemporaryValue('wizard'));
-  }
-
 }
diff --git a/src/Form/AddChildrenWizard/TypeSelectionForm.php b/src/Form/AddChildrenWizard/TypeSelectionForm.php
index fffb2ae9..68237711 100644
--- a/src/Form/AddChildrenWizard/TypeSelectionForm.php
+++ b/src/Form/AddChildrenWizard/TypeSelectionForm.php
@@ -3,25 +3,50 @@
 namespace Drupal\islandora\Form\AddChildrenWizard;
 
 use Drupal\Core\Cache\CacheableMetadata;
-use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
 use Drupal\Core\Entity\EntityFieldManagerInterface;
 use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
 use Drupal\Core\Entity\EntityTypeManagerInterface;
 use Drupal\Core\Form\FormBase;
 use Drupal\Core\Form\FormStateInterface;
 use Drupal\islandora\IslandoraUtils;
-use Drupal\taxonomy\TermInterface;
 use Symfony\Component\DependencyInjection\ContainerInterface;
-use function Symfony\Component\DependencyInjection\Loader\Configurator\iterator;
 
+/**
+ * Children addition wizard's first step.
+ */
 class TypeSelectionForm extends FormBase {
 
+  /**
+   * Cacheable metadata that is instantiated and used internally.
+   *
+   * @var \Drupal\Core\Cache\CacheableMetadata|null
+   */
   protected ?CacheableMetadata $cacheableMetadata = NULL;
+
+  /**
+   * The entity type bundle info service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeBundleInfoInterface|null
+   */
   protected ?EntityTypeBundleInfoInterface $entityTypeBundleInfo;
+
+  /**
+   * The entity type manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityTypeManagerInterface|null
+   */
   protected ?EntityTypeManagerInterface $entityTypeManager;
-  protected ?EntityFieldManagerInterface $entityFieldManager;
 
+  /**
+   * The entity field manager service.
+   *
+   * @var \Drupal\Core\Entity\EntityFieldManagerInterface|null
+   */
+  protected ?EntityFieldManagerInterface $entityFieldManager;
 
+  /**
+   * {@inheritdoc}
+   */
   public static function create(ContainerInterface $container) {
     $instance = parent::create($container);
 
@@ -39,14 +64,33 @@ class TypeSelectionForm extends FormBase {
     return 'islandora_add_children_type_selection';
   }
 
+  /**
+   * Memoization for ::getNodeBundleOptions().
+   *
+   * @var array|null
+   */
   protected ?array $nodeBundleOptions = NULL;
+
+  /**
+   * Indicate presence of model field on node bundles.
+   *
+   * Populated as a side effect of ::getNodeBundleOptions().
+   *
+   * @var array|null
+   */
   protected ?array $nodeBundleHasModelField = NULL;
-  //protected ?array $nodeBundleHasMemberOfField = NULL;
+
+  /**
+   * Helper; get the node bundle options available to the current user.
+   *
+   * @return array
+   *   An associative array mapping node bundle machine names to their human-
+   *   readable labels.
+   */
   protected function getNodeBundleOptions() : array {
     if ($this->nodeBundleOptions === NULL) {
       $this->nodeBundleOptions = [];
       $this->nodeBundleHasModelField = [];
-      //$this->nodeBundleHasMemberOfField = [];
 
       $access_handler = $this->entityTypeManager->getAccessControlHandler('node');
       foreach ($this->entityTypeBundleInfo->getBundleInfo('node') as $bundle => $info) {
@@ -62,7 +106,6 @@ class TypeSelectionForm extends FormBase {
         }
         $this->nodeBundleOptions[$bundle] = $info['label'];
         $fields = $this->entityFieldManager->getFieldDefinitions('node', $bundle);
-        //$this->nodeBundleHasMemberOfField[$bundle] = array_key_exists(IslandoraUtils::MEMBER_OF_FIELD, $fields);
         $this->nodeBundleHasModelField[$bundle] = array_key_exists(IslandoraUtils::MODEL_FIELD, $fields);
       }
     }
@@ -70,7 +113,16 @@ class TypeSelectionForm extends FormBase {
     return $this->nodeBundleOptions;
   }
 
-  protected function getModelOptions() : \Traversable {
+  /**
+   * Generates a mapping of taxonomy term IDs to their names.
+   *
+   * @return \Generator
+   *   The mapping of taxonomy term IDs to their names.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
+  protected function getModelOptions() : \Generator {
     $terms = $this->entityTypeManager->getStorage('taxonomy_term')
       ->loadTree('islandora_models', 0, NULL, TRUE);
     foreach ($terms as $term) {
@@ -78,15 +130,43 @@ class TypeSelectionForm extends FormBase {
     }
   }
 
-  protected function mapModelStates() : \Traversable {
+  /**
+   * Helper; map node bundles supporting the "has model" field, for #states.
+   *
+   * @return \Generator
+   *   Yields associative array mapping the string 'value' to the bundles which
+   *   have the given field.
+   */
+  protected function mapModelStates() : \Generator {
     $this->getNodeBundleOptions();
     foreach (array_keys(array_filter($this->nodeBundleHasModelField)) as $bundle) {
       yield ['value' => $bundle];
     }
   }
 
+  /**
+   * Memoization for ::getMediaBundleOptions().
+   *
+   * @var array|null
+   */
   protected ?array $mediaBundleOptions = NULL;
+
+  /**
+   * Indicate presence of usage field on media bundles.
+   *
+   * Populated as a side effect in ::getMediaBundleOptions().
+   *
+   * @var array|null
+   */
   protected ?array $mediaBundleUsageField = NULL;
+
+  /**
+   * Helper; get options for media types.
+   *
+   * @return array
+   *   An associative array mapping the machine name of the media type to its
+   *   human-readable label.
+   */
   protected function getMediaBundleOptions() : array {
     if ($this->mediaBundleOptions === NULL) {
       $this->mediaBundleOptions = [];
@@ -113,16 +193,33 @@ class TypeSelectionForm extends FormBase {
     return $this->mediaBundleOptions;
   }
 
+  /**
+   * Helper; list the terms of the "islandora_media_use" vocabulary.
+   *
+   * @return \Generator
+   *   Generates term IDs as keys mapping to term names.
+   *
+   * @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
+   * @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
+   */
   protected function getMediaUseOptions() {
-    /** @var TermInterface[] $terms */
-    $terms =  $this->entityTypeManager->getStorage('taxonomy_term')
+    /** @var \Drupal\taxonomy\TermInterface[] $terms */
+    $terms = $this->entityTypeManager->getStorage('taxonomy_term')
       ->loadTree('islandora_media_use', 0, NULL, TRUE);
 
     foreach ($terms as $term) {
       yield $term->id() => $term->getName();
     }
   }
-  protected function mapUseStates() {
+
+  /**
+   * Helper; map media types supporting the usage field for use with #states.
+   *
+   * @return \Generator
+   *   Yields associative array mapping the string 'value' to the bundles which
+   *   have the given field.
+   */
+  protected function mapUseStates(): \Generator {
     $this->getMediaBundleOptions();
     foreach (array_keys(array_filter($this->mediaBundleUsageField)) as $bundle) {
       yield ['value' => $bundle];
@@ -165,7 +262,7 @@ class TypeSelectionForm extends FormBase {
         'required' => [
           ':input[name="bundle"]' => $model_states,
         ],
-      ]
+      ],
     ];
     $form['media_type'] = [
       '#type' => 'select',