Explore everything FotoGrids can do
Style every gallery to your brand
Drag, drop, publish. No code
Rank higher. Load lighter
Your photos stay your photos
Track. Engage. Grow
Native block for the WordPress editor
Dedicated widget with full control
Custom module for any Divi layout
Fully customizable native element
Anywhere WordPress renders
Read, write, and automate galleries
Customize behavior with WP hooks
Bring your own styles and scripts
Hooks, REST API, and full control
Showcase your work beautifully
Collaborate, deliver, and scale client work
Beautiful galleries without writing code
Turn visitors into paying customers
Product galleries built to sell
Creative portfolios for every field
Curated video playlists and embeds
Conferences, weddings and celebrations
E-Commerce-ready product showcases
Property photos that close deals
Client proofing with secure galleries
The free plugin registers 80+ routes in one namespace — fotogrids/v1. More than a dozen are public and need no key at all. The whole content API — Galleries, Albums, items, rendering, Lightbox, metadata, stats and templates — is in Free.
More than a dozen routes answer without authentication — their permission_callback returns true. This is one of them, and it is the whole request.
BASH
terminal BASH
curl https://example.com/wp-json/fotogrids/v1/gallery/42
Six top-level keys: id, title, description, meta, items and shortcode.
description is the post content, not the excerpt. meta carries layout (falls back to grid), columns (falls back to 3) and album_id, which is null when the Gallery sits in no Album.
shortcode hands you the exact string an editor would paste, so a script can drop a working embed into a post without composing one by hand.
Every path below is relative to /wp-json/fotogrids/v1/. The Auth column is the capability the route checks — Open means no authentication at all.
GET
/gallery/{id}
Open
POST
/gallery/render
Open
POST
/gallery/{id}/unlock
Open
POST
/gallery/lightbox/slides
Open
GET
/galleries
Open
GET
/galleries/{id}/items
Open
GET
/album/{id}
Open
GET
/items
Open
GET
/lightbox/item/{id}
Open
POST
/stats/view
Open
POST
/stats/share
Open
GET
/view/{id}/settings
Open
GET
/templates/preview
Open
/gallery/{id} does record a view, so pass preview=true when a job polls it. POST
/gallery/{id}/featured-item
edit_post
POST
/album/{id}/featured-gallery
edit_post
POST
/admin/galleries/{id}/items
edit_post
POST
/admin/galleries/{id}/albums
edit_post
DELETE
/admin/galleries/{id}/albums/{album_id}
edit_post
POST
/admin/albums/{id}/galleries
edit_post
DELETE
/admin/albums/{id}/galleries/{gallery_id}
edit_post
POST
/admin/albums/{id}/galleries/reorder
edit_post
GET POST /admin/general-settings
manage_fotogrids_settings
GET POST /admin/sharing-settings
manage_fotogrids_settings
GET POST /admin/watermark-settings
manage_fotogrids_settings
GET POST /admin/seo-settings
manage_fotogrids_settings
GET POST /admin/view-settings
manage_fotogrids_settings
GET POST /admin/advanced-settings
manage_fotogrids_settings
GET POST /admin/roles
manage_fotogrids_settings
GET
/admin/stats/overview
view_fotogrids_stats
GET
/admin/stats/views
view_fotogrids_stats
GET
/admin/stats/popular-galleries
view_fotogrids_stats
GET
/admin/stats/recent-activity
view_fotogrids_stats
GET
/admin/stats/top-content
view_fotogrids_stats
edit_posts — an editor who can write posts does not get the settings or the stats by default. GET
/library/{type}
manage_fotogrids_library
GET
/metadata/tags
edit_posts
GET
/metadata/people
edit_posts
GET
/metadata/locations
edit_posts
GET
/metadata/item/{id}
edit_posts
GET
/templates
edit_posts
POST
/items/{id}/save
manage_fotogrids
POST
/items/resolve-embed
manage_fotogrids
POST
/items/embed
manage_fotogrids
GET
/picker/items
manage_fotogrids
manage_fotogrids passes everywhere manage_fotogrids_library does, so one admin role covers both. There is no bespoke auth layer. Cookie plus X-WP-Nonce for same-origin admin JavaScript; whatever credential scheme WordPress core already accepts for an external client. Nothing in FotoGrids intercepts, wraps or replaces it — exactly one route verifies a nonce itself, /templates/preview, because it loads inside an iframe.
manage_fotogrids
manage_fotogrids_settings
manage_fotogrids_library
manage_fotogrids_permissions
view_fotogrids_stats
modify_fotogrids_gallery_settings
modify_fotogrids_album_settings
edit_posts
manage_options
GET /gallery/{id}/password. A filter can widen it if your setup needs a narrower role to read it. auth_callback on meta
fotogrids_featured_image_id is writable over core REST only by a caller with manage_fotogrids on that post. No parallel model
edit_post
A contributor stays a contributor
Album membership runs both ways
The gate holds at the API
Every one of these runs on a route from the table above. None of them needs a plugin-specific SDK — an HTTP client and an application password is the whole toolchain.
CSS import.sh BASH
curl -u "$WP_USER:$WP_APP_PASSWORD" \
-X POST https://example.com/wp-json/fotogrids/v1/admin/galleries/42/items \
-H "Content-Type: application/json" \
-d '{"attachment_ids":[118,119,120]}'
Push the files into the Media Library the way you already do, then hand the attachment ids over in one call. Set the cover in the same script with POST /gallery/{id}/featured-item.
CSS render.sh BASH
curl -X POST https://example.com/wp-json/fotogrids/v1/gallery/render \
-H "Content-Type: application/json" \
-d '{"gallery_id":42,"breakpoint":"mobile","partial":"items_only"}'
The response carries the whole rendered Gallery, produced by the same code path the theme uses. Send a breakpoint and partial: items_only when you are appending to a grid you already drew.
CSS slides.sh BASH
curl "https://example.com/wp-json/fotogrids/v1/gallery/lightbox/slides" \
-X POST -H "Content-Type: application/json" \
-d '{"gallery_id":42,"offset":0,"limit":40}'
Slide payloads page by offset and limit. GET /lightbox/item/{id} then fills the detail panel for one item: EXIF, credit, filename, filesize, dimensions and MIME type.
JS track.js JS
fetch( '/wp-json/fotogrids/v1/stats/view', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify( { object_type: 'gallery', object_id: 42 } )
} );
Both stat routes are public, so a front end can record without a key. Read them back with the view_fotogrids_stats routes.
No optional fields and no conditional expansion on GET /gallery/{id} — every entry in items[] carries exactly these keys, in this order.
CSS response.json JSON
{
"id": 42,
"title": "Coastal Shoot",
"meta": { "layout": "grid", "columns": 3, "album_id": null },
"items": [
{
"id": 118,
"position": 0,
"caption": "Low tide, 6am",
"description": "",
"location": "",
"url": ".../tide.jpg",
"thumbnail": ".../tide-150x150.jpg",
"medium": ".../tide-300x200.jpg",
"large": ".../tide-1024x683.jpg",
"full": ".../tide.jpg",
"alt": "Wet sand at low tide"
}
],
"shortcode": "FotoGrids: No gallery ID specified. Usage: FotoGrids: Gallery with ID 1 not found."
}
url and full are the same value — both come from wp_get_attachment_url(). Pick one and stay with it; do not treat a difference between them as meaningful, because there is none.
It reads _wp_attachment_item_alt, not WordPress's _wp_attachment_image_alt, so editing alt text in FotoGrids never touches the Media Library value. It is seeded from that value the first time an item is added to a Gallery, and stored per attachment.
No. The entire content API is in Free — Galleries, Albums, items, rendering, Lightbox, metadata, stats and templates. Nothing you need to read, write or automate a Gallery sits behind a licence. Free is already a full kit. Pro layers on the rest.
Exactly as you would against any WordPress site. Cookie plus X-WP-Nonce from admin JavaScript; whatever credential scheme core accepts for an external client. FotoGrids adds no auth layer of its own, so anything that works against /wp/v2/ works here.
Yes — pass preview=true on GET /gallery/{id}. Without it a non-preview read records a view, so an integration that polls will inflate your own stats. GET /album/{id} increments unconditionally; there is no preview flag on it today.
POST /gallery/render is the paginating route: send page and items_per_page and it answers with page, page_size, total_pages and has_more. The paginated branch drops inlineCss, inlineJs and jsonLd — request page 1 unpaginated if you need those.
Not today. No route registers a schema callback and none subclasses WP_REST_Controller, so OPTIONS self-description is limited to the declared args — which are typed, defaulted and enumerated, and are the contract.
For the post objects, yes. Both types are registered with core REST: /wp/v2/fotogrids-galleries and /wp/v2/fotogrids-albums, served by the stock controller, so core pagination, ordering and _fields all work — including the X-WP-Total headers the custom routes do not send. Items, rendering, Lightbox slides and stats only exist under fotogrids/v1.
We use cookies and similar technologies to make our website work smoothly and understand how it’s used. Choosing “Accept” helps us personalize your experience. If you decline or change your mind later, some features may not work as expected.