Repository navigation
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.
- 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).
Open PhotoPress › Settings and select the Metadata tab.

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.
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.
| 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).

Adding a taxonomy for a parent keyword found in the photos, then reprocessing the images it affects.
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 CORPORATIONNIKON D800givesNikon D800. - A brand repeated at the start of the model is removed.
CanonCanon PowerShot G9givesCanon 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.
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:subjectis 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.
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 Hopestays whole. The keyword is split at every occurrence of the separator:people: family: Janegives 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.
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-UMRgives Unlimited Model Releases,trainedAlgorithmicMediagives 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;.
| 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.
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.
- 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/janealso 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).

The Keywords terms screen under Media, reached from the Terms count.
| 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). |
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).
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,_3and 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 thepp_prefix. - A repeated ID gets
_2,_3and so on, within 32 characters.
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.
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/taxonomiesomits them;/wp/v2/taxonomies/<ID>returns 404. -
/wp/v2/search?type=termdoes not search them, and does not accept them as a subtype. -
/wp/v2/mediaresponses carry no term IDs, term links or term classes inclass_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).
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.
| 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.
| 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 |
- 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:Makeandtiff: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_peopleterms 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.
Galleries
- Gallery Layouts
- Full-Screen Slideshow
- Gallery Slideshow Block
- Taxonomy Gallery
- Child Pages Gallery
- Gallery Images Added and Removed
- Image Templates and Blocks
Metadata
Pages and search
Media
Operation