Skip to content

Image Taxonomies

padams edited this page Oct 14, 2026 · 4 revisions

Image Taxonomies

PhotoPress files each uploaded image under taxonomy terms read from the metadata embedded in its file: camera, lens, location, keywords, and any other field you map. The settings are in the Image Taxonomies card of the Metadata tab under PhotoPress › Settings.

Requirements

  • WordPress 6.6 or later.
  • PHP's DOM extension, to read XMP.
  • PHP's exif extension. PhotoPress calls exif_read_data() on JPEG and TIFF files for the camera make and model (XmpReader.php#L481).
  • Archive pages need the Image taxonomy pages switch on in the Pages & Search tab (on by default).

Settings

Open PhotoPress › Settings and select the Metadata tab.

The Image Taxonomies card: Standard Metadata, Hierarchical Keyword Metadata and Custom Metadata tables
The Image Taxonomies card with its three tables and the list of parent keywords found in the photos.

Control What it does Default
Image Taxonomies switch ("Let visitors browse your photos by camera, place, person and more.") Registers the image taxonomies and fills them on upload. Off, the taxonomies are not registered and uploads get no terms. Terms already set stay in the database. Saves at once. On
Reprocess all images Starts the Re-read image metadata background job over every image: terms, alt text and description, as on upload. Asks for confirmation. —
Advanced options › Empty the terms of images whose files have no metadata for a taxonomy With the box checked, Reprocess all images empties a taxonomy's terms on an image whose file has nothing for it. Unchecked, those terms are kept. Unchecked
Standard Metadata table, On switch Turns one standard taxonomy on or off. Saves at once. On
Standard Metadata table, Edit Opens the taxonomy's edit screen: names and Public switch. —
Hierarchical Keyword Metadata, Add Opens Add Hierarchical Keyword Taxonomy. —
Hierarchical Keyword Metadata, Edit / Remove Edits a parent keyword, or removes its taxonomy after a confirmation. —
Advanced options › Prefix separators The characters between a prefix and the rest of a keyword (genre: Portraiture). Separate several with spaces, such as : >. Empty: prefixes are not read. Hierarchies are read either way. :
Custom Metadata, Add Opens Add Custom Metadata Taxonomy. —
Custom Metadata, Edit / Delete Edits a custom taxonomy, or deletes it after a confirmation. —

Each table has these columns:

Column Shows
Taxonomy The plural name.
How it's filled / Parent keywords / Field What fills the taxonomy.
Public Yes, or No for an admin-only taxonomy.
Archive pages The archive URL pattern, such as /camera/…, or a dash when the taxonomy has no archive pages.
Terms The number of terms in the taxonomy, linked to its terms screen under Media (edit-tags.php?taxonomy=<ID>&post_type=attachment).

Removing or deleting a taxonomy removes its archive pages. Its terms stay in the database and return if you add the same taxonomy again.

Editor screens

Each Edit or Add button opens a screen within the tab, with a ← Image taxonomies link back. Every screen has these fields:

Control What it does Default
Plural name The taxonomy's name in the admin and in the Image Metadata block's labels. From the field or parent keyword
Singular name Sets the archive URL: /<singular name>/<term>. Must be unique among the image taxonomies by its URL form. From the field or parent keyword
Public On: each term has an archive page and the Image Metadata block shows the terms. Off: the taxonomy is for the admin only (see Public switch). On

The line under the Public switch shows the archive URL. When a saved public taxonomy's URL would change, it adds that the old pages will stop working.

Add Hierarchical Keyword Taxonomy (and Parent keyword: ) adds:

Control What it does
Parent keyword The top-level keyword whose sub-keywords become the taxonomy's terms, such as Genre for Genre › Portraiture. One keyword only: ›, > and `
Found in your photos: Up to eight prefixes found in Keywords terms that no parent keyword takes. Click one to fill Parent keyword. Shown on the Add screen only.
Also written as (optional) Other names for the same parent keyword, separated by commas.
What a photo gets A preview table: the keyword in the photo, the taxonomy, the term, and its archive page.

A name already used by another parent keyword is refused.

Add Custom Metadata Taxonomy (and Custom metadata: ) adds:

Control What it does
Metadata field The field to read, chosen from a list grouped by where photo software sets it (IPTC Core, IPTC legacy, IPTC Extension groups, Getty Images, Rating and label, Camera and software, Other). The help under it says what the field holds and links to the IPTC Photo Metadata User Guide. Fields used by Standard Metadata or another custom taxonomy are not offered.
What a photo gets A preview row with the field's example value.

The Standard Metadata edit screen has no field picker. It lists Fields read, in order for the taxonomy.

Save and Save and reprocess

Screen Buttons
Standard Metadata edit Save
Hierarchical keyword add or edit Add or Save, and Save and reprocess N affected images when the change affects images already uploaded
Prefix separators Save, and Save and reprocess N affected images when the change affects images
Custom Metadata add or edit Save, and Save and reprocess all images once a field is chosen

A Save and reprocess button saves, returns to the tab, and starts a background job limited to the affected taxonomies. That job leaves alt text and descriptions alone. Its progress shows at the top of the Image Taxonomies card. Next to the button, Advanced options reveals Empty the … of images whose files have no …, which works as on Reprocess all images.

The affected images, for a parent keyword or separator change, are those with terms in a changed parent keyword's taxonomy, or with Keywords terms starting with one of its names, before or after the change (metadata.php#L185). A separator change counts every parent keyword as changed. The taxonomies reprocessed are the changed parent keywords' and Keywords.

While a re-read runs, a new Save and reprocess is queued and starts when the running one finishes (metadata.php#L284).

A parent keyword found in the photos given a taxonomy, and its images reprocessed
Adding a taxonomy for a parent keyword found in the photos, then reprocessing the images it affects.

How it works

Standard Metadata

Six built-in taxonomies. Each reads every place its information is stored, in order (StandardMetadata.php, TermRouter.php#L288).

Taxonomy ID Fields read, in order
Cameras photos_camera EXIF Make and Model; XMP tiff:Make and tiff:Model; a model alone
Lenses photos_lens exifEX:LensModel; EXIF LensModel; aux:Lens
Cities photos_city photoshop:City
States photos_state photoshop:State
Countries photos_country photoshop:Country
Keywords photos_keywords Keyword hierarchy; dc:subject

Camera names are cleaned so one camera is one term (StandardMetadata.php#L86):

  • The make becomes a brand name from a built-in list, or loses suffixes such as Corporation, Co., Ltd., Inc., AG, GmbH. An all-capital make longer than three letters is title-cased. NIKON CORPORATION NIKON D800 gives Nikon D800.
  • A brand repeated at the start of the model is removed. Canon Canon PowerShot G9 gives Canon PowerShot G9.
  • A bracketed serial number and anything after it is removed.
  • A make or model naming editing or scanning software (Adobe, Photoshop, Lightroom, Capture One, TIFF file, SilverFast, VueScan) gives no camera.

Lens values that are placeholders, such as ---- or -- mm f/--, are skipped. An unknown aperture is dropped: 125 mm f/-- gives 125 mm.

Keywords and hierarchies

PhotoPress reads keywords as paths (TermRouter.php):

  • The keyword hierarchy comes from the first of these fields the file has: lr:hierarchicalSubject (levels split on |, as Lightroom and Capture One write it), digiKam:TagsList (/), MicrosoftPhoto:LastKeywordXMP (/).
  • Each plain keyword in dc:subject is read too, unless it matches a level of a hierarchy path (case-insensitive).
  • When the two lists disagree, the image gets the keywords of both.

A path not under a parent keyword goes to Keywords with its levels nested: Places|USA|California gives California under USA under Places, at /keyword/places/usa/california. The image gets every level, so a search for any level finds it. A word used both as a plain keyword and inside a hierarchy becomes two terms.

Hierarchical Keyword Metadata

A parent keyword gives its sub-keywords a taxonomy of their own. A path whose first level is one of the parent keyword's names goes to that taxonomy, without the parent level, its remaining levels nested (TermRouter.php#L270).

Keyword in the photo Parent keyword People, taxonomy People (singular Person)
`People Jane`
`People Family
people: Jane (prefix separator :) Jane
People alone A Keywords term People
  • Names are matched without regard to case. Also written as adds further names for the same taxonomy.
  • A prefixed keyword is split only when its first part is a parent keyword name. Star Wars: A New Hope stays whole. The keyword is split at every occurrence of the separator: people: family: Jane gives Jane under family.
  • A keyword's prefix must come before the separator. A keyword that starts with the separator is not split.

Parent keywords in your photos with no taxonomy lists up to 20 prefixes found in Keywords terms (prefix: value) that no parent keyword takes, most photos first, with three example values (metadata.php#L404). Until a taxonomy takes them, these keywords stay in Keywords as written. Each has Add taxonomy, which opens the Add screen with the prefix filled in. A prefix of four or more letters that is one letter away from an existing parent keyword name (penre for genre) has Add to instead, which adds it to that parent keyword's names.

Custom Metadata

Every value of the chosen field becomes a term, as written. A field with several values gives the image a term for each. Custom taxonomies are flat.

  • Structured parts. Some fields are parts of a structure, such as Iptc4xmpExt:LocationShown/Iptc4xmpExt:City. Each entry of the structure gives its part (TermRouter.php#L317).
  • Coded fields. Model Release Status, Property Release Status, Minor Model Age Disclosure and Digital Source Type are written as codes or URLs. They are filed by their vocabulary names in US English: MR-UMR gives Unlimited Model Releases, trainedAlgorithmicMedia gives Created using Generative AI (TermRouter.php#L96). An unknown code is written out from its own words.
  • Separated values. Getty Images Personality, written by Capture One as one text (Jane;John), is split on ;.

When terms are set

Event What PhotoPress does
Upload (add_attachment) Reads the file and sets terms, description and alt text.
File replaced (PhotoPress's replace route or Enable Media Replace) The same, unless the request set reprocess_metadata to false.
Re-read image metadata job The same, for every image or the images a change affects.

Only images with a file on the server are read. PDFs, video and audio are skipped.

Terms replace those the image had, so a keyword removed from the file goes. When a file has nothing for a taxonomy's source, its terms there are kept, unless the job was started with Empty the terms checked (TermRouter.php#L159). The sources are:

Source Taxonomies
Keywords (dc:subject or a hierarchy) Keywords and every parent keyword taxonomy
Location (city, state or country) Cities, States and Countries together
Camera, lens, each custom field Its own taxonomy

A file with a city but no state therefore loses its State term.

Public switch

With Public off, the taxonomy is registered with public and publicly_queryable false, no rewrite rules, and no query var (metadata.php#L1254). It has no archive or term pages, is not offered in menus or tag clouds, and the Image Metadata block and Display Taxonomies widget leave it out. Its terms screen under Media and its Media Library column stay.

With Public on and Image taxonomy pages off in the Pages & Search tab, the taxonomy has no archive pages. Its terms are still shown, unlinked.

Archive pages

  • The archive base is the singular name as WordPress makes a slug of it (sanitize_title()): Singular name "Acme job" gives /acme-job/.
  • Keywords and parent keyword taxonomies are hierarchical, with hierarchical URLs: /person/family/jane. /person/jane also finds Jane, as WordPress reads the last part of a term path.
  • An archive lists only images WordPress counts as public: unattached, or attached to a published post (metadata.php#L2123).

Media › Keywords: the Keywords terms with their counts
The Keywords terms screen under Media, reached from the Terms count.

WordPress integration

Hook Type Code Purpose
init action class-module.php#L50 The module's hooks and taxonomies are set up at priority 0.
add_attachment action metadata.php#L62 Reads a new image's file into its terms, description and alt text. The terms are set only while the Image Taxonomies switch is on, as the taxonomies are registered only then.
photopress_attachment_file_replaced action (PhotoPress) metadata.php#L63 Reads a replaced file, unless reprocess_metadata is false.
pre_get_posts action metadata.php#L166 An image taxonomy archive's main query lists images (post_status inherit) and only public ones.
posts_where filter metadata.php#L137 Applies the public-images condition to queries with the photopress_public_images query var.
wp_loaded action metadata.php#L480 Rebuilds the rewrite rules when the taxonomies' URLs changed.
rest_api_init action metadata.php#L51 Registers the photopress/v1/image-taxonomies routes.
rest_endpoints, rest_attachment_item_schema, rest_post_dispatch, rest_term_search_query, rest_prepare_attachment, rest_attachment_query, rest_queried_resource_route filters ImageTaxonomyRest.php#L60 The REST gate (below).

Registration

register_taxonomy() for attachment, once per enabled definition (metadata.php#L1294):

Argument Value
hierarchical true for Keywords and parent keyword taxonomies
public false when the Public switch is off
publicly_queryable, show_in_nav_menus, show_tagcloud true only with archive pages (public, and Image taxonomy pages on)
query_var the taxonomy ID with archive pages, else false
rewrite slug from the singular name, hierarchical as above, ep_mask EP_PERMALINK; false without archive pages
show_in_rest true, with rest_controller_class TermsController
update_count_callback _update_generic_term_count
show_ui, show_in_menu, show_admin_column true

A definition whose ID is a built-in WordPress taxonomy is not registered.

Terms are set with wp_set_object_terms(), replacing the image's terms, inside wp_defer_term_counting(). Nested terms are found with term_exists() under their parent and made with wp_insert_term() (metadata.php#L2081).

Taxonomy IDs

The ID is the name WordPress stores the terms under. Themes (taxonomy-<ID>.php), Relevanssi, the Image Metadata block and the widget refer to it. It does not change when the taxonomy is renamed.

  • The six standard taxonomies always have the IDs in the table above.
  • A taxonomy added in the settings gets pp_ and its singular name, with - as _: pp_genre. A taken ID gets _2, _3 and so on (taxonomy-model.js#L110).
  • Taxonomies made by earlier versions keep their IDs, such as photos_people.

On save, the server enforces these rules for any client (class-settings.php#L248):

  • The ID is cleaned with sanitize_key() and cut to 32 characters, WordPress's limit.
  • An ID that is one of WordPress's own (category, post_tag, nav_menu, link_category, post_format, wp_theme, wp_template_part_area, wp_pattern_category) gets the pp_ prefix.
  • A repeated ID gets _2, _3 and so on, within 32 characters.

Rewrite rules

PhotoPress keeps an MD5 of the [ID, slug, hierarchical] list of the taxonomies with archive pages in the photopress_taxonomy_rewrites option. When the list differs, it calls flush_rewrite_rules( false ) on wp_loaded, after every plugin has registered its types (metadata.php#L470). That happens after a taxonomy is added, renamed, made admin only or turned off, after the Image Taxonomies switch is turned off, and after activation. Deactivation deletes the option and the rewrite_rules option.

REST gate

The taxonomies are in the REST API for the block editor and core blocks (Image Metadata block, Post Terms, Query Loop). Only users who can edit_posts read them (ImageTaxonomyRest.php). For anyone else:

  • The term routes (/wp/v2/<rest_base>) do not exist (404) and are not in the REST index.
  • /wp/v2/taxonomies omits them; /wp/v2/taxonomies/<ID> returns 404.
  • /wp/v2/search?type=term does not search them, and does not accept them as a subtype.
  • /wp/v2/media responses carry no term IDs, term links or term classes in class_list. Term filter arguments (?photos_city=34) are removed and ignored. The media schema omits the taxonomies and their assign and create links.

TermsController (TermsController.php#L27) extends WP_REST_Terms_Controller and repeats the check for reading terms. An admin-only taxonomy's terms also need upload_files.

Role (default capabilities) Public image taxonomy Admin-only image taxonomy
Visitor, Subscriber No No
Contributor (edit_posts) Yes No
Author, Editor, Administrator (upload_files) Yes Yes

Term archive pages of the image taxonomies send no REST alternate <link> or Link header, for any user.

Each taxonomy in /wp/v2/taxonomies has a read-only photopress_public field: whether visitors may see its terms (ImageTaxonomyRest.php#L78).

REST routes

All need manage_options (metadata.php#L350).

Route Method Returns
/photopress/v1/image-taxonomies GET counts (terms per taxonomy ID) and prefixes (the unclaimed prefixes)
/photopress/v1/image-taxonomies/scope POST settings ids and taxonomies a change to the saved settings would affect
/photopress/v1/image-taxonomies/reprocess POST ids, all, taxonomies, skip (default true) job, and queued when a re-read is running

The Reprocess all images button starts the metadata.reprocess job through POST /photopress/v1/jobs with args.force.

Data stored

Name Kind Holds
photopress_core_metadata option custom_taxonomies_enable, custom_taxonomies (the definitions), custom_taxonomies_tag_delimiter (prefix separators). Read and written through /wp/v2/settings.
photopress_taxonomy_rewrites option Hash of the URLs the rewrite rules were built for
photopress_reprocess_queue option Re-reads waiting for the running one
photopress_old_people option Whether the site has photos_people terms (yes/no)

Each custom_taxonomies entry has id, pluralLabel, singularLabel, tag (the field), parseTagValue (true for a parent keyword), and optionally names (a parent keyword's names), disabled (turned off) and private (Public off). A Standard Metadata entry is the first one whose tag is that taxonomy's field.

Hooks PhotoPress provides

Hook Type Arguments When Code
photopress/taxonomies/defaultDefinitions filter $taxonomies (definitions) Builds the default custom_taxonomies, used until the settings are saved metadata.php#L1250
photopress_metadata_tag_name filter $name Runs on every metadata field lookup. Renames the field asked for. XmpReader.php#L167
photopress_metadata_tag_value filter $value, $name, $all_xmp Runs on every field lookup of a file with XMP. A non-empty return is used as the value. XmpReader.php#L177
photopress_attachment_file_replaced action $id, $replacements, $rewritten, $options (reprocess_metadata) After an image is given a new file MediaRest.php#L388, EnableMediaReplace.php#L46

Limits, quirks and known issues

  • Fields other than camera and lens are read from the file's XMP only. IPTC-IIM values without an XMP copy are not read.
  • EXIF is read from JPEG and TIFF files only. Other formats get their camera from XMP tiff:Make and tiff:Model.
  • XMP is read from JPEG segments (including Extended XMP), from where PNG, WebP, GIF, TIFF and HEIF keep it, or else by searching the file. A packet over 16 MB is not read.
  • The Terms column counts terms, not images.
  • Term counts under Media use _update_generic_term_count: they include images attached to unpublished posts.
  • Renaming a taxonomy's singular name moves its archive pages. The old URLs stop working.
  • Reprocessing may give images different terms than an earlier version did: 2.0.0 nests hierarchies, matches parent keywords in any case and cleans camera names.
  • A parent keyword saved by an earlier version as a path (Clients|Acme) has that name ignored.
  • A site that has photos_people terms and never saved its taxonomy settings keeps the pre-2.0 People parent keyword in its defaults. New sites start without it.
  • A Re-read image metadata job that runs over every image also rewrites alt text and descriptions. See Alt Text and Descriptions.

Related

Clone this wiki locally