Problem/Motivation

It's currently impossible for end-users to manually pull metadata associated with media assets from the source into the Drupal media entity, after the entity is created. Similarly, the Thumbnail (which is not a metadata per se) is treated the same way, it is currently only retrieved from the source when the entity is first created.

Several scenarios have shown this is a big limitation, being a prominent example the situation when the source providing the thumbnail is remote (like an YouTube video), and the thumbnail is changed on the remote source after the entity has been created in Drupal. Currently there is no mechanism for users to update the Thumbnail in this scenario. The same is valid for all other metadata attributes that source plugins could define (name, filesize, filemime, width, height, etc).

This issue was spun-off from #2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction.

Proposed resolution

Expose to the UI the possibility of end users with correct permissions to trigger an immediate update of the asset's metadata + thumbnail

Remaining tasks

Usability re-review, see #108 and the last paragraph of #138
#67, testing with multiple languages
#80.2 - a security item
#138 1-3.
Usability review in #166

User interface changes

- New contextual link "Update metadata" is available in the front-end

contextual link

- New operation dropbutton "Update metadata" is available in the back-end

dropbutton

- New "Update metadata" action is available in media administrative views, as a bulk operation.

bulk action

API changes

A new public method \Drupal\media\MediaInterface::updateMetadata() is added to the Media interface.

Data model changes

None

Release notes snippet

Adds the ability for users to manually trigger updating metadata on media entities (e.g. updating a more recent YouTube thumbnail).

CommentFileSizeAuthor
#203 2983456-nr-bot_f2m29uum.txt90 bytesneeds-review-queue-bot
#198 files.jpg57.23 KBrkoller
#190 removed_thumb_edit.jpg51.92 KBrkoller
#190 removed_thumb_list.jpg31.25 KBrkoller
#187 2983456-187-null-thumbnail-interdiff.patch4.04 KBid.conky
#187 2983456-187-11.4.x-null-thumbnail.patch33.71 KBid.conky
#187 2983456-187-11.3.x-null-thumbnail.patch33.39 KBid.conky
#185 2983456-183-11.3.x.patch30.54 KBbircher
#184 2983456-183-11.x.patch30.89 KBbircher
#174 2983456-media_update_metadata-11.3.9--20260506-1.patch23.64 KBrecrit
#173 drupal-2983456-MR3037--20260420-1.diff30.35 KBrecrit
#172 2983456-media_update_metadata-11.3.x-172.diff27.22 KBcodebymikey
#170 Screenshare - 2026-03-02 12_33_06 PM.mp43.4 MBcarolpettirossi
#168 2983456-168-10.5.x.patch25.61 KBduaelfr
#168 2983456-168-11.x.patch25.43 KBduaelfr
#160 Screenshot 2024-08-01 at 10.25.08 AM.png51.51 KBbanoodle
#159 2983456-10.3.1-159.patch25.72 KBduaelfr
#157 2983456-10.3.1-157.patch26.28 KBduaelfr
#145 interdiff_mr3037-145.txt1.94 KBszato
#145 2983456-mr3037-145.patch27.72 KBszato
#144 2983456-144.patch27.2 KBduaelfr
#143 drupal-add_update_metadata_for_media-2983456-10.2.x-143.patch26.4 KBduaelfr
#142 drupal-add_update_metadata_for_media-2983456-10.2.x-142.patch26.87 KBtostinni
#141 drupal-add_update_metadata_for_media-2983456-10.2.x-141.patch27.06 KBkensae
#137 2983456-nr-bot.txt130 bytesneeds-review-queue-bot
#134 drupal-add_update_metadata_for_media-2983456-10.1.x-134.patch27.15 KBjweowu
#133 drupal-add_update_metadata_for_media-2983456-10.1.x-133.patch27.19 KBjweowu
#132 2983456-nr-bot.txt129 bytesneeds-review-queue-bot
#129 drupal-add_update_metadata_for_media-2983456-9.5.x-129.patch27.35 KBjoevagyok
#128 drupal-add_update_metadata_for_media-2983456-128.patch27.28 KBjoevagyok
#127 drupal-add_update_metadata_for_media-2983456-127.patch27.34 KBjoevagyok
#126 drupal-add_update_metadata_for_media-2983456-125.patch27.34 KBjoevagyok
#123 drupal-add_update_metadata_for_media-2983456-123-9.5.3.patch26.39 KBduaelfr
#122 drupal-add_update_metadata_for_media-2983456.patch26.99 KBgfarishyan
#121 2983456-nr-bot.txt150 bytesneeds-review-queue-bot
#118 drupal-add_update_metadata_for_media-2983456-118-9.x.patch26.86 KBduaelfr
#115 drupal-add_update_metadata_for_media-2983456-115-9.x.patch26.71 KBduaelfr
#113 drupal-add_update_metadata_for_media-2983456-113-9.x.patch23.74 KBduaelfr
#113 interdiff.2983456.104.113.txt601 bytesduaelfr
#104 drupal-add_update_metadata_for_media-2983456-104-9.4.x.patch23.37 KBahebrank
#103 drupal-add_update_metadata_for_media-2983456-103-9.4.x.patch23.41 KBahebrank
#95 interdiff-2983456-88-95.txt1.2 KBguypaddock
#95 drupal-add_update_metadata_for_media-2983456-95-9.4.x.patch23.36 KBguypaddock
#94 Capture.PNG36.77 KBguypaddock
#92 2983456-91-test-debug-only.patch25.24 KBguypaddock
#90 2983456-89-test-only.patch25.13 KBjeroent
#89 2983456-89.patch23.26 KBjeroent
#88 0001-Debugging-Issue-2983456-88.test-only.patch24.94 KBguypaddock
#87 0001-Debugging-Issue-2983456-88.test-only.patch25.3 KBguypaddock
#86 0001-Debugging-Issue-2983456-88.test-only.patch25.27 KBguypaddock
#82 2983456-88.patch23.18 KBchr.fritsch
#82 interdiff-2983456-81-82.txt2.78 KBchr.fritsch
#81 interdiff_75-81.txt465 bytespghaemim
#81 2983456-81.patch22.77 KBpghaemim
#78 2983456-78.patch22.74 KBnikunj.shah
#75 interdiff-72-75.txt1.3 KBkishor_kolekar
#75 2983456-75.patch22.74 KBkishor_kolekar
#72 2983456-70-72-interdiff.txt6.76 KBrosk0
#72 2983456-72.patch22.75 KBrosk0
#70 interdiff_2983456_78-70.txt563 bytesankithashetty
#70 2983456_70.patch22.6 KBankithashetty
#68 interdiff_55-68.txt1.74 KBvsujeetkumar
#68 2983456_68.patch22.6 KBvsujeetkumar
#62 2983456_62.patch22.5 KBanmolgoyal74
#55 interdiff_53-55.txt1.38 KBvsujeetkumar
#55 2983456_55.patch22.45 KBvsujeetkumar
#53 interdiff_51-53.txt1.27 KBvsujeetkumar
#53 2983456_53.patch22.42 KBvsujeetkumar
#51 interdiff_47-51.txt2.3 KBravi.shankar
#51 2983456-51.patch22.58 KBravi.shankar
#47 interdiff_44-47.txt1.4 KBvsujeetkumar
#47 2983456_47.patch22.46 KBvsujeetkumar
#44 interdiff_41-44.txt1.22 KBridhimaabrol24
#44 2983456-44.patch22.39 KBridhimaabrol24
#41 2983456-41.patch22.25 KBhardik_patel_12
#35 interdiff-33-35.txt977 bytesmarcoscano
#35 2983456-35.patch24.09 KBmarcoscano
#33 2983456-33.patch24.09 KBmarcoscano
#33 interdiff-31-33.txt3.23 KBmarcoscano
#32 interdiff-31-32.txt4.89 KBmarcoscano
#32 2983456-32.patch20.87 KBmarcoscano
#31 interdiff-29-31.txt4.89 KBmarcoscano
#31 2983456-31.patch20.87 KBmarcoscano
#29 interdiff-26-28.txt5.46 KBmarcoscano
#29 2983456-28.patch20.58 KBmarcoscano
#26 interdiff-24-26.txt808 bytesmarcoscano
#26 2983456-26.patch16.61 KBmarcoscano
#24 3_bulk_actions.png480.4 KBmarcoscano
#24 2_operation.png346.11 KBmarcoscano
#24 1_contextual.png68.83 KBmarcoscano
#24 interdiff-23-24.txt4.43 KBmarcoscano
#24 2983456-24.patch17.4 KBmarcoscano
#23 interdiff-19-23.txt11.17 KBmarcoscano
#23 2983456-23.patch12.97 KBmarcoscano
#19 2983456_15_19.interdiff.txt368 bytesdww
#19 2983456-19.patch8.6 KBdww
#15 2983456-15.patch8.12 KBseanb
#15 interdiff-7-15.txt7.14 KBseanb
#7 2983456-7-with-2878119-65.patch60.03 KBmarcoscano
#7 2983456-7-this-patch-only-do-not-test.patch7.65 KBmarcoscano
#7 operation_button.png43.26 KBmarcoscano
#7 contextual_and_message.png33.67 KBmarcoscano
#5 contextual_link.png539.72 KBmarcoscano
#5 bulk_operation.png47.33 KBmarcoscano
#5 2983456-5-with-2878119-55.patch66.5 KBmarcoscano
#5 2983456-5-this-patch-only-do-not-test.patch3.95 KBmarcoscano

Issue fork drupal-2983456

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:

Comments

marcoscano created an issue. See original summary.

marcoscano’s picture

First suggestion:

- Create a new action plugin "Update metadata", that will trigger the metadata (+thumbnail) update logic and save the entity. This would be an immediate action, regardless if the type is configured to use queue or not.
- Enable this action in the Bulk Operations dropdown for the media overview page (and media library page)
- Expose this as a contextual link on the rendered entity
- Expose this as a secondary submit button on the edit form

Opinions?

marcoscano’s picture

Thinking a bit more about this, maybe on the edit form we shouldn't have it. It would be cool to have a button with something like "Fetch metadata", which would just try to retrieve metadata values and populate the form mapped fields, without saving them into the entity, but I guess that's another issue. Having the action that updates and saves the metadata present in the edit form would be confusing because the user may have entered info in mapped fields and it may not be clear what would happen with them when they click "Save" vs "Update metadata". Let's just avoid that route.

So my proposal is:

- Create a new action plugin "Update metadata", that will trigger the metadata (+thumbnail) update logic and save the entity. This would be an immediate action, regardless if the type is configured to use queue or not.
- Enable this action in the Bulk Operations dropdown for the media overview page (and media library page)
- Expose this as a contextual link on the rendered entity

phenaproxima’s picture

Title: Expose triggering update of media metadata + thumbnail to end users » [PP-1] Expose triggering update of media metadata + thumbnail to end users
Status: Active » Postponed
Issue tags: +Needs usability review, +Usability

I like your proposal @marcoscano, but I think this will need usability review. Additionally, I think we'll need to block this work on anything except #2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction, since that finalizes the metadata updating API. Therefore, I'm postponing on that issue.

marcoscano’s picture

Starting to proof-of-concept this.

chr.fritsch’s picture

I like these ideas. I think it would make sense to use the BatchAPI for updating multiple media items.

marcoscano’s picture

So we realized that views doesn't yet support batch API for bulk operations. Instead of writing our own batch system, we will just wait for that to be solved generically in core, and instead only allow updating the metadata on individual items.

Still needs tests, and probably a re-roll on the latest patch from the other issue, but this is how things look like so far:

seanb’s picture

Let's link #2603820: [PP-1] Allow selecting all entities in a given page or in every pages for bulk operations.

  1. +++ b/core/modules/media/config/optional/views.view.media.yml
    @@ -182,7 +182,8 @@ display:
    +            - media_update_metadata
    
    +++ b/core/modules/media/media.routing.yml
    @@ -25,6 +25,17 @@ entity.media.revision:
    +media.update_metadata:
    ...
    +  requirements:
    +    _entity_access: 'media.update'
    

    Do we need to protect this with a CSRF token?

  2. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,38 @@
    +    $request = \Drupal::request();
    +    if ($request->server->get('HTTP_REFERER')) {
    +      return $request->server->get('HTTP_REFERER');
    +    }
    

    Shouldn't we use something like a destination parameter for this?

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

Drupal 8.6.0-alpha1 will be released the week of July 16, 2018, which means new developments and disruptive changes should now 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.

deviantintegral’s picture

A small UX improvement would be if the link text was something like Update from <source>. "Update from YouTube" seems much more straightforward than "metadata". Possibly even "Refresh"?

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

Drupal 8.7.0-alpha1 will be released the week of March 11, 2019, which means new developments and disruptive changes should now be targeted against the 8.8.x-dev branch. For more information see the Drupal 8 minor version schedule and the Allowed changes during the Drupal 8 release cycle.

jweirather’s picture

Wondering/hopeful whether there are any updates here?

I've just updated to 8.7 and these patches don't appear to apply (via composer), and the features do not seem to be integrated OOTB. I do realize it's a moving target with moving parts, etc.

Alternatively, is there an effective workaround to manually update the media thumbnails?

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.

dww’s picture

Title: [PP-1] Expose triggering update of media metadata + thumbnail to end users » Expose triggering update of media metadata + thumbnail to end users
Status: Postponed » Needs work
Issue tags: +Needs reroll
Related issues: +#2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction

Based on #2878119-135: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction, it sounds like the media maintainers no longer think #2878119 is a good idea, that issue should be won't fix'ed, and we should plow ahead here with just the updateMetadata() API change for media entities along with all the nice UI additions.

This needs work for:

  • Re-rolling to apply against 8.9.x
  • To not bring anything else from #2878119 beyond updateMetadata()
  • Rename media_update_8601()
  • ...

Trying to re-roll #2878119 manually really sucked. ;) I'd rather not have to try to do that again. If someone's already got this on a branch that would be "easy" to rebase, that'd be swell. I'd be happy to try to move it forward from there.

Thanks!
-Derek

seanb’s picture

Status: Needs work » Needs review
Issue tags: -Needs reroll
StatusFileSize
new7.14 KB
new8.12 KB

Here is a good starting point. This is based on 2983456-7-this-patch-only-do-not-test.patch in #7.
I think all we need is some tests (also for the update path to install the new action) and a UX review.

Also decided to not disable the new action in the media/media_library views by default, even though the batch API is not used. In theory updating metadata could be slower than other action, but I don't think this is necessarily a reason not to expose the option to users. I've tried updating 50 youtube video's (since that is all we show on 1 page), and that seemed to work fine, took about 2,5 seconds on my local machine.

Hopefully this helps!

seanb’s picture

Some more thoughts for further iterations.

  1. +++ b/core/modules/media/src/Entity/Media.php
    @@ -391,6 +391,30 @@ public function prepareSave() {
    +    foreach ($this->translations as $langcode => $data) {
    +      if (!$this->hasTranslation($langcode)) {
    

    Use foreach (array_keys($this->getTranslationLanguages()) as $langcode)?
    $this->hasTranslation($langcode) shouldn't be needed.

  2. +++ b/core/modules/media/src/Entity/Media.php
    @@ -391,6 +391,30 @@ public function prepareSave() {
    +      foreach ($translation->bundle->entity->getFieldMap() as $metadata_attribute_name => $entity_field_name) {
    +        if ($translation->hasField($entity_field_name)) {
    +          $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
    +        }
    +      }
    

    Move this to a new protected updateMappedMetadata method, it is duplicate code (also in prepareSave()).

  3. +++ b/core/modules/media/src/Entity/Media.php
    @@ -391,6 +391,30 @@ public function prepareSave() {
    +      $translation->updateThumbnail();
    

    We need to check what to do if the source does not have a thumbnail. The updateThumbnail method uses a default thumbnail when that happens, but not sure if we need additional logic to skip a thumbnail update in that case?

Status: Needs review » Needs work

The last submitted patch, 15: 2983456-15.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

dww’s picture

Assigned: Unassigned » dww

Thanks, @seanB!

A huge # of those test failures are this:

Drupal\Core\Config\Schema\SchemaIncompleteException: Schema errors for system.action.media_update_metadata with the following errors: system.action.media_update_metadata:configuration missing schema
 

I'm going to do a quick re-roll to include that and see how much closer to green that gets us. Stay tuned...

dww’s picture

Assigned: dww » Unassigned
Status: Needs work » Needs review
StatusFileSize
new8.6 KB
new368 bytes

Ugh, having troubles with my local test environment again. :( Uploading here so the bot can verify the results. Hopefully this should help.

dww’s picture

Status: Needs review » Needs work

Amazing, that's green. ;)

So, back to NW for:
- Feedback in #16 (which all seems legit and worth fixing)
- Tests

phenaproxima’s picture

  1. +++ b/core/modules/media/media.install
    @@ -5,6 +5,8 @@
     
    +use Drupal\Core\Config\FileStorage;
    +use Drupal\Core\Config\InstallStorage;
     use Drupal\Core\Entity\Sql\SqlEntityStorageInterface;
     use Drupal\Core\File\Exception\FileException;
     use Drupal\Core\File\FileSystemInterface;
    @@ -12,6 +14,7 @@
    
    @@ -12,6 +14,7 @@
     use Drupal\media\Entity\MediaType;
     use Drupal\media\MediaTypeInterface;
     use Drupal\media\Plugin\media\Source\OEmbedInterface;
    +use Drupal\system\Entity\Action;
    

    These don't seem to be used?

  2. +++ b/core/modules/media/media.install
    @@ -257,3 +260,21 @@ function media_update_8700() {
    +function media_update_8900() {
    +  if (!Action::load('media_update_metadata')) {
    +    \Drupal::entityTypeManager()
    +      ->getStorage('action')
    +      ->create([
    +        'id' => 'media_update_metadata',
    +        'label' => 'Update metadata',
    +        'type' => 'media',
    +        'plugin' => 'media_update_metadata',
    +      ])
    +      ->trustData()
    +      ->save();
    +  }
    +}
    

    I could be wrong, but I think the fact that this is using the entity API means that it should be a post-update function.

  3. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,42 @@
    +/**
    + * Class UpdateMetadataController.
    + */
    +class UpdateMetadataController extends ControllerBase {
    

    This probably needs a better doc comment. :) Also, maybe we should tag it explicitly @internal like so:

    @internal
      Controllers are internal.
    
  4. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,42 @@
    +    $media->updateMetadata()->save();
    

    I know it's more verbose, but for DI reasons, can we use $this->entityTypeManager()->getStorage()->save()?

  5. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,42 @@
    +    \Drupal::messenger()->addStatus($this->t('Updated metadata on media item %label', [
    +      '%label' => $media->label(),
    +    ]));
    

    We should be using $this->messenger().

  6. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,42 @@
    +    if (\Drupal::request()->query->has('destination')) {
    +      return \Drupal::destination()->get();
    +    }
    

    I think we can just use $this->getRedirectDestination() here.

  7. +++ b/core/modules/media/src/Entity/Media.php
    @@ -394,6 +394,30 @@ public function prepareSave() {
    +  public function updateMetaData() {
    

    I think we usually treat "metadata" as one word, so this should be updateMetadata().

  8. +++ b/core/modules/media/src/Entity/Media.php
    @@ -394,6 +394,30 @@ public function prepareSave() {
    +    foreach ($this->translations as $langcode => $data) {
    

    I don't think we should be using $this->translations directly. Classes should use their own APIs. So $this->getTranslations() is preferable.

  9. +++ b/core/modules/media/src/Plugin/Action/UpdateMetadataAction.php
    @@ -0,0 +1,35 @@
    +  public function execute($entity = NULL) {
    +    /** @var \Drupal\media\MediaInterface $entity */
    +    $entity->updateMetadata()->save();
    +  }
    

    Can we inject the entity storage handler instead?

marcoscano’s picture

Assigned: Unassigned » marcoscano
Issue tags: +Amsterdam2019

working on this

marcoscano’s picture

StatusFileSize
new12.97 KB
new11.17 KB

#16:

1) It seems you selected code from ::prepareSave(), while the patch is adding updateMetaData(), which is probably where that came from? Since both code chunks do the same, I've updated both of them, under the risk of being pushed back for out-of-scope in the first method.

2) 👏much better in a separate method!

3) IMHO we shouldn't worry too much trying to skip the update here. To me, a call to ::updateMetadata() is an explicit instruction to "update all you can", even if that means re-detecting that we need to use the default thumbnail...

What we could consider doing, if #2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction is indeed a wont' fix, is to remove this todo, which is in that method?

   * @todo There has been some disagreement about how to handle updates to
   *   thumbnails. We need to decide on what the API will be for this.
   *   https://www.drupal.org/node/2878119

(I haven't done it here, though)

#21:

1) 👍

2) 👍

3) 👍

4) 👍

5) 👍

6) 👍

7) 👍

8) This was fixed when addressing feedback from #16

9) 👍

I will work on the missing tests tomorrow.

marcoscano’s picture

Assigned: marcoscano » Unassigned
Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new17.4 KB
new4.43 KB
new68.83 KB
new346.11 KB
new480.4 KB

Let's see if the testbot likes this.

I also updated the issue summary and added some screenshots of the UI changes.

I'm not sure we need a change record for the new method added to the media interface?

Status: Needs review » Needs work

The last submitted patch, 24: 2983456-24.patch, failed testing. View results

marcoscano’s picture

Status: Needs work » Needs review
StatusFileSize
new16.61 KB
new808 bytes

sorry, was too optimistic about what the MediaContextualLinksTest was about... Any suggestion about the cleanest way to check the contextual link appears there? Or should we just rely that if the link exists in config, it will be there because that's a separate API that is tested elsewhere?

seanb’s picture

  1. +++ b/core/modules/media/src/Entity/Media.php
    @@ -364,29 +364,62 @@ public function prepareSave() {
    +      if ($override_existing) {
    +        $should_map_field = TRUE;
    +      }
    +      else {
    +        // If not explicitly requested by the caller, the field will be mapped
    +        // if it's empty, or if the source field changed.
    +        $should_map_field = $translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged();
    +      }
    +      if ($translation->hasField($entity_field_name) && $should_map_field) {
    +        $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
           }
    

    $should_map_field = $override_existing || ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())?

    Also, we do the $translation->hasField($entity_field_name) check after $translation->get($entity_field_name)->isEmpty()?

    Maybe this is even better:

    if (!$translation->hasField($entity_field_name)) {
      continue;
    }
    
    if ($override_existing || $translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged()) {
      $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
    }
    

marcoscano’s picture

StatusFileSize
new20.58 KB
new5.46 KB

Thanks for reviewing!

1. I like your simplification, thanks! I've added an additional inline comment so to make it easier to read that conditional, but no strong opinions if you think it's too verbose.

I also added the contextual test back. It turns out that if we want to assert the contextual links themselves (and @seanb and myself think we should, since the links are provided by the media module), we need to convert the test into a javascript test, and do some javascript-y things to make them appear.

Also, crediting @Lendude who helped me figure out the above. Thanks!

phenaproxima’s picture

  1. +++ b/core/modules/media/media.install
    @@ -8,14 +8,14 @@
    +use Drupal\Core\StringTranslation\TranslatableMarkup;
     use Drupal\Core\Url;
    +use Drupal\image\Plugin\Field\FieldType\ImageItem;
     use Drupal\media\Entity\MediaType;
     use Drupal\media\MediaTypeInterface;
     use Drupal\media\Plugin\media\Source\OEmbedInterface;
     use Drupal\user\Entity\Role;
     use Drupal\user\RoleInterface;
    -use Drupal\image\Plugin\Field\FieldType\ImageItem;
    -use Drupal\Core\StringTranslation\TranslatableMarkup;
    

    Probably an automatic IDE fix; technically out of scope, but eh...I don't care much.

  2. +++ b/core/modules/media/media.post_update.php
    @@ -97,3 +98,21 @@ function media_post_update_add_status_extra_filter() {
    +    \Drupal::entityTypeManager()
    +      ->getStorage('action')
    +      ->create([
    +        'id' => 'media_update_metadata',
    +        'label' => 'Update metadata',
    +        'type' => 'media',
    +        'plugin' => 'media_update_metadata',
    +      ])
    

    Nit: Why not simply use Action::create() here?

  3. +++ b/core/modules/media/media.routing.yml
    @@ -25,6 +25,17 @@ entity.media.revision:
    +  options:
    +    parameters:
    +      media:
    +        type: entity:media
    

    Is this necessary? For some reason, I was under the impression that the routing system would reflect on the controller method and determine automatically that it expects a media entity. No big deal, just not sure if my info is correct.

  4. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,45 @@
    + * @internal
    + *   Controllers are internal.
    

    🙏

  5. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,45 @@
    +   * @param \Drupal\media\MediaInterface $media
    +   *   The media item it update.
    

    Should probably be "The media item for which to update metadata"?

  6. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,45 @@
    +    $this->entityTypeManager()->getStorage('media')->save($media);
    

    Hmmm...isn't the whole idea of this issue to add an explicit updateMetadata() method? Wouldn't we call that instead, then save?

  7. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,45 @@
    +    if (\Drupal::request()->query->has('destination')) {
    +      return $this->getRedirectDestination()->get();
    +    }
    

    Shouldn't we just plain use $this->getRedirectDestination(), rather than checking if a specific URL query parameter is set?

  8. +++ b/core/modules/media/src/Entity/Media.php
    @@ -364,29 +364,60 @@ public function prepareSave() {
    +  protected function updateMappedMetadata(MediaInterface $translation, $override_existing = FALSE) {
    

    Not a big deal, but I'm not entirely clear on why we would pass $translation into this method? Couldn't we just call $translation->updateMappedMetadata() and have it operate on itself?

    Also, I know there's already been some bikeshedding on this, but I'd use "overwrite" instead of "override". Override implies that the previous value is remembered somewhere and can be reverted, but that's not case -- AFAICT, if $override_existing is TRUE, previous values are thrown away forever. That is an overwrite.

  9. +++ b/core/modules/media/src/Entity/Media.php
    @@ -364,29 +364,60 @@ public function prepareSave() {
    +      if (!$translation->hasField($entity_field_name)) {
    +        continue;
    +      }
    

    Under what circumstances would the field not exist?

  10. +++ b/core/modules/media/src/MediaInterface.php
    @@ -64,4 +64,12 @@ public function setCreatedTime($timestamp);
    +  /**
    +   * Update the media entity's field values from the source's metadata.
    +   *
    +   * @return \Drupal\media\MediaInterface
    +   *   The updated media item.
    +   */
    +  public function updateMetadata();
    

    This documentation is vague. We should document if, and how, existing values are overwritten here. We should also document how this interacts with translations, and we should say that this does NOT save the media item afterwards.

marcoscano’s picture

Assigned: Unassigned » marcoscano
Status: Needs review » Needs work
Issue tags: +Needs tests
StatusFileSize
new20.87 KB
new4.89 KB

Thanks for reviewing!

1) yeah.. sorry about that, that's me doing cmd-option-O too often so PHPStorm removes unused, that ends up sorting them too... I can roll it back if someone feels strongly about this change, but arguably having this in will prevent the next "me" in the line from adding noise to the patches? 😛

2) 👍

3) I honestly don't know, and I guess this came from the media revision route, that does have that in the route definition. 🤷‍♂️It's true if we remove these lines things appear to still work, so I just removed them for now.

4) 🙌

5) 👍

6) You are absolutely right! We missed it in one of the recent rerolls / feedback addressing. This also uncovers the lack of test coverage when using the controller. I've fixed the bug here, and I'll be creating a specific test for the controller next.

7) I think the idea here was to be able to send users to the media collection route, if the destination param is _not_ present? Otherwise I believe this would cause a redirect loop?

8) This helper method exists because we are trying to avoid some duplication when we need to do the same twice. The trick is, in one of the places this needs to happen inside an already existing loop that is also doing stuff with the $translation, so I guess it's just simpler this way?

I went ahead and replaced "override" with "overwrite", I'm always confused about when to use one or the other...

9) Probably a separate issue, but it turns out we are apparently never using \Drupal\media\Entity\MediaType::setFieldMap(). This means that if a field gets deleted, we are probably not updating the fieldmap in the database (AFAICT). This is definitely something that should be fixed, but more generically, since the field map doesn't come from entity API, I think it's fair to be safe and only try to use a field we know exists in the entity.

10) 👍

marcoscano’s picture

Assigned: marcoscano » Unassigned
Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new20.87 KB
new4.89 KB

Now with a dedicated test for the controller.

marcoscano’s picture

StatusFileSize
new3.23 KB
new24.09 KB

Not sure what happened but I managed to mess up with the diffs. Now the correct files, sorry for the noise.

Status: Needs review » Needs work

The last submitted patch, 33: 2983456-33.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

marcoscano’s picture

Status: Needs work » Needs review
StatusFileSize
new24.09 KB
new977 bytes
marcoscano’s picture

Also worth noting, on #10, @deviantintegral suggested we used better wording for the UI-facing texts.

While I agree that "Refresh from Youtube" is probably more self-explanatory than the current label, I'm afraid it would be very tricky to get this right in a reasonable effort, since "Youtube", in most cases, isn't a media type, but a provider name. Also, on non-remote sources, the "from" terminology might not be the best, such as "Refresh from File", or "Refresh from Image"...

Considering all this, I still think the generic "Update metadata" is a good compromise that is accurate in all scenarios. It could be argued also that users who don't know what "metadata" is (in the context of a media entity) are likely missing out some of the features of the media system, so it wouldn't hurt to let them figure out what that means... :P

bkosborne’s picture

+1 to this. I need a public API to trigger metadata updates when the source field value has changed. Media module currently handles this automatically but the logic for determining if source value has changed is not quite sophisticated enough to detect certain situations. Specifically in my case, if the file entity for a file-based media entity is updated.

Having this committed would allow my module, Media Entity File Replace, to manually trigger a metadata update.

bkosborne’s picture

fgm’s picture

One use case I have on a site and haven't seen mentioned here is having the thumbnail be redefined on the video hosting platform (Vimeo in that specific case), and having to trigger a refresh on site while the URL of the media is constant but the actual thumbnail content changes (or I don't understand what's going on): this would mean not being able to rely on a thumbnail URL to compare whether the managed file association needs to be redone.

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.

hardik_patel_12’s picture

StatusFileSize
new22.25 KB

Re-rolling patch against 9.1.x-dev, kindly review a patch.

Status: Needs review » Needs work

The last submitted patch, 41: 2983456-41.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

jonathanshaw’s picture

Issue tags: +Novice

Novice to fix the trivial test fail

ridhimaabrol24’s picture

Status: Needs work » Needs review
StatusFileSize
new22.39 KB
new1.22 KB

Fixing failed tests! Please review!

jonathanshaw’s picture

Issue tags: -Novice

Looks good, thanks @ridhimaabrol24

Status: Needs review » Needs work

The last submitted patch, 44: 2983456-44.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

vsujeetkumar’s picture

Status: Needs work » Needs review
StatusFileSize
new22.46 KB
new1.4 KB

Fixing Fail test, Please have a look.

Status: Needs review » Needs work

The last submitted patch, 47: 2983456_47.patch, failed testing. View results
- codesniffer_fixes.patch Interdiff of automated coding standards fixes only.

phenaproxima’s picture

Category: Task » Feature request
Priority: Normal » Major
Issue tags: +Triaged Media Initiative issue

This is a major feature request, but also an important one, so I'm bumping priority.

ravi.shankar’s picture

Assigned: Unassigned » ravi.shankar
ravi.shankar’s picture

Assigned: ravi.shankar » Unassigned
Status: Needs work » Needs review
StatusFileSize
new22.58 KB
new2.3 KB

Here I have tried to fix failed tests and fixed some CS violations.

Status: Needs review » Needs work

The last submitted patch, 51: 2983456-51.patch, failed testing. View results

vsujeetkumar’s picture

Status: Needs work » Needs review
StatusFileSize
new22.42 KB
new1.27 KB

Fixing test.

Status: Needs review » Needs work

The last submitted patch, 53: 2983456_53.patch, failed testing. View results

vsujeetkumar’s picture

Status: Needs work » Needs review
StatusFileSize
new22.45 KB
new1.38 KB

Fixing test, Please review.

benjifisher’s picture

Issue summary: View changes
Status: Needs review » Needs work
Issue tags: +Needs reroll, +Novice, +Needs issue summary update, +Needs change record

Usability review

We looked at this issue at the #3173646: Drupal Usability Meeting 2020-09-29.

Thanks for the screenshots in the issue summary. I guess the main question is whether we can come up with something better than "update metadata" to describe the action.

I am setting the status to NW for a reroll (even though the current patch is less than two weeks old) and an issue summary update.

  • Add a release notes snippet to the issue summary.
  • Where will this be documented? This is especially important because of comments like "it wouldn't hurt to let them figure out what that means" (from #36).
  • The issue summary refers to #2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction, which is closed as "won't fix". It is OK to leave that link for historical interest, but do not ask readers (like me) to go to that issue for context. Give examples of what "update metadata" means, say for a local PDF or a remote video. The examples should help decide whether "refresh" or "update" is clearer.
  • Is there a confirmation page? If so, please include a screenshot under "user interface changes".

Not in scope for the usability review, but doesn't an API addition require a change record? I am adding the tag for that.

marcoscano’s picture

Issue summary: View changes
Status: Needs work » Needs review
Issue tags: -Needs reroll, -Novice, -Needs issue summary update, -Needs change record

Thanks for reviewing!

I am setting the status to NW for a reroll (even though the current patch is less than two weeks old) and an issue summary update.

I just checked, and there is no reroll needed for 9.1.x, which is where this is would hopefully go, since it's a new feature.

Add a release notes snippet to the issue summary.

Done

Where will this be documented?

I expanded the documentation over at https://www.drupal.org/docs/8/core/modules/media/creating-and-configurin... to be more explicit about this metadata mapping.

The issue summary refers to #2878119: Whether queued or not, update the media thumbnail and metadata before beginning the entity save database transaction, which is closed as "won't fix". It is OK to leave that link for historical interest, but do not ask readers (like me) to go to that issue for context. Give examples of what "update metadata" means, say for a local PDF or a remote video. The examples should help decide whether "refresh" or "update" is clearer.

Updated, I hope it's clearer now with examples.

Is there a confirmation page? If so, please include a screenshot under "user interface changes".

There is no confirmation page for this operation.

Not in scope for the usability review, but doesn't an API addition require a change record? I am adding the tag for that.

Thanks for pointing it out! I'm no expert in change records, but I've given it a try here: #3174553: Added possibility to update metadata on media entities after entities are created Any feedback is welcome!

Thanks!

cbrody’s picture

Great work - are there plans for a patch for 8.9.x?

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.

froboy’s picture

@benjifisher going back to the wording. I see a few notes in #10 and #36 and while 36 raises some technical challenges, I think 10 still has some good thoughts. I disagree with the sentiment in 36 that it wouldn't hurt to let them figure out what [metadata] means. IMHO it's our responsibility to meet users where they are.

From 36 is sounds like getting the source (e.g. "YouTube") is hard, but getting the type (e.g. "Video") is possible. I polled/brainstormed with a bunch of end users and content-focused folk on one of my teams with the question:

If there was a button in Drupal that pulled information from a video provider (YouTube, Vimeo, or otherwise), what would you expect it to say?

"Refresh video information" was their consensus. Given the options above I think we could abstract this to "Refresh <type> information".

Given the base media types, this would produce:

Refresh video information
Refresh image information
Refresh local video information
Refresh document information

which all seem to sound reasonable (to me).

cweagans’s picture

I tried this patch on my D8 project with media_entity_file_replace and found that the width and height of the images wasn't updated after using the new action on my media item.

Steps to reproduce:
1. Upload 400x400 image
2. See that the sizes in the media__field_media_image and media_field_data table are correct.
3. Replace the image with a 1024x1024 image
4. See that the sizes in those tables are still stored as 400x400
5. Run the action on the media item
6. See that the sizes are still 400x400

This causes issues with Focal Point, which uses those dimensions to figure out what the image should do. For now, I did the dumb thing and just reached into the database and updated the values manually when an image is replaced, but that's definitely not the "right" way to do it. I'm not sure if updated width and height attributes were expected as a result of this issue, but if they were, it's definitely not working.

anmolgoyal74’s picture

StatusFileSize
new22.5 KB

Re-rolled for 8.9.x

Status: Needs review » Needs work

The last submitted patch, 62: 2983456_62.patch, failed testing. View results

phenaproxima’s picture

There's no need to reroll this for 8.9.x -- because it's a new feature, it will not be committed to that branch anyway. :) This is for 9.2.x or later.

marcoscano’s picture

Status: Needs work » Needs review
alexpott’s picture

Status: Needs review » Needs work

Reviewing #55

  1. +++ b/core/modules/media/media.post_update.php
    @@ -16,3 +18,19 @@ function media_removed_post_updates() {
    +/**
    + * Install the 'Update metadata' action.
    + */
    +function media_post_update_install_update_metadata_action() {
    +  if (!Action::load('media_update_metadata')) {
    +    Action::create([
    +      'id' => 'media_update_metadata',
    +      'label' => 'Update metadata',
    +      'type' => 'media',
    +      'plugin' => 'media_update_metadata',
    +    ])
    +      ->save();
    +  }
    

    This needs a test.

  2. +++ b/core/modules/media/src/Entity/Media.php
    @@ -364,29 +364,60 @@ public function prepareSave() {
    +      // Populate the field value in one of these scenarios: 1) The caller of
    +      // this function asked for it explicitly, 2) The entity field is empty,
    +      // or 3) The media source field has changed.
    

    Let's use the list format - https://www.drupal.org/docs/develop/standards/api-documentation-and-comm...

  3. +++ b/core/modules/media/src/MediaInterface.php
    @@ -64,4 +64,18 @@ public function setCreatedTime($timestamp);
    +  /**
    +   * Update the media entity's field values from the source's metadata.
    +   *
    +   * This will fetch metadata from the source field, and update all values that
    +   * are mapped to entity fields. This will overwrite non-empty existing values,
    +   * and will update all translations of the entity. This will also try to
    +   * update the entity's thumbnail with a newer version, if available.
    +   *
    +   * @return \Drupal\media\MediaInterface
    +   *   An unsaved version of this media item, after updating the mapped field
    +   *   items and the thumbnail.
    +   */
    +  public function updateMetadata();
    

    It's great that this documents that the documentation says the entity thats returned needs saving.

    At some point it'd be lovely to know if the entity has changed and therefore if a save is actually necessary. But that's out of scope.

    One question I have is are we concerned about data loss through translations being unexpectedly overwritten?

  4. +++ b/core/modules/media/tests/src/Functional/MediaUpdateMetadataControllerTest.php
    @@ -0,0 +1,68 @@
    +    // Initially the "name" metadata is the filename.
    +    $file = \Drupal\file\Entity\File::create([
    

    This fails a coding standards check. Need to add use Drupal\file\Entity\File as FileEntity and then $file = FileEntity::create([

  5. One concern I have is whether we do this differently. At the moment we call $media->updateMetadata() and then $media->save(). Whilst we call $media->save() we will call $media->prepareSave() which does some of the same things as $media->updateMetadata(). I wonder if it'd be better if we did something like. $media->enforceMetadataUpdate()->save() where enforceMetadataUpdate() sets a protected property on the Media entity that is then checked in prepareSave().
alexpott’s picture

+++ b/core/modules/media/tests/src/Functional/MediaUpdateMetadataControllerTest.php
@@ -0,0 +1,68 @@
+/**
+ * Tests the media "Update Metadata" controller.
+ *
+ * @group media
+ */
+class MediaUpdateMetadataControllerTest extends MediaFunctionalTestBase {

Given the amount of multilingual logic in the code I think we should be testing multilingual media items here.

vsujeetkumar’s picture

Status: Needs work » Needs review
StatusFileSize
new22.6 KB
new1.74 KB

This patch fixes #66.2 and 66.4.

Status: Needs review » Needs work

The last submitted patch, 68: 2983456_68.patch, failed testing. View results

ankithashetty’s picture

Status: Needs work » Needs review
StatusFileSize
new22.6 KB
new563 bytes

Fixed test failures in #68, thanks!

rosk0’s picture

Status: Needs review » Needs work

Replying to #61 - @cweagans, if I understood you correctly issue of image dimensions not being updated once file is updated/changed is not related to this. Can you please create a new issue for it.

NW for #66.1, #66.3, #66.5 and #67.

rosk0’s picture

Status: Needs work » Needs review
StatusFileSize
new22.75 KB
new6.76 KB

This addresses #66.5 + some code style issues.

Still outstanding: #66.1, #66.3 and #67.

It feels like it should be two separate items/actions: "Update metadata" & "Update thumbnail".

jweowu’s picture

Some very minor tweaks from looking at the #72 interdiff:

1. Instead of:

   protected function reloadPage() {
     if ($this->getRedirectDestination()->get()) {
       return $this->getRedirectDestination()->get();
     }

I suggest:

   protected function reloadPage() {
     if ($destination = $this->getRedirectDestination()->get()) {
       return $destination;
     }

2. And instead of:

   protected function shouldUpdateThumbnail($is_new = FALSE) {
     // Update thumbnail if we don't have a thumbnail yet or when the source
     // field value changed or when it was enforced.
     return !$this->get('thumbnail')->entity || $is_new || $this->hasSourceFieldChanged() || $this->forceMetadataUpdate;
   }

I suggest generally doing the trivial/cheapest tests first:

   protected function shouldUpdateThumbnail($is_new = FALSE) {
     // Update thumbnail if we don't have a thumbnail yet or when the source
     // field value changed or when it was enforced.
     return $is_new || $this->forceMetadataUpdate || !$this->get('thumbnail')->entity || $this->hasSourceFieldChanged();
   }

Status: Needs review » Needs work

The last submitted patch, 72: 2983456-72.patch, failed testing. View results

kishor_kolekar’s picture

Status: Needs work » Needs review
StatusFileSize
new22.74 KB
new1.3 KB

Hey, I have tried to cover the points mentioned in #73
Please review

Status: Needs review » Needs work

The last submitted patch, 75: 2983456-75.patch, failed testing. View results

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.

nikunj.shah’s picture

StatusFileSize
new22.74 KB

I have created Reroll of #75 for 9.3.x-dev. Please review.

steinmb’s picture

Coming here from #3080666: oEmbed system doesn't work if thumbnail url does not have a file extension where Vimeo thumbnails is not correctly getting generated at all. Having an official way of re-generating them is pretty crucial to us.

larowlan’s picture

  1. +++ b/core/modules/media/media.module
    @@ -528,3 +528,20 @@ function media_views_query_substitutions(ViewExecutable $view) {
    +function media_entity_operation(EntityInterface $entity) {
    +  $operations = [];
    +  if ($entity->getEntityTypeId() === 'media' && $entity->access('update')) {
    +    $operations['update_metadata'] = [
    +      'title' => t('Update metadata'),
    

    this should go in the list builder, no need to implement a hook for an entity which the module defines already

  2. +++ b/core/modules/media/src/Controller/UpdateMetadataController.php
    @@ -0,0 +1,46 @@
    +  public function updateMetadata(MediaInterface $media) {
    +    $media->updateMetadata();
    +    $this->entityTypeManager()->getStorage('media')->save($media);
    +    $this->messenger()->addStatus($this->t('Updated metadata on media item %label', [
    

    this is a CSRF vulnerability.

    Either we need a CSRF token on the route, or we need this to be a confirm form.

    I can do this anywhere on the internet

    <img src="https://yoursite.com/media/3/update-metadata" />

    And if I can trick you into visiting that page, it will force regeneration without your knowledge.

    This could lead to server load.

We can't put this in with a security issue in it

pghaemim’s picture

StatusFileSize
new22.77 KB
new465 bytes

trying to cover #80.2 adding csrf token to the "metadata-update" route.

chr.fritsch’s picture

Status: Needs work » Needs review
StatusFileSize
new2.78 KB
new23.18 KB

Fixing the tests and addressing 80.1

Status: Needs review » Needs work

The last submitted patch, 82: 2983456-88.patch, failed testing. View results

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.

guypaddock’s picture

I do not understand why Drupal\Tests\media\Functional\MediaUpdateMetadataControllerTest is failing; when run locally, it passes.

guypaddock’s picture

This patch is intended to force the test runner to dump out what the page output looks like when it fails, since Drupal Core does not save its browser output on Jenkins.

In all other respects, this is the same as #88 -- just trying to understand what the test runner sees that we do not see locally since the XPath matches locally.

guypaddock’s picture

Trying again, this time to get passed the code sniffer to get the debug output I need.

guypaddock’s picture

Test runner... just run the damned tests! I don't care about style right now...

jeroent’s picture

Status: Needs work » Needs review
StatusFileSize
new23.26 KB

I've created a reroll of #82 that applies on 9.4.x.

jeroent’s picture

StatusFileSize
new25.13 KB

The last submitted patch, 89: 2983456-89.patch, failed testing. View results

guypaddock’s picture

StatusFileSize
new25.24 KB

Thanks, @jeroenT! Hadn't considered just commenting out the inspections for debugging... that makes a lot of sense.

Ok, test runner... let's see if base-64-encoding the HTML gives us the context we crave.

Status: Needs review » Needs work

The last submitted patch, 92: 2983456-91-test-debug-only.patch, failed testing. View results

guypaddock’s picture

Assigned: Unassigned » guypaddock
StatusFileSize
new36.77 KB

Interesting... on Drupal CI the paths for the site have a subdirectory prefix, which explains the test failures:

The href of the anchor is "/subdirectory/media/1/update-metadata" not "/media/1/update-metadata".

This does not happen locally. Mystery solved; this should be a quick fix for the tests. Working on that now.

guypaddock’s picture

StatusFileSize
new23.36 KB
new1.2 KB

Ok, added-in the site base path. This is the same as #89 with tests (hopefully) working now.

Also, I am attaching an inter-diff from 88 to this change since one wasn't previously attached. Cross-branch inter-diffs pose an interesting challenge; I am diffing the patches themselves since the changes are minimal. If anyone prefers a better way to get a cross-branch inter-diff, I am all ears!

guypaddock’s picture

Assigned: guypaddock » Unassigned
Status: Needs work » Needs review

Setting to NR.

ironsizide’s picture

I have used the patch in #95 with Drupal 9.3.5 and it's working well. Incidentally I am also using the patch from https://www.drupal.org/project/drupal/issues/3042423#comment-14357576 so a hook can pull hires thumbnails as well. The patch on this issue insures that if a video is edited so a higher resolution thumbnail is pulled the queue cam be run immediately and the new thumbnail is hooked up in the filesystem and used for the thumbnail display. Working like a charm.

edurenye’s picture

Status: Needs review » Needs work

If the video was deleted from YouTube, update metadata does not let you update the metadata, it just deletes the entity.

I wanna keep the video so it just show the usual YouTube box telling you the video was deleted.

Also if the video is not available in your region but is available in others it will remove the entity.

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.

blazey’s picture

If anyone's looking for a fix to the issue reported by @cweagans in #61 it's here: #3088168: Media thumbnail dimensions are wrong for YouTube videos.

thetailwind’s picture

I used the patch #95. It worked once or twice, now the option does not appear in the bulk menu. I tried removing the patch(via composer), updating the db(nothing to change), reapplying the patch, updating the db (nothing to change).

Additionally, sometimes when I run it on the individual media item, I get something like looks like JSON in an expanding text area.

Edit: I got the bulk option back by running this command:

drush ev "include 'core/modules/media/media.post_update.php'; media_post_update_install_update_metadata_action();"

Not sure if this is isolated to me, but hope it helps someone else!

glynster’s picture

@GuyPaddock your patch no longer applies:

Patch: 2983456-95-9.4.x.patch no longer applies but after upgrading to Drupal 9.4.4 the following error occurs:

PHP Fatal error:  Class Drupal\media\Entity\Media contains 1 abstract method and must therefore be declared abstract or implement the remaining methods (Drupal\media\MediaInterface::enforceMetadataUpdate) in /app/web/core/modules/media/src/Entity/Media.php on line 86
ahebrank’s picture

Here's a reroll for 9.4.4.

ahebrank’s picture

StatusFileSize
new23.37 KB

... and a fix for the style linter.

glynster’s picture

Thanks @ahebrank applies smoothly again!

stijnhau’s picture

Latest patch works perfectly

anybody’s picture

Still the points from #98 need to be addressed to put this back to "Needs review".

What can we do to make progress with the usability review? (Needs usability review tag) Is it still needed for this bulk operation?

benjifisher’s picture

The best way to get a usability review is to join the weekly meeting and present the issue.See the #ux channel in Drupal Slack for the schedule.

If you cannot make it to the meeting, then either ping the same channel or add a comment to the issue for the weekly meeting, currently #3310096: Drupal Usability Meeting 2022-09-23 and ask for a review. Either way, make the issue easy to review: make sure the issue summary is up to date, so that people at the meeting do not have to read through the comments to understand the usability questions.

  • The "Proposed resolution" section should describe all the changes made in the issue.
  • The "User interface changes" should show the existing UI and the proposed UI.

Most of the time, I prefer to have plain text in the "Proposed resolution" section and screenshots in the "User interface changes" section.

Also, review #56 and make sure that all the points raised there have been addressed.

kleve’s picture

Patch applies but 2 extra folder structures are added as well with the files included in the patch. Is anyone else having this problem? Guessing this is not something that should be happening?

Eg. the following added file
core/modules/media/config/install/system.action.media_update_metadata.yml

Is also added to the following locations
core/b/core/modules/media/config/install/system.action.media_update_metadata.yml
core/core/modules/media/config/install/system.action.media_update_metadata.yml

Using patch from #104
https://www.drupal.org/files/issues/2022-07-30/drupal-add_update_metadat...

Using drupal/core (9.4.7)

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.

duaelfr’s picture

I've been testing this patch on a 9.x live install and I had issues with the thumbnails update.

If a thumbnail already exists on the Media and we trigger the new update metadata function, the thumbnail is not updated. To make it work we have to:

  1. Physically delete the file
  2. Run the update metadata function
  3. Run the cron (or the queue)
  4. Clear image styles

From an usability point of view, I think that the user should only have to use the update metadata function then see the result immediately.

duaelfr’s picture

Status: Needs work » Needs review
StatusFileSize
new601 bytes
new23.74 KB

In the MR:

  • Rerolled #104 on 10.1.x
  • Changed condition in \Drupal\media\Entity\Media::getThumbnailUri() for force thumbnail update instead of using existing one

In the attached patch:

  • 9.x version of the above

Status: Needs review » Needs work
duaelfr’s picture

Status: Needs work » Needs review
StatusFileSize
new26.71 KB

In the MR:

  • Rebased the branch on 10.1.x
  • Added the \Drupal\media\MediaInterface::isMetadataUpdateEnforced() method
  • Updated \Drupal\media\Plugin\media\Source\OEmbed::getLocalThumbnailUri() to be able to force the thumbnail download
  • Updated \Drupal\media\Entity\Media::updateThumbnail() to flush thumbnail's images styles after update

In the attached patch:

  • 9.x version of the above
flyke’s picture

#115 is missing the following use statement:
use Drupal\system\Entity\Action;
which throws an error:
Error: Class 'Action' not found in media_post_update_install_update_metadata_action() (line 42 of /app/web/core/modules/media/media.post_update.php) #0 /app/vendor/drush/drush/src/Commands/core/UpdateDBCommands.php(321): media_post_update_install_update_metadata_action(Array)

no sssweat’s picture

Status: Needs review » Needs work
duaelfr’s picture

Status: Needs work » Needs review
StatusFileSize
new26.86 KB

@No Sssweat The patch is only here for devs convenience but the real review has to be made on the !3037 Merge Request.
I checked in the MR and the appropriate use properly is included so the change should be effective on D10.

As told in #116, the attached patch was faulty. Here is a new one for Drupal 9.5 users.

no sssweat’s picture

My apologies @DuaelFr, I was not aware.

Thank you for enlightening me on how the drupal.org review process flows with GitLab these days.

Also, while I am at it, thank you for your contributions!

kjauslin’s picture

@DuaelFr Thanks for the 9.5.x port of the patch in #118. Successfully using this with a custom MediaSource similar to OEmbed. There is one major issues I experience:

In function `GetLocalThumbnailUri` -`$files = $this->fileSystem->scanDirectory($directory, "/^$hash\..*/");`. scanDirectory will get unusably slow for very large number of files in a directory. The default media table use calls the GetLocalThumbnail function for every media. In my case there are 25'000 media and the page is taking a very long time to load. It would be better to use `file_exists` (maybe with fallback for image extensions). What do you think?

Otherwise working really nice.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new150 bytes

The Needs Review Queue Bot tested this issue. It either no longer applies to Drupal core, or fails the Drupal core commit checks. Therefore, this issue status is now "Needs work".

Apart from a re-roll or rebase, this issue may need more work to address feedback in the issue or MR comments. To progress an issue, incorporate this feedback as part of the process of updating the issue. This helps other contributors to know what is outstanding.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

gfarishyan’s picture

Patch for 9.5.3 users.

duaelfr’s picture

StatusFileSize
new26.39 KB

Patch from #122 doesn't apply for me using composer. I could get it to partly apply using the patch utility but then I had fatal errors.
Here is a new reroll for Drupal 9.5.3

socialnicheguru’s picture

Is there an update hook to install this file? core/modules/media/config/install/system.action.media_update_metadata.yml

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.

joevagyok’s picture

For now, I just went through the patch in #123 to identify the reason why the patch doesn't apply.
I found some mix-up in there, namely with Media.php and the media.post_update.php parts. I have taken the gitlab pull request as reference and re-rolled the patch over 9.5.9 version of Drupal core.

joevagyok’s picture

Fixed the spelling error in the #126 patch.

joevagyok’s picture

Fixed assertion for "Update metadata" operation in test and reroll it for D10.0.x.

joevagyok’s picture

StatusFileSize
new27.35 KB

Uploading the patch for D9.5.x as well, since #128 fails to apply to that version.

joevagyok’s picture

Status: Needs work » Needs review
smustgrave’s picture

#3271688: Remove source from media mappings may be related as I found when using metadata and trading out an image on a media deletes the files.

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new129 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

jweowu’s picture

Re-roll of #129 against Drupal 10.1.x.

jweowu’s picture

StatusFileSize
new27.15 KB

Re-roll of #129 against Drupal 10.1.x.

(#133 accidentally included an empty file at a deleted file path.)

steinmb’s picture

Status: Needs work » Needs review
jweowu’s picture

#120 is maybe a going concern?

(If that's pre-existing behaviour though, it could be a new issue.)

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new130 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

rkoller’s picture

I came across this issue and applied the patch in #134. In general the functionality looks real good and useful. While testing and playing around I've noticed a few details:

1. The status message when running Update metadata seems solely inform the user that the process started and ran, but not about its potential outcomes:

a) You are able to update a media item several times in a row but each time you get the same status message returned: Updated metadata on media item x. Just based on that status message, I would assume that the media item is getting updated with new changes on every run. But if you take a look at the Updated-column on /admin/content/media the timestamp for the media item remains the same and shows an update event in the past. A discrepancy and disconnect between the status message and the Updated-column.

b) After that I was curious and got inspired by #98 what would be the status message if you update the metadata for a remote video media type's media item where the URL is not reachable because the server is unavailable/down. Not sure if it is a legitimate way to simulate that scenario, but I've simply switched off the WLAN connection while the site was still running locally in DDEV.
In a Safari window I got You are not connected to the internet for the URL of the remote video's media item. While when I ran Update metadata I've received the same status message "Updated metadata on media item x" and the media item's thumbnail got removed alongside.

c) Not sure how likely it is that a local source file is getting deleted and the Update metadata process is run, but I've manually removed the original image of an image media type's media item. Again I've received the status message Updated metadata on media item x while the thumbnail got removed as in b).

I wonder if instead of informing the user that the process updating the metadata got started, would it be more helpful to provide information about the outcome of that process? That way the user would feel more in control. How about the following rough draft, not perfect at all, just wanted to communicate the gist about each scenario:

  • If everything runs through fine with changes in place on the media item's source the current status message could be used.
  • For scenario a) how about something like "Nothing to update. Media item x remains unchanged."
  • For scenario b) something like "The remote source for media item x is currently unavailable. Refreshing the metadata is not possible, try again later."
  • For scenario c) something like "The source file for media item x is missing, unable to refresh the metadata."

2. About the main question if there is a better alternative for describing the action compared to Update metadata? I am uncertain if there is a one or two worded alternative that explains the process clear and unambiguous as a whole. But from my perspective it should be avoided to use loaded terms that might create assumptions, associations, and expectations on the user's end. I think more neutral terms should be used instead preferably. From my perspective Update as well as Metadata are such loaded terms.

Update sounds familiar in the context of updating for example Core or contrib modules but in the context of entities it feels sort of unusual - in particular for locally stored media items in contrast to the remote video ones. In addition to that the term sort of overlaps with Edit one of the other options in the operations drop button. Personally my initial association was either to add something new to a media item and or it might entail additional pro-active manual steps.
Metadata, on the other hand, generates certain expectations. For audio you have for example mp3tags for mp3s, for images and locally hosted videos there is EXIF data and documents like PDFs have extensive metadata too. But if you for example try to create a view based on any of the media items it turns out the metadata is mainly about the thumbnail (in Core out of the box only for remote video and image media types) and the metadata attributes (name, filesize, filemime, width, height, etc) as mentioned in the issue summary. That is totally fine but the term metadata is potentially creating certain assumptions and expectations on the user's end and "might" lead into confusion therefore.

The proposed alternative Refresh (in #10 and #60) for the term Update might be the more clear and neutral choice. From my perspective the term Refresh implies a more unsupervised and automated process.

But in both comments I disagree with the proposed alternative for the term metadata. #10 suggests Refresh from Youtube but as @marcoscano points out in #36 not every media item is from Youtube therefore that suggestion is not applicable. On the other hand going with the labels suggested in #60 I consider those too wordy and it also raises the question what kind information is updated?

Refresh video information
Refresh image information
Refresh local video information
Refresh document information

But I think @devianintegral indirectly provided another viable alternative in #10 from my point of view. Why not use the term Source instead of Metadata? The term Source is more neutral but at the same time would imply that you synchronize your media items based on the informations available in the media item's source file. So how about the following changes?

The drop button in the operations column
All options in the select field are single worded, I wonder if it would make sense to stay consistent here?

Edit 
Delete
Update metadata -> Refresh

Bulk action options
For bulk actions I would provide some more context like the other options do and add "from source":

Delete media
Publish media 
Save media
Unpublish media
Update metadata -> Refresh from source

3. As recommended by @benjifisher in #56 https://www.drupal.org/docs/8/core/modules/media/creating-and-configurin... was already added as noted in #57.
But I wonder if it would make sense to create a help topic for the Update metadata task alongside. That way the user wouldn't have to leave the admin ui, plus it would be an easy and convenient way to explain the underlaying functionality as well what it entails aka what data is being updated/refreshed for the different media types.

Those were just my personal observations. I think it would be still good to discuss the issue, in particular point 2 about the microcopy, in a larger group in the weekly usability meeting (as suggested by @benjifisher in #108).

japerry’s picture

We've ran into this bug from a slightly different angle with Acquia DAM. We have implemented our own Metadata Sync controller which will attempt to resave the media entity. However the following code in the media entity ensures that if you change the metadata on the external source, it'll never update Drupal because the actual source asset id hasn't changed.

   // Only save value in the entity if the field is empty or if the
   // source field changed.
   if ($translation->hasField($entity_field_name) && ($translation->get($entity_field_name)->isEmpty() || $translation->hasSourceFieldChanged())) {
      $translation->set($entity_field_name, $media_source->getMetadata($translation, $metadata_attribute_name));
          }

In the meantime we've copied code from core and manually fixed it in our module. Once this issue is fixed, it'll make that code and our metadata sync controller redundant. So +1 to prioritizing a fix here!

marcoka’s picture

Applied #134 succesfully
I can "update" single items but the "update metadata" is not avaliable in the batch selection

Edit: My bad, did not see the db updates. Ran drush updb. Everything works fine now #134.

kensae’s picture

The patch in #134 failed for Drupal 10.2 on the media.routing.yml file, so I've adapted the patch slightly.

tostinni’s picture

StatusFileSize
new26.87 KB

We had a problema applying #141 following the change of getMetada() into getRawMedata in #3042423: Add new hook to Media module to modify OEmbed metadata #59

So here is a patch to apply those changes.

duaelfr’s picture

StatusFileSize
new26.4 KB

Patch from #142 was not applying because it has been created inside the core folder instead of at the root of the project.
This patch solves that issue and applies on 11.x (and 10.2)

duaelfr’s picture

StatusFileSize
new27.2 KB

I rerolled MR !3037 on 11.x based on the code from #134 and #141 (next patches were missing some code).

The attached patch applies on Drupal 10.2

szato’s picture

StatusFileSize
new27.72 KB
new1.94 KB

Thank you for this feature. Using it on D10.2.2.

For us, one issue remains: browser cache. E.g. updating YouTube video media, new thumbnails will be created but with the same hash (file name). If the browser cache is enabled, the new thumbnail will not be refreshed in the browser.

I'm attaching a patch to fix this issue, using timestamp as a suffix for thumbnail files, and care about removing the old ones on the force update. Moved image_path_flush().

The patch was created from MR3037 diff.

FYI: as @klausi noted, the scanDirectory() can become unusably slow if the directory contains many files.

joevagyok’s picture

@szato, we faced the same issue, however we felt changing the logic around the thumbnail name generation might be an overkill and we refrained from solving front-end cache issue by changing the back-end logic.

We have varnish configured on our sites, which further complicates the issue.
So we applied the changedTime of the thumbnail entity to the URI of the image style served, as a get parameter, in an md5 encoded format.
Browser cache relies on the URI too, like varnish does, so cache-busting by get parameter is an acceptable solution which is well separated from the back-end logic of thumbnail generation.
However, we found that the changedTime on the thumbnail entity is not update when we trigger this action, so that might be something to address here!

szato’s picture

@joevagyok, if you use hook_preprocess_image_style(), then you can use filemtime($variables['uri']) (the original image file modification time) for changedTime. I think it's better because the entity update time changes every time it's saved again, not just when the file is changed.

Luke.Leber made their first commit to this issue’s fork.

luke.leber’s picture

Rebased against 11.x -- hopefully the test bot doesn't freak out 😅.

Additionally, the concern brought up in #98 is still valid. Upon manual testing, the following procedure results in data loss:

  1. Create a media entity that implements oembed
  2. Disconnect from the public internet
  3. Update the metadata
  4. Notice that the original thumbnail is gone and is not replaced with a new one
firewaller’s picture

+1

agentrickard’s picture

Related to @japerry's comment in #139, I would note that this approach only handles base field values (string, integer, boolean), and there are cases where it would be important to have source data mapped to, say, a taxonomy term reference field.

The current code can't do that, but I would propose a follow-up issue to make it possible using an event handler.

I can work on that over in #3443757: Mapping metadata to reference field as a proof-of-concept. Posting here to see if there is an existing issue or indeed, a desire for that kind of feature.

recrit’s picture

Note: the latest MR 3037 does not have the browser cache busting that was added in #145.

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

karlshea’s picture

Rebased on 11.x, I added most of #145 except for removing image_path_flush() in Media, that will affect every type not just OEmbed.

Edit: actually I removed #145, it looks like there was some disagreement.

recrit’s picture

@KarlShea
Regarding your comment "I added most of #145 except for removing image_path_flush() in Media, that will affect every type not just OEmbed."
- That seems like an edge case. You would need to have another media type that is using the thumbnail file of an oEmbed resource. The normal usage would be a 1:1 of media to thumbnail file.

Regarding your comment "Edit: actually I removed #145, it looks like there was some disagreement."
There still needs to be a solution for busting cache - browser, edge cache, reverse proxy.

Options so far for cache busting:
1. The thumbnail generation approach as used in patch #145
Pros:
- Busts through all layers of caching - browser, edge cache reverse proxy.
- Automatically deletes the old file and any image styles for the old file.
- ???
Cons:
- A call to "getMetadata" for the "thumbnail_uri" assumes that the thumbnail is being set on the media entity. If it does not update the media, then this would cause deletion of the old file.
- ???

2. Add a modified timestamp URL query parameter as described in #146 and #147
Pros:
- Does not alter the thumbnail generation.
- ???
Cons:
- URL query parameters are not always respected by all layers of caching. For example, edge caching in Akamai could ignore the query parameter for some assets such images depending on the configuration in Akamai.
- Depending on the approach to get the modified time, you could be incurring a file system operation ("filemtime") on every image_style theme rendering.
- ???

duaelfr’s picture

StatusFileSize
new26.28 KB

Rerolled !3037 MR against 11.x
Patch attached for people needing this on 10.3.1

queenvictoria’s picture

Hey @DuaelFr applying that patch in 10.3.1 causes update.php to fail with [error] The installed version of the /Media/ module is too old to update. Update to a
version prior to 11.0.0 first (missing updates:
media_post_update_remove_mappings_targeting_source_field).
.
Specifically: removing the following lines allows the database update to pass:

+    'media_post_update_oembed_loading_attribute' => '11.0.0',
+    'media_post_update_set_blank_iframe_domain_to_null' => '11.0.0',
+    'media_post_update_remove_mappings_targeting_source_field' => '11.0.0',
duaelfr’s picture

StatusFileSize
new25.72 KB

@queenvictoria Thank you for letting me know! You're right, I did a mistake rerolling this and making the patch. Here is a new one.

banoodle’s picture

StatusFileSize
new51.51 KB

Thank you, @DuaelFr for patch #157 for D10.3.

It applied cleanly and works well, but it introduces the following error when drush updb is run:

 media_post_update_oembed_loading_attribute

"The following update is specified as removed in hook_removed_post_updates() but still exists in the code base: media_post_update_oembed_loading_attribute"

jphelan’s picture

I was getting the same error as banoodle but patch 159 seems to have resolved it.

banoodle’s picture

Status: Needs work » Reviewed & tested by the community

Oh, @jphelan, you are correct! I don't know why, but I didn't realize 159 is for 10.3 also. Thanks for pointing this out.

Patch for #159 works perfectly for me.

quietone’s picture

Issue summary: View changes

Thanks to everyone for getting this working and to RTBC!

I started triage and immediately saw that the remaining tasks state that a usability review is needed. So, I went through the comments and I do not see a review. Setting back to needs work. I read through nearly all of the comments and noticed some that have not yet been addressed. I have listed those in the 'remaining tasks'.

So, this just needs to work through those items to finish this off.

quietone’s picture

Status: Reviewed & tested by the community » Needs work
rkoller’s picture

I've had already added it to our shortlist on #3468437: Drupal Usability Meeting 2024-08-23. But MR3037 needs a rebase, on a none case sensitive file system ( i am on a mac) i run into the following error:

$> git checkout -b '2983456-expose-triggering-update' --track drupal-2983456/'2983456-expose-triggering-update'
error: The following untracked working tree files would be overwritten by checkout:
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Connection.php
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysql/Install/Tasks.php
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Connection.php
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestMysqlDeprecatedVersion/Install/Tasks.php
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Connection.php
	core/modules/system/tests/modules/driver_test/src/Driver/Database/DrivertestPgsql/Install/Tasks.php
Please move or remove them before you switch branches.
Aborting

it happens when the issue fork was created or last rebased before this issue went in https://git.drupalcode.org/project/drupal/-/commit/8b368d712d83900765744 on the 13th of august fixing spelling errors. the switch to camel case is the problem where the none case sensite file system in combination with git struggles and leads into this error.

rkoller’s picture

Issue tags: -Needs usability review

Usability review

We first discussed this issue at #3475677: Drupal Usability Meeting 2024-09-27. The link to the recording is https://youtu.be/cWtwA63z-IE. For the record, the attendees at the usability meeting were @amazingrando, @anmolgoyal74, @benjifisher, @rkoller, @simohell, and @zetagraph.
We revisited this issue at #3477161: Drupal Usability Meeting 2024-10-04. The link to the second recording is https://youtu.be/JPxvcpNXY0Q. For the record, the attendees at the second usability meeting were @AaronMcHale, @avani.bhut, @benjifisher, @rkoller, @shaal, @simohell, and @zetagraph.
Yesterday we revisited this issue for a third time at #3485024: Drupal Usability Meeting 2024-11-08. The link to the recording is https://www.youtube.com/watch?v=8DqSpKVK768. For the record, the attendees at the usability meeting were @benjifisher, @rkoller, and @simohell.

After taking a look at the current state of the MR, we’ve mainly focused on the points raised in #138, since those cover most of the remaining open questions from an UX perspective, and we’ve assessed their validity and relevance.

1. First, we went through the different scenarios that might happen aside a successful update:

Scenario A (No changes and therefore nothing to update):
It was considered as a nice to have but optional, not a blocker at this point, since it is a difficult task to determine if a media item is changed or not. So we leave it up to the people working on this issue if they want to cover scenario A already within the scope of this issue or if they would prefer to move it to a followup issue. Our consensus for the status message was:

Nothing to update. Media item [x] remains unchanged.

In contrast, the other two scenarios should definitely be covered within the scope of this issue, since in both cases content might be removed and/or lost. As Laura Klein stated in her book “Build Better Products” -

Good design doesn’t lose data or state just because a user has performed an action in a surprising way.

. To prevent any potential data loss, like missing thumbnails in the frontend, the group agreed on adding a confirmation step to each of the two scenarios. So that the user becomes aware, that something is off and that they might experience a potential subsequent data loss, when the metadata of a media item is updated from the source. In the case of remote media items, the source might simply be temporarily unavailable due to an outage, just as, for example, source files where the file folder is being mounted from a file system and that file system is unavailable - without a confirmation step, the data would get removed when the metadata is getting updated. Our recommendation for those two cases are as follows:

Scenario B (The local source of the media item is missing):

Description:
The source file for media item [x] is missing, unable to refresh.

Buttons:
Remove thumbnail
Cancel

Status message after...
…the Remove thumbnailbutton is clicked: Thumbnail removed for media item [x].
…the Cancel-button is clicked: Canceled. Media item [x] remains unchanged.

Scenario C (The remote media item the source is unavailable):

Description:
The remote source for media item [x] is unavailable.

Buttons:
Retry
Cancel

Status message after...
…the Retry button is clicked and the refresh was successful: Updated metadata on media item [x], while if the refresh fails, the confirmation form is shown again.
…the Cancel-button is clicked: Canceled. Media item [x] remains unchanged.

It has to be noted that we had a clear consensus about the importance of having a status message after a button on a confirmation form was pressed. There is always the possibility that someone is clicking a button on a confirmation form, either absent-minded or by a stray mouse click. The subsequent status message keeps the user in the loop and informed about the made choice.

Aside from the refresh of a single source, there is also the case of refreshing more than one source at once via bulk actions. Question is, how to handle things with more than one case of scenario B, more than one case of scenario C, or even a mix of both? You can’t run someone through a chain of tens of single confirmation pages. One option is that the confirmation pages for scenario B might be combined into a single page, the same as the confirmation pages for scenario C, or all confirmation pages for scenario B and C might be combined into a single confirmation page. But due to the fact that there is no existing UI pattern in Drupal Core yet, we don’t want to hold back the current issue, and we would recommend moving the bulk refresh of media items into a follow-up issue.

2. In regard to the microcopy, we considered the term Refresh as suggested in #10 to be the more clear and accurate choice. Update is a loaded term, in combination with the fact that all the other options (edit, delete, translate) on the Operations drop-down point to forms on other pages. That way, the user’s assumption might be that Update also points to a dedicated page or dialogue that entails an active manual interaction. In addition to that, all the other options in the Operations drop-down are single-worded verbs. Therefore, we would recommend the following change to the Operations drop-down option:

Update metadata -> Refresh

The term metadata is also sort of an abstract and ambiguous term in regard to its scope in this context. It is not clear what kind of data is getting refreshed by the option Update metadata. Is it only the associated fields or also something like the thumbnail, as already mentioned in the issue summary. To make things more explicit we would recommend the following change to the bulk action option label in the follow-up issue (again in line with the suggestion in #10):

Update metadata -> Refresh from source

3. We also checked if there were already help topics for the other options available on the media page, but we were unable to find any. So we had the consensus that it wouldn’t be necessary to add any instructions about the Refresh option to the help topics at this point.

4. One additional detail we’ve noticed during our testing. If you are manually replacing an image in the file system, then hit the Update metadata option, the thumbnail is properly updated on admin/content/media. But if you now click the Edit-button for the media item and then click the link to the source file, the old replaced image is still shown. Could that be a caching issue? We haven’t had the time to investigate in more detail.

I am setting the issue to Needs work and remove the Needs usability review tag. If you want more feedback from the usability team, a good way to reach out is in the #ux channel in Slack.

w01f’s picture

Wondering if this improvement will also work for images stored in cloud storage options such as S3, Azure, etc. via modules such as the S3 File System and Flysystem?
Once the images are stored in the external cloud storage, will this still work in capturing exif data on demand for already loaded/saved images and media?

duaelfr’s picture

StatusFileSize
new25.43 KB
new25.61 KB

Rerolled MR on last 11.x.
Made a minor change to help applying this with other patches.
Providing patches for 11.x and 10.5.x for composer.

Version: 11.x-dev » main

Drupal core is now using the main branch as the primary development branch. New developments and disruptive changes should now be targeted to the main branch.

Read more in the announcement.

carolpettirossi’s picture

StatusFileSize
new3.4 MB

The thumbnail image provided by Vimeo does not get updated when I run update metadata. See the screencast attached for reference.

I'm using this along with the video_embed_field module.

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

codebymikey’s picture

StatusFileSize
new27.22 KB

Attached a rebased version of the MR that should still works on 11.3.x.

However, the latest version of the MR targeting main will reference API that's only available on 11.4.0 (see https://www.drupal.org/node/3567619).

recrit’s picture

StatusFileSize
new30.35 KB

static patch of the latest MR 3037

recrit’s picture

Attached is re-roll of for 11.3.x since the `2983456-media_update_metadata-11.3.x-172.diff` started to fail applying for 11.3.9.

The original patch and MRs have a new `Media::updateMappedMetadata()` method that is causing the conflicts with the latest changes to Media.php in this commit a0601071a0e7ab91dde7ab1389489869951c39f6. For that reason, the attached patch does not use the new `Media::updateMappedMetadata()` . It was only used in one place and will continue to cause conflicts with core.

joevagyok’s picture

Thank you for this patch @recrit. It applies correctly and the feature is working as expected.

rkoller’s picture

one question to @anybody. you have rebased two MRs recently. which one of the two is the one that should be used, MR3037 or MR8529?

anybody’s picture

@rkoller sorry I just tried rebasing both, but as !8529 has merge target 10.4.x I guess that's the wrong one, but I'm not sure.
Code looks very similar, so after an interdiff we should probably just close and hide the wrong one to prevent further confusion.

codebymikey changed the visibility of the branch 11.x to hidden.

codebymikey changed the visibility of the branch 10.4.x to hidden.

codebymikey changed the visibility of the branch 2983456-expose-triggering-update-10 to hidden.

codebymikey’s picture

Hid the !8529 MR as it wasn't targeting main or passing phpcs.

Updated the MR so tests should now be passing again, however before this issue can be switched to 'Needs Review', the tasks in the Remaining tasks section needs to be reviewed and addressed.

rkoller’s picture

Issue summary: View changes

thanks for the rebase @codebymikey, based on your comment in #181 i've added #166 to the list of remaining tasks. haven't realized that there was a list of remaining tasks section for this issue and we haven't added the review there.

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

bircher’s picture

StatusFileSize
new30.89 KB

I also re-rolled the patch for composer for Drupal 11.x

bircher’s picture

StatusFileSize
new30.54 KB

also 11.3

id.conky made their first commit to this issue’s fork.

id.conky’s picture

Fixed the missing-thumbnail regression in MR !3037, commit 56f9fd1.

When a media source returns NULL for its thumbnail URI, loadThumbnail() correctly selects the default icon. However, the subsequent derivative flush receives the original NULL value and throws a TypeError, preventing the media entity from being saved.
The fix skips derivative flushing when the source thumbnail URI is empty. Kernel coverage checks null and empty-string metadata during creation and explicit refresh, preservation of unrelated derivatives, and replacement of the fallback when a thumbnail becomes available.

Two full replacement patches based on the #183 attachments are provided:
- 11.4.x: uses ImageDerivativeUtilities::pathFlush().
- 11.3.x: retains image_path_flush().

anybody’s picture

@id.conky thanks! Sadly pipeline is failing. If you could fix that, this could be set to Needs review again?

glynster’s picture

Status: Needs work » Needs review

Thanks to everyone who has kept this going: @codebymikey for the rebases and the D11.4 work, @id.conky for the null-thumbnail fix in #187, @recrit and @bircher for the patches, and @rkoller and the usability team for the very clear review in #166.

I've pushed commits to MR !3037 that work through the remaining tasks. I've kept the existing approach and the existing machine names (media.update_metadata, media_update_metadata) so sites already on the patch keep working.

Pipeline (#188)

  • Merged main. Nightwatch, eslint and the build job now pass. The only remaining red jobs are PHPUnit Unit [8.6-ubuntu], which also fail on main itself (pipelines 1010211, 1011407, 1012726), so they aren't caused by this MR.
  • PHPStan flagged the new functional test because it uses OEmbedTestTrait, whose helpers had no return types. Instead of adding more baseline entries, I gave those three trait methods : void and removed the 18 baseline entries that existed only because of them.

Usability review (#166)

  1. Labels: the operation and contextual link are now Refresh, and the action is Refresh from source.
  2. Scenario B (the local source file is missing) and scenario C (the remote source is unavailable) no longer change anything straight away. The user goes to a confirmation form with the wording from #166:
    • B: "The source file for media item %label is missing, unable to refresh." Buttons: Remove thumbnail / Cancel.
    • C: "The remote source for media item %label is unavailable." Buttons: Retry / Cancel. Retry shows the form again until the source can be reached.
    • Every outcome shows a status message, including "Canceled. Media item %label remains unchanged." Cancel is a button rather than a link so that message is always shown.
  3. Bulk: rather than moving bulk refresh to a follow-up, the action now skips items whose source is missing or unavailable and lists them in one warning. That way a bulk refresh never loses data and no chained confirmation UI is needed. If the usability team would still prefer bulk in a follow-up, it's a small change to drop the action from this MR.
  4. Scenario A ("Nothing to update") is left for a follow-up, as #166 allowed.

#80.2 (CSRF)
The route keeps _csrf_token: 'TRUE' and _entity_access: media.update. The confirmation form uses its own route, which is protected by the form token. New tests check that a request without a token, or with an invalid one, gets a 403, that a user without update access never sees the link, and that the media item is not changed.

#98 (refreshing a deleted or region-blocked video lost data)

  • A refresh first checks the source. Missing or unavailable sources take the confirmation path above instead of saving.
  • Even when an enforced update does run, a mapped field that already has a value is no longer overwritten with NULL just because the source returned nothing.

Two bugs found while testing

  • oEmbed refresh used stale data. ResourceFetcher caches resources in cache.default with no expiry. "Update metadata" therefore re-read the copy cached when the item was created, which I think explains #170 (the Vimeo thumbnail not updating). The refresh now drops that cache entry before re-fetching. Feedback welcome on whether this would be better as a method on the fetcher rather than a cache ID in the refresher.
  • #67, translations. Translation objects are clones, so non-default translations never saw the enforce flag. The thumbnail and oEmbed code read it per translation. The flag is now copied to each translation and cleared after the save. Thumbnails are also replaced straight away when downloads are queued, instead of being queued a second time.

Structure

  • MediaMetadataRefresher (an internal service) holds the source check and the refresh. The controller, confirmation form and action all use it, so the logic lives in one place.
  • MediaSourceStatus is an enum with three cases: Available, Missing and Unavailable.
  • enforceMetadataUpdate(): static and isMetadataUpdateEnforced(): bool now have native return types, and the docblock explains what an enforced update does.

Tests

  • Kernel tests: mapped fields are overwritten once and the flag resets; NULL doesn't erase a stored value; a missing thumbnail file falls back to the default; queued thumbnails are replaced straight away; every translation is refreshed; and the source-status checks.
  • Functional tests: the operations link flow; CSRF and access; the missing-file confirmation (Remove thumbnail / Cancel); the unavailable remote (Retry / Cancel / recovery); cache bypass; and bulk refresh skipping unsafe items.
  • I checked that the translation and cache-bypass tests fail without their fixes.
  • Local results: the media Kernel, Functional and Unit suites pass. PHPCS and cspell are clean for the changed files, and PHPStan passes on the hosted pipeline.

Remaining tasks I haven't touched: the thumbnail cache-busting decision from #156, and Scenario A. I'd suggest both as follow-ups.

rkoller’s picture

StatusFileSize
new31.25 KB
new51.92 KB

Thank you for all the work @glynster! I've manually tested all the points in MR3037 that we've raised in the context of the ux meeting back then. In the following a few details I've noticed. I am referring to the four points within the "usability review (#166)" section in #189:

Point 1

I can confirm, that the label for the CTA on the drop button got changed to Refresh. Thanks! But I am unable to find the action Refresh from source within the bulk action list? It doesn't matter if no checkboxes are being checked, or if only checkboxes for instances for Scenario A are being checked, or if only checkboxes for instances for Scenario B and/or C are being checked, nor if checkboxes for instances for Scenario A, B, and C are being checked, the CTA Refresh from source is not available in the bulk action list at any time.

Point 2

Scenario B - the image source of a media item is missing in the local file system)

If you press Refresh on a media item that is missing its image source in the local file system you are getting forwarded to a confirmation page. Probably out of scope for this issue, but something we ran into repeatedly and grew a strong consensus about in the weekly UX meetings is the fact that having dedicated pages for informational confirmation pages with just an H1 and one or two sentences of information and a confirmation button do not justify a dedicated confirmation page. That way most of the page is empty. For that kind of confirmation message, it might be more straightforward to use just a dialog modal instead. But as I said that is probably out of scope for this issue. Currently there is just an inconsistent mix of confirmation pages across core, some are using dedicated pages some are already using dialog modals instead. In regard to the behavior clicking the two available options on the confirmation page in scenario B:

a) If you press the Cancel button things behave as expected, you are being redirected to the media item list page and you get a status message stating Canceled. Media item statue.jpeg remains unchanged.. That looks good.

b) If you press the Remove thumbnail button and you are getting redirected to the media item list page, the thumbnail of the media item gets replaced by a prohibition sign and the status message says Thumbnail removed for media item league2.jpg.. But if you are looking at that particular media item, aside the missing thumbnail, everything looks fine. Same situation, if another user would run into that very same media item in the media item list. They only figure that the thumbnail is missing, aside that everything looks fine and there seems no need for any immediate mandatory action for that media item.

media item on the media item list page with the thumbnail missing and showing a prohibition sign instead

In consequence there a two expected reactions. Due to the fact there is no indication on the list row that also the image source is missing the person might simply press the Refresh on the drop button in the hope to refresh the media item and regenerate the thumbnail.

Instead, they are being presented again with the confirmation form informing them that the source file is missing and the two available options are another time to either remove the thumbnail or to cancel. The only problem this time, in this case the thumbnail for the media item with the missing image source was already removed. And in both cases if you press Remove the thumbnail or Cancel , in each case you are again redirected to the media item list page. For the former you again see the status message Thumbnail removed for media item league2.jpg., but this time it is misleading and/or wrong because there was no thumbnail to remove.

After the outcome of the refresh the person then might click the edit button, in case that wasn't already their first choice. There they will notice two more problems:

media item edit page showing the thumbnail missing and text field for the alt text

At first the removed thumbnail is still available on the media item edit page and second also on the edit page there are no helpful nor actionable information that the local file is missing for this media item. The link to the file name is still visible and removable plus it looks normal and correct.

Scenario C - For the remote media item the source is unavailable

I've tested scenario C by simply switching off my WLAN connection. I vaguely remember back then, when we reviewed the issue, we had a hard time to reliably simulate a scenario where it is impossible for Drupal to retrieve the meta data from the remote server. In my tests the error message on the confirmation form reads Could not retrieve the oEmbed resource. and it persists for every new press of the Retry button. So I am uncertain if switching off the WLAN connection is the correct choice simulating scenario C. The expected line would be The remote source for media item [x] is unavailable. instead.

Point 3

As already mentioned under Point 1, I am unable to trigger any refresh via the bulk actions.

Point 4

I can create the followup in the next few days and leave a comment and reference it to this issue.

The review was just my personal opinion. But I guess it would be good to put the issue onto the shortlist for the ux meeting to discuss the issue another time in a group context (in particular for the points i've outlined in the context of scenario B)

glynster’s picture

Thanks for the thorough manual testing, @rkoller! Here's where each point stands. I've pushed fixes for the two that were bugs.

Points 1 and 3: "Refresh from source" not in the bulk actions
The media overview shows every media action, and the new action ships in config/optional, so it should appear on a fresh install. I've added an assertion that it is in the bulk operations list on /admin/content/media. On a site that already existed before the MR was applied, the action is only created by the post-update hook media_post_update_install_update_metadata_action(). Could you check whether drush updb (or update.php) was run on your test site after applying the MR? If it was, and the action still doesn't appear, that's a bug I'd like to track down.

Point 2, scenario B: refreshing again after the thumbnail was removed
You're right, and this was a bug. Once the thumbnail had been removed, Refresh offered Remove thumbnail again, and "Thumbnail removed" was then a false message. Now, when the source file is missing and the item already shows a placeholder icon, the form says "The source file for media item %label is missing, unable to refresh. It already shows a placeholder icon." and offers only Cancel. The functional test follows your exact sequence: Cancel, Remove thumbnail, then Refresh again.

On the other two observations in scenario B:

  • The list and edit pages don't show that the source file is missing. That's true, but core doesn't flag missing media source files anywhere today, with or without this MR. I'd suggest it as its own follow-up rather than growing this one.
  • The dialog-versus-page question: agreed it's out of scope here. Happy for the UX meeting to decide.

Point 2, scenario C: "Could not retrieve the oEmbed resource."
Switching off WLAN is a valid way to simulate this. The form did output "The remote source for media item %label is unavailable." too, but the refresh check went through the oEmbed source plugin, which adds its own error message, and that was the prominent text. The check now fetches the resource itself and handles the failure, so only the form's own wording appears. The test asserts the plugin's error is absent, including after Retry.

Point 4
Thanks for creating the follow-up. +1 to putting this on the UX meeting shortlist, especially for scenario B.

Verification

  • The media Unit, Kernel and Functional suites pass locally.
  • PHPCS and PHPStan are clean for the changed files.
  • Both fixes are covered by tests, and those tests fail without the fixes.
  • Hosted pipeline: apart from the known PHPUnit Unit [8.6-ubuntu] failures that also happen on main, the only red job is WorkspacesMediaLibraryIntegration::testWidget. It's a JavaScript timing assertion in the media library widget that doesn't touch this code, and it passed on the previous two runs, so it looks like a random failure. A re-run of that job should confirm.
glynster’s picture

Follow-up on the CI note in #191: the re-run of PHPUnit Functional Javascript 2/3 failed again on the same assertion, WorkspacesMediaLibraryIntegrationTest::testWidget (inherited from EntityReferenceWidgetTest::testWidget(), line 370). That test is the known random failure tracked in #3613225, a race that loses under load. Line 370 checks data-disabled-focus on the open button straight after the insert, without waiting for the AJAX rebuild that adds it.

I ran it locally with Chrome for Testing as well. It passed most runs and failed intermittently. Nothing on that path (the media library widget and its insert flow) uses the refresh code changed here, it is the only failure among the 163 tests in that job, and the Kernel, Functional and other FunctionalJavascript jobs all pass. So I don't think this needs a change in this MR.

glynster’s picture

A correction to #192: I cited the wrong issue. #3613225 covers a different assertion in the same test method (the exposed filter race at line 249), and it was fixed in August. The failure here was a separate race.

The cause: after inserting media into a field that is then full, MediaLibraryWidget renders the open button with data-disabled-focus. Drupal.behaviors.MediaLibraryWidgetDisableButton then focuses the button and only sets disabled after a 50 ms setTimeout, so screen readers can catch up. EntityReferenceWidgetTest::testWidget() checked both attributes straight after the insert, without waiting, so it lost whenever that timer hadn't fired yet. It's timing-dependent, which is why it came and went between pipelines.

The fix (pushed to this MR): both places that assert the disabled open button now wait for .js-media-library-open-button[data-disabled-focus][disabled] using the test's existing assertElementExistsAfterWait(), instead of reading the attributes immediately. Locally WorkspacesMediaLibraryIntegrationTest::testWidget (which inherits this test) failed about 1 in 4 runs before the change and passed 20 of 20 after it, and EntityReferenceWidgetTest::testWidget passed 4 of 4. On the hosted pipeline that test now passes too.

It's a test-only change in media_library. Happy to move it into its own issue if maintainers prefer.

In the same pipeline, views FieldTest::testModalDialogTitle failed once, reading an empty dialog title where it expected "Content". That's Views UI, which this MR doesn't touch, and it looks like the same kind of dialog timing race. A re-run of that job should clear it.

rkoller’s picture

Issue tags: +Accessibility, +wcag1411

Thanks again @glynster for all the work! In regard to Points 1 and 3 ("Refresh from source" not in the bulk actions). i am not entirely sure if i've updated the database schema in my previous test. but i guess it is most likely i had not. but I had to drop the database for my test project yesterday and that way when checking out the recent changes for the MR of this issue i havent had installed the media module yet again. so that way there wasnt even the need for a database update due the fact it was a fresh install. and i can confirm from a brief test that the refresh from source option is now available in the bulk action select. it would have been really odd if it was not.

and i will see if we find a consensus with the other attendees for discussing this issue already in the next meeting on friday. until then i hold back my own personal feedback in regard to micro copy and general behavior of the MR - always better to base it on the consensus of a group than a single personal opinion.

the only thing already to denote, in dark mode in the default admin theme the prohibition sign has to have a color contrast of at least 3:1 to meet WCAG 2.2. SC1.4.11 but it only reaches a contrast of roughly 1.15:1 (#343434 vs #2a2a2d - i've only used a color picker) - in light mode the color contrast of the prohibition sign against the white background is fine.

glynster’s picture

Thanks @rkoller, good to hear the bulk action shows up on a fresh install, and thanks for taking it to Friday’s meeting.

On the dark-mode contrast: that prohibition sign is core’s existing no-thumbnail.png (in the media module since 2018), the default thumbnail for Image and oEmbed media. “Remove thumbnail” restores that default, but core already shows the same icon whenever a thumbnail is missing, for example a queued thumbnail that hasn’t been generated yet or a failed oEmbed fetch. So the 1.15:1 contrast under Claro’s dark mode is a pre-existing accessibility issue rather than one introduced here. I’d suggest a follow-up issue, either giving media thumbnails a light background in Claro’s dark mode or replacing the PNG icons with SVGs that follow the theme colour, so it gets fixed everywhere the icons appear. I’m happy to open it.

rkoller’s picture

Claro never had a dark mode only its subtheme Gin, which is the basis for the default admin theme. if that contrast problem applies to more iconography aside the prohibition sign then i probably agree that it is most likely out of the scope for this issue. but will ask around and also add that detail to the discussion in case we get to this issue next friday.

glynster’s picture

Thanks @rkoller, and you’re right, I should have said the Gin-based default admin theme, not Claro. On whether it affects more icons: it does. I checked all four of the media module’s placeholder icons (no-thumbnail.png, generic.png, video.png, audio.png). All four use the same #333333, which gives about 1.13:1 against #2a2a2d (and 12.63:1 on white). So every media item without a real thumbnail fails SC 1.4.11 in dark mode, including documents, audio and video files and failed oEmbed fetches, not just the “Remove thumbnail” case. That points to a follow-up for the icons themselves; I’ll open one after Friday’s meeting.

rkoller’s picture

StatusFileSize
new57.23 KB

thanks for more digging into the media module. yeah hopefully we'll get to discussing the issue tomorrow. by the way while preparing a bit of demo content in case others agree revisiting this issue ive noticed one other noteworthy detail. i've found the no-thumbnail.png under /admin/content/files. to me the icon is not really part of the users content but content the site provides to the user so i am not sure if that icon should be listed there at all? i've noticed it cleaning up the images ive uploaded for testing.

two images on the files list page

it is used in zero places because ive cleared the list of media items before i went to the file list page, so at that point nothing was left.

benjifisher’s picture

At #3632583: Drupal Usability Meeting 2026-10-30, one point we discussed is whether the contrast problem with the icon has to be fixed as part of this issue. If that problem already shows up before this issue, then I think this issue can be fixed before or after the contrast problem is fixed. At the meeting, we were not sure how to see that icon.

Here are some testing steps:

  1. Install Drupal with the Standard profile.
  2. Apply the core image_media_type recipe.
  3. Edit field_media_image on the Image media type and make it not required.
  4. Create an Image media item with field_media_image empty.
  5. View the media library.

I tested those steps, but I leave it to someone else to switch to dark mode and check the contrast.

AI disclosure: I used Claude to come up with the steps, but I wrote this comment myself.

rkoller’s picture

Usability review

We discussed this issue at #3632583: Drupal Usability Meeting 2026-10-30. The issue will have a link to the recording. The attendees at the usability meeting were @benjifisher, @rkoller, and @simohell.

In the following a brief summary of our discussions:

  • In regard to #190 @benjifisher remembered that there was an issue for core to convert all the existing confirmation pages to use modal dialogs instead. So we've agreed on that this conversion would be out of scope for this issue since that should happen at once in that aforementioned issue. (*After the meeting I've searched the issue queue. I was able to dig up that particular issue, and it turns out to be a meta issue: #1842036: [META] Convert all confirm forms to use modal dialog. To me it looks like this issue is only for converting existing confirmation form pages in core, so it might be better at this point not to add another confirmation page so it could get converted at a later point. But that is only my personal opinion post meeting, and I haven't got any feedback on the meeting thread on Slack yet.)
  • In regard to the color contrast issue in dark mode with the prohibition sign (#194) the group, as already indicated by @benjifisher in #199, agreed on the following approach: do the issue in either order if there are more occasions; if it is the only place, postpone the issue. I've tested the unchecked required state approach Benji suggested in #199, and as expected the problem turns up there as well without any code of the MR involved. Plus, @glynster denotes in #197 that also three more images within the media module are directly affected, but so are most likely all images for the default admin theme. So the consensus is opening a separate follow-up, and @glynster already offered opening it after the meeting - thanks for that!
  • There was a clear consensus that any media item missing their source image is neither recognizable on the media item list page nor on the edit detail page for a media item, and therefore poses a serious problem overall. But that situation already existed before this issue and was not introduced by this MR; it only gets surfaced and amplified by this MR. Therefore, we've agreed that it is out of scope even though it heavily harms the overall user experience due to the lack of situational awareness for the users. Nevertheless, I will create an initial follow-up later tonight.
  • One of the occasions that is affected by that lack of situational awareness is if a user is triggering a refresh on a media item that already ran a refresh, dropping the thumbnail. That leads into sort of a dead end that requires one unnecessary confirmation form informing the user that the source file is missing on this media item with the only option to cancel. That is not the best experience for the user. The options of extending the label to something like Refresh (source missing) and disabling the CTA would be too lengthy compared to the rest of the one-worded verbs, or simply hiding the CTA, were both no viable options the group discarded. The only reasonable approach would be to clearly label media items with a missing source image in the aforementioned follow-up and keep the confirmation page until then. So the only remaining noteworthy problem with the microcopy on the newly introduced confirmation step for a media item without a source image and a removed thumbnail is the question of what It refers to in: The source file for media item [filename] is missing, unable to refresh. It already shows a placeholder icon.. The group had a clear consensus to make the second sentence slightly more verbose but bridge the gap between the two sentences, keeping a common thread by using the following instead: The source file for media item [filename] is missing, unable to refresh. That is why the media library shows a placeholder icon.. I'll add a suggestion on the MR after posting the comment.
  • Subtract the number of warnings from the overall number of media items for running a bulk action. So if there are 3 skipped out of 5 refreshed media items, the status message should only state that a refresh from the source was applied to two items in that case. Because the media items that were skipped and listed in the warning message have not been refreshed.

If you want more feedback from the usability team, a good way to reach out is in the #ux channel in Slack.

rkoller’s picture

glynster’s picture

Thanks @benjifisher, @rkoller and @simohell for going through this at the meeting, and @rkoller for opening #3634476.

I've pushed the following to MR !3037:

  • The @todo on Media::updateThumbnail() (@benjifisher's MR note): removed. #2878119 was closed in favour of this issue, so it no longer points anywhere useful.
  • Wording: applied the group's suggestion as-is: "The source file for media item %label is missing, unable to refresh. That is why the media library shows a placeholder icon."
  • Bulk count: the "Refresh from source was applied to @count items." status message isn't generated by this action. Views' BulkForm::viewsFormSubmit() adds it for every bulk action, using the number of selected items it could access, before the action runs, and an action has no way to change it. Fixing that properly means a small Views API change so actions can report how many items they actually processed, which would help Publish/Unpublish and contrib actions too. I've opened that as a follow-up: #3634563. Meanwhile, the warning in this MR now states it explicitly, for example: "3 of the 5 selected media items were not refreshed because their source is missing or unavailable: A, B, C."

On the other points:

  • Contrast follow-up: opened as #3634562, per the meeting's consensus. All four media placeholder icons use the same #333333. Thanks @benjifisher for the reproduction steps in #199; I've used them there. Since the contrast problem now lives in that issue, the Accessibility and wcag1411 tags may fit better there than here.
  • no-thumbnail.png under /admin/content/files: that predates this MR. The media module copies its icons to public://media-icons/generic when it's installed, and the first time an icon is used as a thumbnail, Media::loadThumbnail() creates a permanent file entity for it. That's why it stays listed even with no media left. I agree it's site-provided rather than user content, so it seems worth its own issue rather than something to change here.
  • Fewer confirmation pages (#1842036): noted. I've kept the confirmation step as the group agreed, and it uses ConfirmFormBase, so it would be converted along with the rest under that meta issue.

If the usability team is happy with these changes, is anything else needed from the usability side before this can move on?

needs-review-queue-bot’s picture

Status: Needs review » Needs work
StatusFileSize
new90 bytes

The Needs Review Queue Bot tested this issue. It no longer applies to Drupal core. Therefore, this issue status is now "Needs work".

This does not mean that the patch necessarily needs to be re-rolled or the MR rebased. Read the Issue Summary, the issue tags and the latest discussion here to determine what needs to be done.

Consult the Drupal Contributor Guide to find step-by-step guides for working with issues.

glynster’s picture

Status: Needs work » Needs review

Merged current main to resolve the conflict the bot reported, which was only in core/.phpstan-baseline.php. Since main now runs PHPStan at level 3, I also fixed the 20 new errors in this MR's code and tests. One baseline entry is added for MediaUpdateMetadataControllerTest: the $container assignment in OEmbedTestTrait, which other test classes using the trait already have. No behaviour changes. Setting back to Needs review, since none of the earlier feedback is outstanding.