Title: PhotoFetch
Author: Topher
Published: <strong>16 de octubre de 2026</strong>
Last modified: 16 de octubre de 2026

---

Buscar plugins

![](https://ps.w.org/photofetch/assets/banner-772x250.jpg?rev=3750391)

![](https://ps.w.org/photofetch/assets/icon.svg?rev=3750441)

# PhotoFetch

 Por [Topher](https://profiles.wordpress.org/topher1kenobe/)

[Descargar](https://downloads.wordpress.org/plugin/photofetch.zip)

 * [Detalles](https://es.wordpress.org/plugins/photofetch/#description)
 * [Valoraciones](https://es.wordpress.org/plugins/photofetch/#reviews)
 *  [Instalación](https://es.wordpress.org/plugins/photofetch/#installation)
 * [Desarrollo](https://es.wordpress.org/plugins/photofetch/#developers)

 [Soporte](https://wordpress.org/support/plugin/photofetch/)

## Descripción

This plugin adds a «Photo Directory» search UI to wp-admin that talks to the
 public
Photo Directory REST API.

You can search, preview, and import photos directly into your own Media
 Library,
where the imported image behaves exactly like any regular upload — usable as a featured
image, inside blocks, in a gallery, etc.

Entry points:

 * **Media > Photo Directory** — a dedicated search/browse admin page.
 * **«Photo Directory» button** next to Add Media in the classic editor.
 * **«Photo Directory» tab** inside the native WordPress media picker itself
    (Set
   Featured Image, Add Media, an Image block’s Media Library button, etc.) — works
   in both the classic and block editor, since they share the same underlying media
   picker.

### Notes for developers

 * This is an unofficial integration with a public but not formally
    documented 
   API. `includes/class-photofetch-api.php::normalize_item()` is where the raw JSON
   from the Photo Directory gets mapped into predictable sizes/`alt`/`author` fields—
   it tries several plausible shapes (`media_details.sizes`, an embedded featured-
   media object, a bare source_url, etc.). If wordpress.org changes the API’s response
   shape, this is the one function that should need updating.
 * Title and alt text are sourced independently: alt text prefers a real
    alt-text
   field if the API exposes one, otherwise falls back to the same text used for 
   the Description field (see `PhotoFetch_API::normalize_item()` for the exact priority
   order). It’s never derived from the title. For title, known upstream placeholder
   strings (currently «Photo Detail», «Untitled», «Untitled Photo» — see `photofetch_generic_title_placeholders`
   filter) are treated as no title at all, and a fallback title is derived from 
   the photo’s slug instead (e.g. `red-fox-in-snow`  «Red fox in snow»). If the 
   slug itself isn’t usable, the title falls back to «Untitled photo».
 * The attachment’s Description field (post_content) and alt text both get
    the 
   photo’s full description text; its Caption field (post_excerpt) gets _only_ the
   photographer credit line (e.g. «Photo by Jane Smith, via the WordPress Photo 
   Directory.»), or is left empty if no author name is available.
 * The search/browse picker UI doesn’t display each photo’s title — many
    photos
   on the Photo Directory only have a slug-derived fallback title (see above), which
   isn’t meaningful to show while browsing. The title is still set on the imported
   attachment; it’s just not shown in the grid.
 * Imports are deduplicated: each imported attachment gets a
    _photofetch_source_id
   meta value, and re-importing the same photo returns the existing attachment instead
   of downloading it again.
 * Image format conversion (Settings > Photo Directory,
    PhotoFetch_Settings::get_format())
   happens in PhotoFetch_Importer::maybe_convert_image(), right after download and
   before sideloading. It re-checks `wp_image_editor_supports()` at import time 
   rather than trusting the stored setting outright, and falls back to the original
   file on any failure.
 * Search results are cached for 5 minutes via transients to avoid hammering
    the
   upstream API on repeat searches.
 * All photos on the Photo Directory are released CC0 (no attribution
    required),
   but the plugin stores the original photo URL and author name (when available)
   as `_photofetch_source_url` / `_photofetch_source_author` attachment meta for
   your own reference, in addition to the caption credit above.

## Instalación

 1. Upload the plugin files to the `/wp-content/plugins/photofetch` directory, or install
    the plugin through the **Plugins > Add New** screen in wp-admin directly.
 2. Activate the plugin through the **Plugins** screen in WordPress.
 3. That’s it — no configuration is needed and no API key or account is required. Look
    under **Media > Photo Directory**, use the «Photo Directory» button next to Add
    Media in the classic editor, or use the «Photo Directory» tab inside the native
    media picker (Set Featured Image, Add Media, an Image block’s Media Library button,
    etc.).

## FAQ

### Do I need an API key or account to use this?

No. The Photo Directory REST API is public, so the plugin works as soon as it’s 
activated.

### Do I need to credit the photographer?

No — every photo on the Photo Directory is released under CC0, so attribution isn’t
legally required. The plugin adds a photographer credit line to each imported photo’s
caption anyway, when the API provides an author name, so credit is there if you 
choose to show it.

### Why does an imported photo’s title look like a URL slug instead of a real title?

Some photos on the Photo Directory only have a generic placeholder title, because
the original uploader never set a real one. The plugin recognizes those placeholders
and falls back to a title built from the photo’s slug or description instead, rather
than importing the placeholder text as-is. It’s a best-effort fallback, not guaranteed
to read naturally — worth a glance before publishing.

### Why don’t I see the «Photo Directory» button in the block editor?

That button is added next to Add Media via the `media_buttons` hook, which only 
the classic editor fires. In the block editor, use the «Photo Directory» tab inside
the native media picker instead — it opens the same way from Set Featured Image,
Add Media, or an Image block’s Media Library button.

### Can I choose what size image gets imported?

Yes. Both the Media > Photo Directory browse screen and the media picker tab let
you choose Full, Large, or Medium before importing.

### Can imported photos be converted to WebP or AVIF?

Yes, if your server’s image editor supports it. Go to **Settings > Photo Directory**
to choose — WebP is used automatically whenever your server can produce it. If it
can’t, the page says so plainly and photos keep their original format. A quality
field appears alongside the format choice whenever WebP or AVIF is selected; it 
has no effect when keeping the original format, so it’s hidden in that case.

### Where does the plugin store which photos I’ve already imported?

Each imported attachment gets a `_photofetch_source_id` meta value matching its 
ID on the Photo Directory. Importing the same photo again returns the existing attachment
instead of downloading a duplicate.

## Reseñas

No hay valoraciones para este plugin.

## Colaboradores y desarrolladores

«PhotoFetch» es un software de código abierto. Las siguientes personas han colaborado
con este plugin.

Colaboradores

 *   [ Topher ](https://profiles.wordpress.org/topher1kenobe/)
 *   [ Kamran Abdul Aziz ](https://profiles.wordpress.org/ekamran/)
 *   [ veeeharris ](https://profiles.wordpress.org/veeeharris/)
 *   [ Matt Galdino ](https://profiles.wordpress.org/mattgaldino/)
 *   [ Taylor Elizabeth Rose ](https://profiles.wordpress.org/telizarose/)
 *   [ Guste Cibulskyte ](https://profiles.wordpress.org/gusteci/)
 *   [ Michelle Frechette ](https://profiles.wordpress.org/michelleames/)

[Traduce «PhotoFetch» a tu idioma.](https://translate.wordpress.org/projects/wp-plugins/photofetch)

### ¿Interesado en el desarrollo?

[Revisa el código](https://plugins.trac.wordpress.org/browser/photofetch/) , echa
un vistazo al [repositorio SVN](https://plugins.svn.wordpress.org/photofetch/) o
suscríbete al [registro de desarrollo](https://plugins.trac.wordpress.org/log/photofetch/)
por [RSS](https://plugins.trac.wordpress.org/log/photofetch/?limit=100&mode=stop_on_copy&format=rss).

## Registro de cambios

#### 2.0.0

Renamed the plugin from «Photo Directory Importer» to «PhotoFetch.» Unlike the 1.3.16
rename, this one is a full internal rebrand, not just the public-facing name:
 *
Main plugin file renamed from `photo-directory-importer.php` to `photofetch.php`;
every `includes/class-pdi-*.php` file renamed to `includes/class-photofetch-*.php`;
the bundled `.pot` file renamed to `languages/photofetch.pot`. * The `Text Domain`(
and every translation call’s domain argument) changed from `photo-directory-importer`
to `photofetch`, matching the new slug — same requirement as the 1.3.14 and 1.3.16
fixes. * Unlike 1.3.16, this time the internal-only identifiers were deliberately
included: all `PDI_*` class names (`PDI_API`, `PDI_Importer`, `PDI_Plugin`, `PDI_Settings`)
are now `PhotoFetch_API`, `PhotoFetch_Importer`, `PhotoFetch_Plugin`, `PhotoFetch_Settings`;
the `PDI_*` constants are now `PHOTOFETCH_*`; every `pdi_`-prefixed hook, filter,
nonce, AJAX action, option, and meta key (including the `_pdi_source_id`/`_pdi_source_url`/`
_pdi_source_author`/`_pdi_imported` attachment meta) is now `photofetch_`-prefixed;
and every `pdi-*` CSS class, script/style handle, and HTML id is now `photofetch-*`.*
This is a breaking change for existing installs: deactivate and remove the old plugin,
then install this one fresh. Site functionality and every imported photo’s existing
attachment meta are otherwise unaffected — only the identifiers above changed, not
what they do.

#### 1.3.17

 * Fixed the phpcs findings from a fresh run against the renamed plugin:
    an equals-
   sign alignment warning in `class-pdi-plugin.php`‘s author-link rewriter, missing
   short descriptions in three doc comments (one each in class-pdi-importer.php 
   and `class-pdi-settings.php`, two total in the latter), and `languages/index.
   php`‘s file comment switched from a `//` line comment to the required `/** ...*/`
   docblock style.

#### 1.3.16

 * Renamed the plugin from «WP Photo Directory Importer» to «Photo
    Directory Importer»—
   WordPress.org’s plugin guidelines prohibit «WP» or «WordPress» in a plugin’s 
   name, since it implies an official affiliation the plugin doesn’t have. This 
   touched everything tied to the old name: the `Plugin Name` header, the main plugin
   file (`wp-photo-directory-importer.php`  `photo-directory-importer.php`), the`
   Text Domain` (and every translation call’s domain argument, to match — same requirement
   as the 1.3.14 fix), the bundled `.pot` file’s name and contents, and the `@package`
   docblock tag across every PHP file. Internal-only identifiers (the `PDI_*` class
   names, `pdi_`– prefixed hooks/filters/nonces, `pdi-*` CSS/JS handles) were left
   untouched, since none of them spell out «WP» or «WordPress» and changing them
   would be an unrelated, unnecessary breaking change.

#### 1.3.15

 * Fixed incorrect plural handling in the browse screen and media-picker
    tab: several«
   N selected»/»N imported» strings picked between exactly two hardcoded forms using
   a `count === 1` check in JavaScript — correct for English, but impossible for
   a translator to adapt to a language with three, four, or six plural forms (Russian,
   Polish, and Arabic, among others). Now uses `wp.i18n._n()`, which consults the
   current locale’s real plural-forms rule instead. Along the way this also fixed
   a visible English-language bug: the single-photo «quick import» success message
   was using the plural template with the count hardcoded to 1, producing «1 photos
   imported.»
 * Added a bundled `.pot` file (`languages/photo-directory-importer.pot`)
    and a`
   Domain Path` header, so translators have a starting point instead of needing 
   to generate one themselves before they can begin.

#### 1.3.14

 * Fixed a Plugin Check error: «Mismatched text domain. Expected
    ‘photo-directory-
   importer’ but got ‘pdi’.» WordPress.org requires the Text Domain header, and 
   every translation function’s domain argument, to exactly match the plugin’s own
   folder/slug. Changed the domain from pdi to `photo-directory-importer` everywhere:
   the plugin header and all translation function calls across every PHP and JS 
   file. Internal-only identifiers that happen to start with `pdi_` (hooks, filters,
   nonces, meta keys, transient keys) were deliberately left untouched, since those
   aren’t text domains.
 * Reformatted a handful of PHP statements that became excessively long
    purely 
   from the domain string’s length.

#### 1.3.12

 * On the Plugins list page, each contributor’s name now links to their
    own wordpress.
   org profile (`https://profiles.wordpress.org/username`) instead of the whole 
   comma-separated author list linking to one shared GitHub URL — the standard plugin
   header format only supports one link for the entire «Author» string, so this 
   rewrites the row directly via the `all_plugins` filter.
 * Added a «Settings» link to the plugin’s row on the Plugins page,
    appearing first
   among the action links, right next to «Deactivate».

#### 1.3.11

 * Added a quality field to **Settings > Photo Directory**, shown only
    when converting
   to WebP or AVIF (hidden automatically when «Keep original format» is selected—
   quality has no meaning there, since nothing gets re-encoded). Defaults to 82,
   matching WordPress core’s own default JPEG compression quality. Clamped to 1–
   100 on save regardless of what’s posted.

#### 1.3.10

 * Added a **Settings > Photo Directory** page. If this server’s image
    editor (
   GD or Imagick, whichever core picked) can actually produce WebP — checked live
   via `wp_image_editor_supports()`, not assumed from PHP version or extension presence—
   a format picker appears: keep the original format, convert to WebP, or convert
   to AVIF (the latter only offered when supported too). WebP is the default whenever
   it’s available. If WebP isn’t supported, the page simply says so and no photos
   are converted, same as before this release.
 * Conversion happens right after download, before the file is sideloaded,
    so every
   generated thumbnail/medium/large sub-size is produced from the converted file
   directly rather than converted a second time after the fact.
 * A conversion failure for any reason falls back to importing the
    original file
   untouched — this is meant to be a nice-to-have, never something that can turn
   a failed conversion into a failed import.
 * The «Import settings» link in the Media > Photo Directory page header,
    present
   but hidden since 1.3.4, now points at the new settings page.

#### 1.3.9

 * Added `w.org` to the default trusted image hosts (`pdi_allowed_image_hosts`).
   
   The Photo Directory serves its images from `pd.w.org` specifically — w.org is
   WordPress.org’s own short domain, the same family as s.w.org, its well-known 
   static-assets host. The 1.3.8 fix (adding wp.com for Photon) turned out not to
   be where these images actually live; this corrects it based on the real rejected
   host.

#### 1.3.8

 * **Fixed a regression from 1.3.7 that broke every import.** The trusted-host
    
   check added in 1.3.7 only allowed `wordpress.org` (and its subdomains), but the
   Photo Directory serves uploaded images through Automattic’s Photon CDN (`i0.wp.
   com`, `i1.wp.com`, etc.) rather than from wordpress.org’s own domain directly—
   so every single import was rejected as «untrusted.» `wp.com` (and its subdomains)
   is now included in the default allowed hosts.
 * The «not on a trusted host» error message now includes the actual
    rejected hostname,
   so a similar mismatch in the future is immediately diagnosable without digging
   through network requests, and can be resolved on the spot via the `pdi_allowed_image_hosts`
   filter.

#### 1.3.7

Security review and hardening. No user-facing behavior changes; all four
 items 
below were fixed as defense-in-depth rather than in response to an exploited vulnerability.

 * **Sideloaded image URLs are now pinned to a trusted host.**
    PDI_Importer::import_photo()
   downloads whichever image URL the Photo Directory API returns for a photo; that
   URL is data returned _by_ the API, not something this plugin generates itself.
   Added is_allowed_image_host(), checked before `download_url()` is ever called,
   requiring the URL’s host to be `wordpress.org` or a subdomain of it (filterable
   via `pdi_allowed_image_hosts`). Nothing a site visitor or lower-privileged user
   supplies can influence which host this plugin talks to for search or photo lookups—
   those always go to the hardcoded REMOTE_BASE/`TAXONOMY_BASE` constants — so this
   specifically guards against a compromised or malicious upstream API response 
   causing this site to download and store a file from an attacker-controlled server.
 * **Removed an unused `innerHTML` code path.** `assets/js/admin.js`‘s `el()`
    helper
   had a dead `'html'` attribute branch (`e.innerHTML = attrs.html`) that nothing
   in the codebase called, but that would become an XSS sink the moment anything
   did. Removed it entirely.
 * **Added `rel="noopener noreferrer"`** to the «View in Media Library»
    link in`
   assets/js/admin.js`, which opens in a new tab (`target="_blank"`). Its destination
   is fully server-generated today, so this wasn’t exploitable, but it’s standard,
   zero-cost protection against reverse-tabnabbing regardless.
 * **Added explicit `return` statements after every `wp_send_json_error()`
    call
   
   in `class-pdi-api.php` (`ajax_search()`, `ajax_terms()`) and
    class-pdi-importer.
   php (`ajax_import()`) that wasn’t already the last statement in its function.`
   wp_send_json_error()` calls `wp_die()`, which WordPress’s AJAX handling turns
   into an immediate `die()`, so execution already halted in normal operation — 
   this wasn’t currently exploitable. But code after those calls was relying on 
   that implicit behavior instead of stating it, which would fall through with invalid/
   stale state (e.g. continuing with a photo ID of 0, or treating a WP_Error object
   as an array) if `wp_die()`‘s behavior were ever filtered, as some testing harnesses
   deliberately do.

#### 1.3.6

 * Added a «View full» button to the «Photo Directory» tab inside the
    native media
   picker (Set Featured Image, Add Media, etc.), next to the «Import only» button
   in the footer. Opens the currently-detailed photo’s full-size image in a plain,
   image-only overlay (closes on Escape, clicking outside the image, or the close
   button).

#### 1.3.5

 * Added a «View full» button to every photo card on the Media > Photo
    Directory
   browse screen. Opens the photo’s full-size image in a lightbox (closes on Escape
   or clicking outside the image), which includes its own Import button (or a «View
   in library» link, once the photo has been imported).

#### 1.3.4

 * Rebuilt **Media > Photo Directory** as a filterable browse screen
    (`assets/js/
   photo-browser.js`, React via `wp-element`): category, orientation, and color 
   filters populated live from the Photo Directory’s own taxonomies; sort by relevance
   or newest; multi-select with a bulk-import tray; per-photo title/alt/caption 
   edits and a photographer-credit toggle before import.
 * Rebuilt the «Photo Directory» tab inside the native media picker as a
    two-pane
   picker (thumbnail grid + detail sidebar) with the same filters, matching the 
   browse screen.
 * Photos already in the Media Library are now flagged in bulk for a
    whole result
   page at once (`PDI_Importer::find_existing_attachments()`) instead of one lookup
   per card.
 * `_embed` now requests only the two relations the plugin reads
    (`author,wp:featuredmedia`)
   instead of every relation the API would otherwise expand, avoiding an unnecessary`
   wp:term` expansion per taxonomy per photo.
 * Title fallback now prefers a short title derived from the photo’s own
    description
   over a humanized slug, since most Photo Directory slugs are opaque hex strings(
   e.g. `6836a813f7`) with no human meaning to humanize in the first place.
 * Normalized photo data now includes width, height, MIME type, and file
    size, 
   and the computed credit line is available directly on the photo object for the
   new UI to prefill.
 * Added Michelle Frechette as a contributor.
 * Removed the bundled `LICENSE` file in favor of linking the license
    online.
 * Fixed the search field’s icon overlapping its placeholder text.

#### 1.3.3

 * Sanitize untrusted fields from the Photo Directory API before use: the
    slug 
   now goes through `sanitize_title()`, the author name through wp_strip_all_tags()/`
   trim()`, and every image URL through esc_url_raw().
 * Moved the `wp-admin/includes/{media,file,image}.php` requires from
    file scope
   into `import_photo()` itself, so they’re only parsed while an import is actually
   happening rather than on every page load (this file loads on every request via`
   plugins_loaded`, including the front end).
 * Fixed a phpcs suppression bug: the slow-query warning for
    meta_key/`meta_value`
   was suppressed with a single `phpcs:ignore` comment, which only covers the next
   line and so didn’t actually suppress the `meta_value` warning. Switched to `phpcs:
   disable`/ phpcs:enable spanning both lines.
 * Fixed invalid XML in `phpcs.xml.dist` — an unescaped `--` inside an XML
    comment(`--
   dev`) is illegal in XML and would cause strict parsers to reject the whole ruleset
   file.
 * Added gusteci to the plugin’s Author/Contributors list.

#### 1.3.2

 * Alt text now falls back to the same description text used for the
    Description
   field, rather than a separate excerpt-only source that was frequently empty even
   when the description itself had usable text.
 * Reverted the 1.3.1 Caption/Description swap: Description (post_content)
    gets
   the photo’s full description text again, and Caption (post_excerpt) goes back
   to containing only the photographer credit line.

#### 1.3.1

 * Swapped the Caption/Description field mapping: Caption (post_excerpt)
    now gets
   the photo’s full description text, and Description (post_content) gets only the
   photographer credit line.
 * Removed the (often meaningless, slug-derived) title text from the
    search/browse
   picker grid. The title is still set on import; it’s just no longer shown while
   browsing.

#### 1.3.0

 * Alt text now falls back to the photo’s excerpt specifically, rather than
    its(
   potentially much longer) content/description.
 * The Caption field (post_excerpt) now contains only the photographer
    credit line;
   description text no longer appears in both the Description and Caption fields.

#### 1.2.3

 * Alt text now falls back to the photo’s description when the upstream
    API doesn’t
   expose a dedicated alt-text field of its own — that appears to be the closest
   thing to alt text the Photo Directory API offers.

#### 1.2.2

 * Alt text was coming through empty for photos that, per direct testing,
    do have
   alt text upstream — the embedded-featured-media lookup this plugin relied on 
   apparently isn’t where the Photo Directory’s custom post type actually stores
   it. Added speculative fallback checks (`alt_text` and `meta.alt_text`/`meta._wp_attachment_image_alt`
   on the item itself) pending confirmation against a real API response.

#### 1.2.1

 * The upstream Photo Directory substitutes a generic placeholder title
    (e.g. «
   Photo Detail») for photos the uploader never titled. That placeholder is now 
   recognized and treated as no title, with a fallback title derived from the photo’s
   slug instead (e.g. `red-fox-in-snow`  «Red fox in snow») rather than importing
   the literal placeholder text. Filterable via `pdi_generic_title_placeholders`.

#### 1.2.0

 * Fixed a bug where the attachment title was copied into the alt text
    field whenever
   the upstream photo had no alt text of its own, so the title and alt text would
   end up identical (and, for photos with a generic placeholder title, both fields
   would show that placeholder). Alt text is now only ever populated from the upstream
   photo’s own alt text, and left blank otherwise.
 * Added a photographer credit line to the imported attachment’s caption
    when the
   upstream API exposes an author name.
 * Removed the block editor sidebar panel; the native media modal tab
    (added in
   1.1.0) covers the same use case without a separate panel.

#### 1.1.0

 * Added a «Photo Directory» tab inside the native WordPress media modal
    (Set Featured
   Image, Add Media, Image block, etc.), so photos can be searched and imported 
   without leaving the picker you’re already in.

#### 1.0.0

 * Initial release.

## Meta

 *  Versión **2.0.0**
 *  Última actualización **hace 3 días**
 *  Instalaciones activas **Menos de 10**
 *  Versión de WordPress ** 5.8 o superior **
 *  Probado hasta **7.1.3**
 *  Versión de PHP ** 7.4 o superior **
 *  Idioma
 * [English (US)](https://wordpress.org/plugins/photofetch/)
 * Etiquetas:
 * [importer](https://es.wordpress.org/plugins/tags/importer/)[media](https://es.wordpress.org/plugins/tags/media/)
   [photo directory](https://es.wordpress.org/plugins/tags/photo-directory/)[photos](https://es.wordpress.org/plugins/tags/photos/)
 *  [Vista avanzada](https://es.wordpress.org/plugins/photofetch/advanced/)

## Valoraciones

Aún no se han enviado valoraciones.

[Tu valoración](https://wordpress.org/support/plugin/photofetch/reviews/#new-post)

[Ver todas las reseñas](https://wordpress.org/support/plugin/photofetch/reviews/)

## Colaboradores

 *   [ Topher ](https://profiles.wordpress.org/topher1kenobe/)
 *   [ Kamran Abdul Aziz ](https://profiles.wordpress.org/ekamran/)
 *   [ veeeharris ](https://profiles.wordpress.org/veeeharris/)
 *   [ Matt Galdino ](https://profiles.wordpress.org/mattgaldino/)
 *   [ Taylor Elizabeth Rose ](https://profiles.wordpress.org/telizarose/)
 *   [ Guste Cibulskyte ](https://profiles.wordpress.org/gusteci/)
 *   [ Michelle Frechette ](https://profiles.wordpress.org/michelleames/)

## Soporte

¿Tienes algo que decir? ¿Necesitas ayuda?

 [Ver el foro de soporte](https://wordpress.org/support/plugin/photofetch/)