Developer guide

How the gallery is built, and how to render it, override its templates, read its settings and extend it from a theme or plugin.

FreePro

Architecture

FreePro
NamespaceSiteryn\SiterynProductGalleryZoomSiteryn\SiterynProductGalleryZoomPro
Text domainsiteryn-product-gallery-zoomsiteryn-product-gallery-zoom-pro
Bootplugins_loaded, then fires siteryn_pgz_loadedOn siteryn_pgz_loaded, then fires siteryn_pgz_pro_loaded
Settings optionsiteryn_pgz_settingssiteryn_pgz_pro_settings

On init (priority 20), when Enable Product Gallery is on, Free removes woocommerce_show_product_images from woocommerce_before_single_product_summary, adds its own renderer at priority 20, returns false for WooCommerce's zoom, PhotoSwipe and FlexSlider filters, and filters the woocommerce/product-image-gallery block output. Pro extends Free only through hooks: it swaps the template for the selected style and, when licensed, loads its own assets instead of Free's.

Rendering the gallery

siteryn_pgz_product_gallery( int $product_id = 0 ): void // 0 = current product

The template tag and [siteryn_pgz_gallery] render the markup but don't load assets; Free enqueues its CSS and JS only on single product pages. Elsewhere, enqueue them yourself:

\Siteryn\SiterynProductGalleryZoom\Assets::enqueue_gallery_assets();
siteryn_pgz_product_gallery( 123 ); // or echo do_shortcode( '[siteryn_pgz_gallery id="123"]' );

// Pro (licensed): style shortcodes enqueue their own assets and accept Free settings as attributes.
echo do_shortcode( '[siteryn_pgz_pro_grid id="123" main_image_fit="cover" zoom_mode="lens"]' );

A Pro style rendered through Free's path off a product page also needs \Siteryn\SiterynProductGalleryZoomPro\Assets::enqueue_style_assets( 'grid' ).

Useful public methods

MethodReturns
Frontend::get_gallery_html( $product )The gallery HTML, or '' for an invalid product
Gallery::get_images( $product )The image list passed to the template
Settings::get_all() · Settings::get( $key ) · Settings::defaults()Free settings merged over defaults
Templates::get_template_html( $name, $args ) · Templates::locate( $name )Rendered template · resolved path
Pro License::is_active()Whether the Pro license is valid
Pro VideoMeta::get_videos( $product )A product's videos

Free classes live in Siteryn\SiterynProductGalleryZoom, Pro classes in Siteryn\SiterynProductGalleryZoomPro.

Templates

Copy templates/product-image.php from the Free plugin to your-theme/siteryn-product-gallery-zoom/product-image.php. It receives $product, $images and $settings. Keep the @version header: when the bundled copy has a newer version, administrators see "Siteryn Product Gallery template files should be updated".

id, alt,
full_src, full_srcset, full_sizes, full_width, full_height,   // main image (woocommerce_gallery_image_size)
thumb_src, thumb_width, thumb_height,                         // thumbnail (woocommerce_gallery_thumbnail_size)
lightbox_src, lightbox_width, lightbox_height                 // zoom & lightbox (woocommerce_gallery_full_size)

The product image comes first, then the gallery images, without duplicates. A product without images gets one placeholder item with id 0.

When Pro is licensed and a Pro style is selected, the Pro style's template replaces your theme copy. Pro style templates have no theme path; override them with the siteryn_pgz_pro_style_templates filter.
add_filter( 'siteryn_pgz_pro_style_templates', function ( $templates ) {
	$file = locate_template( 'siteryn-product-gallery-zoom-pro/style-grid.php' );
	if ( $file ) {
		$templates['grid'] = $file;
	}
	return $templates;
}, 20 );

Keep namespace Siteryn\SiterynProductGalleryZoomPro; at the top of the copy. The vertical-slider, vertical-scroll and multirow-slider templates also include a file from parts/; copy it alongside.

Markup contract

The script finds the gallery through these attributes; keep them in a template override.

PartSelector
Rootdiv.images.woocommerce-product-gallery.siteryn-pgz-gallery[data-siteryn-pgz-gallery], with .siteryn-pgz-gallery--thumbs-{bottom|top}, .siteryn-pgz-gallery--transition-{type} and data-arrow-placement, data-arrow-alignment, data-main-transition, data-zoom-mode, data-zoom-lens-shape, data-zoom-window-position; the script sets data-current-index
Slides[data-siteryn-pgz-track] > .siteryn-pgz-gallery__slide[data-index][data-image-id], image img.siteryn-pgz-gallery__main-image[data-zoom-src]
Lightbox triggerbutton[data-siteryn-pgz-lightbox-trigger]
Arrows[data-siteryn-pgz-prev] · [data-siteryn-pgz-next] (.siteryn-pgz-gallery__arrow; inside .siteryn-pgz-gallery__arrow-row--above|--below for those placements)
Thumbnails[data-siteryn-pgz-thumbs] > button.siteryn-pgz-gallery__thumb[data-index] (active: .is-active), inside .siteryn-pgz-gallery__thumbs-wrap; scroll buttons [data-siteryn-pgz-thumb-prev] · [data-siteryn-pgz-thumb-next]
Lightbox[data-siteryn-pgz-lightbox] (data-keyboard, data-touch, data-slideshow-interval), moved to <body>; html.siteryn-pgz-lightbox-open while open
Lightbox parts[data-siteryn-pgz-lightbox-image], -close, -prev, -next, -counter, -thumbs, and toolbar -zoom, -share, -slideshow (all data-siteryn-pgz-lightbox-…)

JavaScript

CSS custom properties

Your settings are printed as an inline style on :root (tablet and mobile overrides in max-width: 782px and 480px media queries). Override them in your theme to restyle the gallery without a template.

PartVariables (--siteryn-pgz-…)
Main imagemain-bg, main-ratio, main-fit, main-border-width, main-border-color, main-radius, main-spacing, main-transition, main-transition-speed
Thumbnailsthumb-ratio, thumb-spacing, thumb-visible-count, thumb-radius, thumb-active-color, thumb-active-width, thumb-inactive-opacity; the script sets thumb-effective-count on the strip
Arrowsarrow-size, arrow-icon-size, arrow-radius, arrow-bg, arrow-icon-color, arrow-border-width, arrow-border-color, arrow-hover-bg, arrow-hover-icon-color, arrow-offset, arrow-shadow
Lightboxlightbox-bg, lightbox-fit, lightbox-max-width, lightbox-icon-color, lightbox-icon-bg
Zoomzoom-inner-scale, zoom-lens-size, zoom-lens-scale, zoom-lens-border-width, zoom-lens-border-color, zoom-window-width, zoom-window-scale, zoom-window-border-width, zoom-window-border-color

The zoom layers the script adds are .siteryn-pgz-zoom-inner, .siteryn-pgz-zoom-lens and .siteryn-pgz-zoom-window (each .is-active while showing).

Data

NameTypeContent
siteryn_pgz_settingsOptionAll Free settings (81 keys)
siteryn_pgz_versionOptionInstalled Free version
siteryn_pgz_pro_settings · siteryn_pgz_pro_versionOptionPro style settings (gallery_style plus per-style keys) · version
siteryn_license_product-gallery-zoom_key · _status · _updateOptionPro license key, cached status, update info (not autoloaded)
_siteryn_pgz_pro_videosPost metaA product's videos: [{url, thumb_id}]
_siteryn_pgz_pro_videos_auto_thumbsPost metaAutomatic YouTube/Vimeo thumbnails, keyed by URL
_siteryn_pgz_pro_video_url · _siteryn_pgz_pro_video_thumb_id · _siteryn_pgz_pro_video_thumb_auto_urlPost metaOlder single-video format: read only when _siteryn_pgz_pro_videos is missing, and removed the next time the product is saved with an active license
siteryn_pgz_outdated_templatesTransientOutdated template check, 1 day
update_post_meta( $product_id, '_siteryn_pgz_pro_videos', array(
	array( 'url' => 'https://www.youtube.com/watch?v=XXXXXXXXXXX', 'thumb_id' => 0 ),
	array( 'url' => 'https://example.com/media/demo.mp4', 'thumb_id' => 789 ),
) );

Video URLs can be self-hosted .mp4, .webm or .ogv files, or anything WordPress can embed. Settings keys are listed per tab on the feature pages; for example zoom_mode is none, inner, lens or window.

Uninstalling Free deletes its two options (on every site of a network). Uninstalling Pro deletes its options and license data; product videos are kept.

Endpoints

There are no REST routes, blocks or public AJAX actions. Admin endpoints require manage_woocommerce and a nonce:

ActionUsed for
wp_ajax_siteryn_pgz_save_settingsSaving a settings tab
admin_post_siteryn_pgz_reset_settings · admin_post_siteryn_pgz_pro_reset_settingsReset to Defaults
wp_ajax_siteryn_pgz_pro_license_actionActivating or deactivating the Pro license

wp_ajax_siteryn_deactivation_feedback (shared by Siteryn plugins) sends the optional deactivation survey; it requires activate_plugins and a nonce.

There are no cron events and no custom capabilities.

wp-config constants

ConstantEffect
SCRIPT_DEBUGLoad unminified CSS and JS
SITERYN_FEEDBACK_ENDPOINTWhere the optional deactivation survey is sent (shared by Siteryn plugins; also filterable with siteryn_deactivation_feedback_endpoint)
SITERYN_PGZ_PRO_LICENSE_API_BASELicense server URL (default https://siteryn.com/wp-json/siteryn/v1), e.g. for staging

Hooks and their examples are on Hooks & filters.