I finally worked this out, using Views (which is a way of querying the database and presenting lists of data). My design places the View as a block on my taxonomy term pages, so I refer to a block display in this method rather than a page display:
BASIC VIEW TO SHOW ALL MEDIA
- Structure > Views > Add view
- Enter View name and Description
- Show Media of type All sorted by Unsorted
- Select "Create a block"
- Unformatted list of Fields
- Adjust "Items per block" as appropriate (e.g. 25)
- Save and edit
- Scroll down and check all your Media names are listed in the Preview section, to ensure the basic View is working correctly.
- FIELDS > Add > Rendered entity (Category: Media).
- Here you could alternatively add fields such as Image, Video URL and File rather than the general Rendered entity.
- Choose the appropriate View mode > Apply. In my case I had set up a "Preview" display mode in /admin/structure/media/manage/MyMediaType/display, with a thumbnail image format and most fields disabled.
- Scroll down to check your media is listed below the names.
- Click "Media: Name" > Remove, if you don't want it. It's often unnecessary for media.
- Save
CONTEXTUAL FILTER TO SHOW ONLY THIS TERM'S MEDIA
Here we need to make sure that in this block we will only display media that refers to the term whose page the block will be seen on. In this case, that reference is made in a field on my media labelled "Primary Taxon".
- ADVANCED > CONTEXTUAL FILTERS > Add
- Select "Primary Taxon (field_primary_taxon)" (Category: Media)(or whatever your field is called) > Add and configure contextual filters
- WHEN THE FILTER VALUE IS NOT AVAILABLE > Provide default value > Type: Taxonomy term ID from URL > Select (only) "Load default filter from term page" > Apply > Save. We have to supply the value this way because, unlike a page, a block does not have a URL to find the value in.
- For testing, find the taxonomy term ID number ("TID") for some of the terms in your vocabulary. You can find these in the URL of the taxonomy term's page. For example my Roses page has URL
.../taxonomy/term/86
so the TID is 86. If you have a module such as Pathauto providing URL aliases, then you can find the TIDs by visiting .../admin/structure/taxonomy/manage/MyVocabulary/overview
, hovering over "Edit" and looking at the URL at the bottom left of your browser.
- In the Preview section, test the View is filtering correctly by entering your different TIDs in the "Preview with contextual filters" box and click "Update preview". For example if I enter 86, I see only media for which I had entered "Roses" in the "Primary Taxon" field.
RELATIONSHIP & CONTEXTUAL FILTER TO SHOW CHILD MEDIA
To list media that refers to children of the term whose page that the block will be seen on, we need to find media whose parent refers to that term. This "reverse thinking" helps with understanding contextual filters; think of the relationship from the thing you're listing, not from the thing you're displaying the list on. My media has no "Parent Taxon" field; that would have been redundant because terms' parents are inherently defined in the hierarchical vocabulary they belong to. This means we can't just add "Parent Taxon" as another simple contextual filter. So we need to extend the range of database tables that Views can query by adding a relationship:
ADVANCED > RELATIONSHIP > Add > Select "Taxonomy term referenced from field_primary_taxon" (Category: Media) > Add and configure relationships > Do not select "Require this relationship" > Apply. This looks at the taxonomy term specified in the media's "Primary Taxon" field and "pulls in" that term's taxonomy information so that Views can query it with our next contextual filter:
ADVANCED > CONTEXTUAL FILTERS > Add. You will see that the list of available filters to choose from is now longer than when we chose the first contextual filter, because of the new relationship.
- Select "Parent term" (Category: Taxonomy term) > Add and configure contextual filters
- Same as before... WHEN THE FILTER VALUE IS NOT AVAILABLE > Provide default value > Type: Taxonomy term ID from URL > Select (only) "Load default filter from term page" > Apply.
- OTHER > Query settings > Select "Contextual filters OR" > Apply > Save. This means results will be listed that pass either the 1st contextual filter OR this 2nd one. Without this, it will filter for media matching both one AND the other, and no results will be displayed.
- Note that after this 2nd contextual filter has been added, the view can no longer be previewed below (I don't know why). So we need to place the block on a page...
PLACE THE BLOCK ON THE PAGE
- Go to Structure > Block layout > Find appropriate theme(s) (in horizontal sub-menu at the top) and region > Place block > Find your new block > Place block > De-select "Display title" if you want...
- We only want our block to show on taxonomy term pages, however in the "Visibility" section there is unfortunately no "Taxonomy term page" listed under "Content type" (I don't know why). So click "Pages" and type
/taxonomy/term/*
in the box > Save block > Save blocks (at the bottom). This restriction will be applied before URL aliasing, so don't worry if you have a Pathauto alias set for your taxonomy pages.
- Visit an appropriate taxonomy term page to check the View works. You may need to refresh the page and/or clear all caches (at
.../admin/config/development/performance
), especially if you haven't disabled caching.
DISPLAY THIS TERM'S MEDIA BEFORE CHILDREN'S MEDIA
The default order of display of the media is by the "Authored on" time. To display this term's media before child term's media:
- Install the Views Argument Order Sort module (there's currently only a development version).
- SORT CRITERIA > Add > Select "Multi-item Argument Order" > Add and configure sort criteria > Apply > Save. This put this taxon's media before child taxa's media, whether I selected "Sort ascending" or "Sort descending".
- Despite exposing this sort criterion to users to try and allow them to change the sort order, I was unable to get that working. If you know how, please comment.
FURTHER GROUP MEDIA BY TAXON
You can group the media by the term they refer to, with headings:
- FIELDS > Add > Primary Taxon > Add and configure fields > Select "Exclude from display" (not necessary but you can still group by this field even if it is hidden like this) > De-select "Link label to the referenced entity" (also not essential) > Apply
- FORMAT > Format > Settings > Grouping field Nr.1 > Media: Primary Taxon > Apply > Save > Test the view.
VALIDATION BUG?
In theory, validating the output of the 2 contextual filters as follows is a good idea:
- Click the contextual filter > WHEN THE FILTER VALUE IS AVAILABLE OR A DEFAULT IS PROVIDED > Select "Specify validation criteria" > Validator: "Media" > Select only the Media types you wish to show (or none for all of them) > Select "Validate user has access to the Media" > Apply > Save.
However, this validation prevents the view from displaying anything. Please comment if you know why, or if you think this is a bug.
IMPROVEMENT SUGGESTIONS
- HEADER > Add > Result summary. This will give you a summary of results at the top of the block, as is standard on a page display.
- Select ADVANCED > Other > "Use AJAX" to reduce page refreshes.
- In some cases a Table view is useful, rather than unformatted list etc., because you can sort the media by field columns if you add extra fields.
- You can add a "Media type" regular filter (not contextual) and expose it to visitors to allow them to show only certain type(s) of media (e.g. Images or videos or both). The Better Exposed Filters module allows the choices to be shown as checkboxes rather than as a drop-down menu, although I have a bug with it (link to follow) at the moment (version 8.x-3.0-alpha3 in Views 8.4.4).
- The Views Infinite Scroll module can make for a nice improvement over standard paging if you have a lot of media.
Here is what my View looks like (with the optional Infinite Scroll and AJAX selected):

I have little Drupal experience, so feel free to suggest refinements to this method.