Start here
All documentation Installing JMGallery Your first gallery How JMGallery stores thingsFilling the library
Adding photos Custom fields The library and bulk editing CSV export and importShowing photos
Building a display Grid, masonry and list Shortcodes The archive page and filters Single photo pages The Elementor widgetPro features
Video Captions, backgrounds, hover Protecting your photos Downloads and sellingReference
Settings reference Licences and updates For developers TroubleshootingJMGallery 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 type | jmzg_media |
|---|---|
| Meta and taxonomy keys | jmzg_ + the field key |
| Options | jmzg_settings, jmzg_fields,
jmzg_displays |
| REST namespace | jmarztech/v1 |
| CSS namespace | .jmz- |
| Classes and functions | jmzg_ 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
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.