Developers

Gallery Z is built on core blocks, the Interactivity API and plain CSS. This page covers the command line, the Playground blueprint, the hooks, and what loads when.

WP-CLI

wp plugin install gallery-z.zip --activate
wp gallery-z import list
wp gallery-z import <envira|nextgen|modula|foogallery|all> [--ids=1,2] [--force] [--dry-run]

The import command is described on Switching from other plugins. Gallery Categories are a regular taxonomy, so core’s term commands work too:

wp term create gallery_z_category Architecture
wp post term add 123 gallery_z_category architecture

Live preview blueprint

The plugin ships a WordPress Playground blueprint, assets/blueprints/blueprint.json, for the “Live Preview” button on wordpress.org. It installs the plugin, imports 12 Pexels photos in 4 categories and opens a demo page with a filter, a masonry gallery and a carousel.

It is generated from bin/playground-demo.php in the plugin repository:

npm run blueprint                                        # regenerate assets/blueprints/blueprint.json
node bin/blueprint.mjs --local <zip url> <out.json>       # variant that installs a local zip
npx @wp-playground/cli server --blueprint=<out.json>      # try it locally

wordpress.org reads the blueprint from the SVN assets/blueprints/ folder, not from the plugin zip.

Filters

FilterDefaultWhat it changes
gallery_z_taxonomy_object_types['attachment', 'post', 'page']The post types Gallery Categories are attached to
gallery_z_eager_itemsthe desktop column countHow many items of the page’s first gallery load eagerly (the first row)
gallery_z_image_size_width480Width of the extra image size between WordPress’ 300px and 768px sizes
// Gallery Categories for a "project" post type too.
add_filter( 'gallery_z_taxonomy_object_types', function ( $types ) {
	$types[] = 'project';
	return $types;
} );

// Load the first two rows eagerly.
add_filter( 'gallery_z_eager_items', function ( $count, $settings ) {
	return $count * 2;
}, 10, 2 );

Assets and handles

Only what a page uses loads (sizes gzipped):

PartSizeLoads
view.js – filter, gallery core3.1 KBon pages with a gallery or filter
layout.js – masonry and rows placement1.8 KBwhen such a gallery is on the page; never for grid, carousel or accordion (pure CSS)
layouts.js – carousel navigation and loop, click accordion3.5 KBwhen a carousel or accordion is on the page
lightbox.js2.9 KBwhen the browser is idle, only on pages with a lightbox gallery
Masonry pre-paint script1.0 KBinline, once, only with masonry or rows
Base CSS2.3 KBwhere a gallery renders
Carousel, accordion, arrows, reveal and lightbox CSS0.5–1.1 KB eachonly where a gallery uses it

Stylesheets are enqueued from the blocks’ render callbacks: into the <head> on block themes, as a <link> right before the block on classic themes. A theme that switches layouts or options on the fly can enqueue the optional parts itself:

wp_enqueue_style( 'gallery-z-carousel' );
// Also: gallery-z-accordion, gallery-z-nav, gallery-z-reveal, gallery-z-lightbox

Performance

  • Above the fold: the first desktop row of the page’s first gallery loads eagerly, its first image with fetchpriority="high". Everything else is loading="lazy" with sizes="auto".
  • Right-sized files: every image gets a sizes value from the gallery’s columns, alignment and the theme’s content and wide size, plus the extra 480px image size.
  • No layout shift: images carry width and height; rows and grids are pure CSS; masonry and rows are placed by a 1 KB script right after the gallery, before the first paint. CSP nonces are supported through wp_get_inline_script_tag.
  • Little work at runtime: the layout engine reuses the pre-paint placement and only lays out again when something it depends on changes. Carousel autoplay pauses off screen.
  • Filtering only animates the items that are on screen; the lightbox is created on first use.
  • No virtualization, on purpose: a few hundred lazy items are cheap, and keeping them in the page preserves find-in-page, SEO, accessibility and correct filter counts.

Measured on a 100-photo page (logged out, fast 4G; the phone with 4× CPU slowdown):

LCPCLSINP (filter click)Images on first view
Phone, 390px~260–310 ms0.014~65 ms18 requests, 254 KB
Desktop, 1440px~360 ms0.001~55 ms20 requests, 910 KB

Serving WebP or AVIF sub-sizes – with WordPress’ image_editor_output_format filter or the Performance Lab plugin – saves another 30–50% of image bytes.

How it works

  • Server rendering. While a gallery renders, render_block_data and render_block hooks decorate each item’s opening tag with WP_HTML_Tag_Processor: its categories (data-gallery-z-terms), its aspect ratio for rows, lightbox data and the click behavior.
  • Front end. One Interactivity API module, shared by gallery and filter, with no dependencies. Filtering toggles a class on items inside a View Transition, so items move to their new places; browsers without View Transitions switch instantly. The lightbox is a native <dialog>.
  • Layouts are CSS. Rows are flexbox with flex-grow proportional to the aspect ratio; the grid is CSS grid with aspect-ratio and object-fit; masonry is CSS grid with 1px rows, and a small script puts each item in the shortest column (skipped where the browser has native masonry). Responsive values are custom properties that fall back from mobile to tablet to desktop.
  • Progressive enhancement. Without JavaScript every item shows and links work; lightbox links point to the image file. @starting-style, View Transitions, color-mix(), backdrop-filter and :has() only add polish.