# Developers

> Developer notes for Wisp Gallery: WP-CLI commands, the Playground blueprint, filters and hooks, stylesheet and script handles, and how it stays fast.

Source: https://wispgallery.com/docs/developers/

Wisp Gallery 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 wisp-gallery.zip --activate
wp wisp-gallery import list
wp wisp-gallery import <envira|nextgen|modula|foogallery|all> [--ids=1,2] [--force] [--dry-run]
```

The import command is described on [Switching from other plugins](https://wispgallery.com/docs/switching/#cli). Gallery Categories are a regular taxonomy, so core’s term commands work too:

```
wp term create wisp_gallery_category Architecture
wp post term add 123 wisp_gallery_category architecture
```

## Live preview blueprint

The plugin ships a [WordPress Playground](https://wordpress.org/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 |
| --- | --- | --- |
| `wisp_gallery_taxonomy_object_types` | `['attachment', 'post', 'page']` | The post types Gallery Categories are attached to |
| `wisp_gallery_eager_items` | the desktop column count | How many items of the page’s first gallery load eagerly (the first row) |
| `wisp_gallery_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( 'wisp_gallery_taxonomy_object_types', function ( $types ) {
	$types[] = 'project';
	return $types;
} );

// Load the first two rows eagerly.
add_filter( 'wisp_gallery_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( 'wisp-gallery-carousel' );
// Also: wisp-gallery-accordion, wisp-gallery-nav, wisp-gallery-reveal, wisp-gallery-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):

|  | 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_data` and `render_block` hooks decorate each item’s opening tag with `WP_HTML_Tag_Processor`: its categories (`data-wisp-gallery-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.

Further reading: [Custom styles for Wisp Gallery](https://wispgallery.com/blog/custom-styles/) (filter styles, caption looks, hover effects) and [why a gallery doesn’t need jQuery](https://wispgallery.com/blog/gallery-without-jquery/), with measurements from the [100-photo demo](https://wispgallery.com/100-photos/).
