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
| Filter | Default | What it changes |
|---|---|---|
gallery_z_taxonomy_object_types | ['attachment', 'post', 'page'] | The post types Gallery Categories are attached to |
gallery_z_eager_items | the desktop column count | How many items of the page’s first gallery load eagerly (the first row) |
gallery_z_image_size_width | 480 | Width 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):
| Part | Size | Loads |
|---|---|---|
view.js – filter, gallery core | 3.1 KB | on pages with a gallery or filter |
layout.js – masonry and rows placement | 1.8 KB | when such a gallery is on the page; never for grid, carousel or accordion (pure CSS) |
layouts.js – carousel navigation and loop, click accordion | 3.5 KB | when a carousel or accordion is on the page |
lightbox.js | 2.9 KB | when the browser is idle, only on pages with a lightbox gallery |
| Masonry pre-paint script | 1.0 KB | inline, once, only with masonry or rows |
| Base CSS | 2.3 KB | where a gallery renders |
| Carousel, accordion, arrows, reveal and lightbox CSS | 0.5–1.1 KB each | only 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 isloading="lazy"withsizes="auto". - Right-sized files: every image gets a
sizesvalue 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):
| LCP | CLS | INP (filter click) | Images on first view | |
|---|---|---|---|---|
| Phone, 390px | ~260–310 ms | 0.014 | ~65 ms | 18 requests, 254 KB |
| Desktop, 1440px | ~360 ms | 0.001 | ~55 ms | 20 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_dataandrender_blockhooks decorate each item’s opening tag withWP_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-growproportional to the aspect ratio; the grid is CSS grid withaspect-ratioandobject-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-filterand:has()only add polish.