JMGallery is built to be extended. Pro is not privileged code: it is an add-on built entirely on the same public hooks you have.

The contract

The full reference ships in the plugin at jmarztech-gallery/docs/hooks.md. It is the authority; this page is the orientation.

Plugins load alphabetically, so an add-on in a folder sorting before jmarztech-gallery/ loads first. Do all your setup on jmzg_loaded, which fires on plugins_loaded once the gallery is ready.

add_action( 'jmzg_loaded', function () {
    // register field types, display keys, settings, REST routes
} );

Naming

Post typejmzg_media
Meta and taxonomy keysjmzg_ + the field key
Optionsjmzg_settings, jmzg_fields, jmzg_displays
REST namespacejmarztech/v1
CSS namespace.jmz-
Classes and functionsjmzg_ and jmzg_

No custom database tables. Items are posts, values are post meta or terms.

The main extension points

Fields

jmzg_field_types registers a type with its storage, whether it holds many values, and whether it is sortable, filterable and caption-able. jmzg_sanitize_field, jmzg_field_value and jmzg_display_field handle writing, reading and formatting. jmzg_meta_query_clause defines how it filters.

A field keeps its stored type and storage even when no loaded code registers that type. It then behaves as text, or as tags if taxonomy-stored, and saving never rewrites it. Build on that: your add-on going missing should not cost the site its data.

Displays

jmzg_display_defaults adds your keys, jmzg_display_sanitize cleans them, and jmzg_display_style_vars, jmzg_display_classes, jmzg_display_attributes, jmzg_display_before and jmzg_display_top put them into the output. Display keys the plugin does not own are never dropped when a display is saved.

Settings

jmzg_settings_defaults and jmzg_settings_sanitize. Keys you own are carried through untouched when settings are saved from a build that cannot see them.

Output

jmzg_card_caption rebuilds one card’s caption from its parts. jmzg_card_prefix and jmzg_single_actions insert markup. jmzg_image_alt controls alt text. Everything returned must already be escaped.

REST

jmzg_rest_routes adds routes under jmarztech/v1. Each entry is [ path, method, callable, optional permission callable ]; the default permission is edit_posts.

The admin app

The admin is a single script, app.js. Enqueue on jmzg_app_enqueue with 'jmz-app' as a dependency, then register through window.jmzApp:

jmzApp.types.mytype = { input(f, v, name, extra) {}, parse(f, el) {}, fmt(f, v) {} };
jmzApp.formatters.push((f, v) => f.key === 'price' ? '$' + v : undefined);
jmzApp.add('display.layout',     (d, H) => '<label>…</label>');
jmzApp.wire('display.layout',    (scope, d, H) => {});
jmzApp.collect('display.layout', (scope, obj, H) => { obj.key = …; });

Slots: display.layout, display.captions, display.sections, display.listitem, csv.import, settings.sections, upload.video. When no add-on fills a slot, the free plugin renders a disabled preview of what an add-on would put there. Switch those off with jmzg_show_upsell.

Templates

Copy templates/archive-photo.php or templates/single-photo.php into your theme to override them. Block themes get both as block templates, plus

100 items
Designing Mobile-First Layouts
File Name: Designing Mobile-First Layouts
extended-saturday-hours-demo.webp
File Name: extended-saturday-hours-demo.webp
guinea-pig-essentials-demo.webp
File Name: guinea-pig-essentials-demo.webp
understanding-titer-testing-demo.webp
File Name: understanding-titer-testing-demo.webp
File Name: wide-listInfo Free
File Name: text-aboveInfo Pro
File Name: spotlightInfo Pro
File Name: pinboardInfo Free
File Name: news-listInfo Free
File Name: minimal-textInfo Free
File Name: magazineInfo Free
File Name: lead-storyInfo Free
File Name: hero-sliderInfo Free
File Name: featured-gridInfo Free
featured-grid.webp
File Name: featured-grid.webpInfo Pro
File Name: colour-blockInfo Pro
File Name: clean-cardsInfo Pro
File Name: classic-blogInfo Free
File Name: card-carouselInfo Pro
File Name: Snipaste_2026-10-04_13-58-48
File Name: Snipaste_2026-10-04_13-52-44
File Name: Snipaste_2026-10-04_13-48-47
File Name: Card
Understanding the difference between WordPress posts and pages
File Name: Understanding the difference between WordPress posts and pagesInfo Videos / Screenshot, Wordpress, Youtube
and for custom ones.

Translation

Both plugins are fully translatable and ship a POT file in languages/. Text domains are jmarztech-gallery and jmarztech-gallery-pro.