+
+/**
+ * Implements hook_field_ui_preconfigured_options_alter().
+ */
+function media_field_ui_preconfigured_options_alter(array &$options, $field_type) {
+ // If the field is not an "entity_reference"-based field, bail out.
+ /** @var \Drupal\Core\Field\FieldTypePluginManager $field_type_manager */
+ $field_type_manager = \Drupal::service('plugin.manager.field.field_type');
+ $class = $field_type_manager->getPluginClass($field_type);
+ if (!is_a($class, 'Drupal\Core\Field\Plugin\Field\FieldType\EntityReferenceItem', TRUE)) {
+ return;
+ }
+
+ // Set the default formatter for media in entity reference fields to be the
+ // "Rendered entity" formatter.
+ if (!empty($options['media'])) {
+ $options['media']['entity_view_display']['type'] = 'entity_reference_entity_view';
+ }
+}
+
+/**
+ * Implements hook_form_FORM_ID_alter().
+ */
+function media_form_field_ui_field_storage_add_form_alter(&$form, FormStateInterface $form_state, $form_id) {
+ // Provide some help text to aid users decide whether they need a Media,
+ // File, or Image reference field.
+ $description_text = t('Use <em>Media</em> reference fields for most files, images, audio, videos, and remote media. Use <em>File</em> or <em>Image</em> reference fields when creating your own media types, or for legacy files and images created before enabling the Media module.');
+ if (\Drupal::moduleHandler()->moduleExists('help')) {
+ $description_text .= ' ' . t('For more information, see the <a href="@help_url">Media help page</a>.', [
+ '@help_url' => Url::fromRoute('help.page', ['name' => 'media'])->toString(),
+ ]);
+ }
+ $form['add']['description_wrapper'] = [
+ '#type' => 'container',
+ ];
+ $field_types = [
+ 'file',
+ 'image',
+ 'field_ui:entity_reference:media',
+ ];
+ foreach ($field_types as $field_name) {
+ $form['add']['description_wrapper']["description_{$field_name}"] = [
+ '#type' => 'item',
+ '#markup' => $description_text,
+ '#states' => [
+ 'visible' => [
+ ':input[name="new_storage_type"]' => ['value' => $field_name],
+ ],
+ ],
+ ];
+ }
+ $form['add']['new_storage_type']['#weight'] = 0;
+ $form['add']['description_wrapper']['#weight'] = 1;
+}
+
+/**
+ * Implements hook_field_widget_multivalue_form_alter().
+ */
+function media_field_widget_multivalue_form_alter(array &$elements, FormStateInterface $form_state, array $context) {
+ // Do not alter the default settings form.
+ if ($context['default']) {
+ return;
+ }
+
+ // Only act on entity reference fields that reference media.
+ $field_type = $context['items']->getFieldDefinition()->getType();
+ $target_type = $context['items']->getFieldDefinition()->getFieldStorageDefinition()->getSetting('target_type');
+ if ($field_type !== 'entity_reference' || $target_type !== 'media') {
+ return;
+ }
+
+ // Autocomplete widgets need different help text than options widgets.
+ $widget_plugin_id = $context['widget']->getPluginId();
+ if (in_array($widget_plugin_id, ['entity_reference_autocomplete', 'entity_reference_autocomplete_tags'])) {
+ $is_autocomplete = TRUE;
+ }
+ else {
+ // @todo We can't yet properly alter non-autocomplete fields. Resolve this
+ // in https://www.drupal.org/node/2943020 and remove this condition.
+ return;
+ }
+ $elements['#media_help'] = [];
+
+ // Retrieve the media bundle list and add information for the user based on
+ // which bundles are available to be created or referenced.
+ $settings = $context['items']->getFieldDefinition()->getSetting('handler_settings');
+ $allowed_bundles = !empty($settings['target_bundles']) ? $settings['target_bundles'] : [];
+ $add_url = _media_get_add_url($allowed_bundles);
+ if ($add_url) {
+ $elements['#media_help']['#media_add_help'] = t('Create your media on the <a href=":add_page" target="_blank">media add page</a> (opens a new window), then add it by name to the field below.', [':add_page' => $add_url]);
+ }
+
+ $elements['#theme'] = 'media_reference_help';
+ // @todo template_preprocess_field_multiple_value_form() assumes this key
+ // exists, but it does not exist in the case of a single widget that
+ // accepts multiple values. This is for some reason necessary to use
+ // our template for the entity_autocomplete_tags widget.
+ // Research and resolve this in https://www.drupal.org/node/2943020.
+ if (empty($elements['#cardinality_multiple'])) {
+ $elements['#cardinality_multiple'] = NULL;
+ }
+
+ // Use the title set on the element if it exists, otherwise fall back to the
+ // field label.
+ $elements['#media_help']['#original_label'] = isset($elements['#title']) ? $elements['#title'] : $context['items']->getFieldDefinition()->getLabel();
+
+ // Customize the label for the field widget.
+ // @todo Research a better approach https://www.drupal.org/node/2943024.
+ $use_existing_label = t('Use existing media');
+ if (!empty($elements[0]['target_id']['#title'])) {
+ $elements[0]['target_id']['#title'] = $use_existing_label;
+ }
+ if (!empty($elements['#title'])) {
+ $elements['#title'] = $use_existing_label;
+ }
+ if (!empty($elements['target_id']['#title'])) {
+ $elements['target_id']['#title'] = $use_existing_label;
+ }
+
+ // This help text is only relevant for autocomplete widgets. When the user
+ // is presented with options, they don't need to type anything or know what
+ // types of media are allowed.
+ if ($is_autocomplete) {
+ $elements['#media_help']['#media_list_help'] = t('Type part of the media name.');
+
+ $overview_url = Url::fromRoute('entity.media.collection');
+ if ($overview_url->access()) {
+ $elements['#media_help']['#media_list_link'] = t('See the <a href=":list_url" target="_blank">media list</a> (opens a new window) to help locate media.', [':list_url' => $overview_url->toString()]);
+ }
+ $all_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('media');
+ $bundle_labels = array_map(function ($bundle) use ($all_bundles) {
+ return $all_bundles[$bundle]['label'];
+ }, $allowed_bundles);
+ $elements['#media_help']['#allowed_types_help'] = t('Allowed media types: %types', ['%types' => implode(", ", $bundle_labels)]);
+ }
+}
+
+/**
+ * Implements hook_preprocess_HOOK() for media reference widgets.
+ */
+function media_preprocess_media_reference_help(&$variables) {
+ // Most of these attribute checks are copied from
+ // template_preprocess_fieldset(). Our template extends
+ // field-multiple-value-form.html.twig to provide our help text, but also
+ // groups the information within a semantic fieldset with a legend. So, we
+ // incorporate parity for both.
+ $element = $variables['element'];
+ Element::setAttributes($element, ['id']);
+ RenderElement::setAttributes($element);
+ $variables['attributes'] = isset($element['#attributes']) ? $element['#attributes'] : [];
+ $variables['legend_attributes'] = new Attribute();
+ $variables['header_attributes'] = new Attribute();
+ $variables['description']['attributes'] = new Attribute();
+ $variables['legend_span_attributes'] = new Attribute();
+
+ if (!empty($element['#media_help'])) {
+ foreach ($element['#media_help'] as $key => $text) {
+ $variables[substr($key, 1)] = $text;
+ }
+ }
+}
+
+/**
+ * Returns the appropriate URL to add media for the current user.
+ *
+ * @todo Remove in https://www.drupal.org/project/drupal/issues/2938116
+ *
+ * @param string[] $allowed_bundles
+ * An array of bundles that should be checked for create access.
+ *
+ * @return bool|\Drupal\Core\Url
+ * The URL to add media, or FALSE if the user cannot create any media.
+ *
+ * @internal
+ * This function is internal and may be removed in a minor release.
+ */
+function _media_get_add_url($allowed_bundles) {
+ $access_handler = \Drupal::entityTypeManager()->getAccessControlHandler('media');
+ $create_bundles = array_filter($allowed_bundles, [$access_handler, 'createAccess']);
+
+ // Add a section about how to create media if the user has access to do so.
+ if (count($create_bundles) === 1) {
+ return Url::fromRoute('entity.media.add_form', ['media_type' => reset($create_bundles)])->toString();
+ }
+ elseif (count($create_bundles) > 1) {
+ return Url::fromRoute('entity.media.add_page')->toString();
+ }
+
+ return FALSE;
+}