Species External Entity

A Drupal module that turns a species name or Catalogue of Life ID into a live entity: taxonomy, photographs, conservation status and ecological data drawn from public biodiversity APIs and mirrored locally for speed.

 

## What it is

Species External Entity, machine name `species_ext`, turns a species name or a Catalogue of Life taxon ID into a full Drupal entity. Its taxonomy, description, photographs, conservation status and ecological relationships are gathered live from public biodiversity APIs and then mirrored locally so pages stay fast.

It ships as two modules: `species_ext`, the data engine, and the optional `species_ext_map`, a presentation layer that turns the resolved fields into maps, charts and a photo gallery. The data engine runs in production on [Biodiversa](/projects/biodiversa), Museo Avellonia and the [Quercus Project](/projects/quercus-project). On the Quercus Project, its species data also feeds MADDev's [Ecosystems](/products/ecosystems) viewer.



 

 





 

## At a glance

Modules`species_ext`, the data engine: source plugins, resolvers, the local mirror and the `species_x` entity's field types; `species_ext_map`, an optional presentation layer for maps, charts and a galleryDrupal core10 or 11Requires`entities_ext`, `dynamic_mirror_base`, `key` and Drupal core's Link module; `species_ext_map` additionally needs the Leaflet contrib moduleEntity type`species_x`, keyed by the Catalogue of Life taxon IDRenderingStandard, BigPipe or progressive loading, so critical fields appear at once and enrichment fields stream in without blocking the pageStatusLive in production on Biodiversa, Museo Avellonia and the Quercus Project

 

 





 

## What visitors and curators see

On sites that install the optional `species_ext_map` submodule, a species page adds a year by year GBIF occurrence density map drawn with Leaflet, a phenology histogram, a population trend chart, a photo gallery, and a lookup and search widget; it presents only what `species_ext` has already resolved and makes no data calls of its own. It runs on [Museo Avellonia](/projects/museo-avellonia) and the Quercus Project. On the Quercus Project, species pages also carry SEO markup and a pretty `/species/{name}` URL rather than the entity's internal path.

A curator can mark a species featured and add their own photographs through a small local entity that sits alongside the resolved data. Those additions are never overwritten by the monthly refresh from upstream.



 

 





 

## What it adds to a Drupal site

### Entity type

`species_x`: an external entity keyed by the Catalogue of Life taxon ID, with fields, view modes and Manage display like any other Drupal entity, even though nobody types its content in by hand.

### Source plugins

One `@SpeciesSource` plugin per upstream, walked by weight until one resolves: a local Catalogue of Life checklist with no network call, the Catalogue of Life API, Wikipedia, GBIF, iNaturalist, the IUCN Red List, EOL and GloBI.

### Routes

`/admin/config/services/species-ext`: enable or disable each source, set the IUCN API key and choose the rendering mode. `/species-ext/lookup`: a POST endpoint for autocomplete and taxon lookup. A disambiguation route handles a name that matches more than one taxon.

### Drush commands

`species-ext:warm`, to warm one or more species immediately; `species-ext:warm-queue`, to drain the warming queue immediately.

### Field locking

A `SpeciesDmbAdapter` connects `species_x` fields to `dynamic_mirror_base`, so an editor can lock a resolved field or override it locally, through the same workflow as MADDev's other external entity modules.



 

 





 

## Data sources and licences

- **Catalogue of Life**: taxonomy, the accepted name, authorship and synonyms; a local checklist table also answers common lookups with no network call
- **Wikipedia**: a plain-language description
- **GBIF**: occurrence records, distribution, phenology data and a map bounding box; for `species_ext_map`, a pre-rendered occurrence density tile layer that needs no GBIF key and downloads no raw occurrence data to the server
- **iNaturalist**: a common name, a taxon summary, photographs, observation counts and recent sightings
- **IUCN Red List**: conservation status, population trend, threats and habitat
- **EOL** (Encyclopedia of Life): a description when Wikipedia has none
- **GloBI** (Global Biotic Interactions): the interaction web, what a species eats, is eaten by, and lives on

A species is resolved once, the first time it is featured, and materialises into a local mirror table so pages stay fast; a cron job refreshes it monthly. Outbound calls are batched and de-duplicated through the shared `request_bus`, and a source that times out never blanks a value already stored. GBIF, iNaturalist and IUCN Red List keys are optional, held in the `key` module rather than in code; without an IUCN key the module degrades cleanly rather than failing.



 

 





 

## Design decisions

- **Field-level source resolution.** Each field is resolved independently from whichever upstream supplies it, rather than one API being authoritative for the whole record.
- **Weighted fallback identity.** Source plugins are walked by weight and the first that resolves wins. The Catalogue of Life covers just over 80% of known species, so a species missing from it still gets an identity from Wikipedia's article title, an iNaturalist ID or a GBIF taxon key.
- **Materialise once, refresh monthly.** A species is stored in a local mirror the first time it is featured, rather than the page firing up to seven live API calls on every view, and is then kept current by cron rather than on demand.
- **Curator edits are never clobbered.** A featured flag and curator photographs are stored locally and survive every upstream refresh.
- **Built to be reusable.** Nothing in `species_ext` is specific to one site; a site's own concerns stay in that project's own module.



 

 





## Start a project.

Tell us about the species or biodiversity data your Drupal site needs to show.



[Get in touch →](/contact)