Skip to content

Image Block: Restore captions in lightbox overlay with Gallery-level toggles#77477

Open
dan-zakirov wants to merge 2 commits into
WordPress:trunkfrom
dan-zakirov:fix/lightbox-captions-60469
Open

Image Block: Restore captions in lightbox overlay with Gallery-level toggles#77477
dan-zakirov wants to merge 2 commits into
WordPress:trunkfrom
dan-zakirov:fix/lightbox-captions-60469

Conversation

@dan-zakirov
Copy link
Copy Markdown

What?

Restores figcaption rendering inside the Image block lightbox overlay so captions authored via the inline caption field become visible when an image is enlarged via the core lightbox. Adds two Gallery-level toggles (Show captions in gallery / Show captions in lightbox) so authors can choose where captions are displayed without editing each image individually.

chrome_9TRMnb5y51.mp4
image

Why?

Fixes #60469.

Captions have been hidden in the lightbox overlay since #58835 shipped in WordPress 6.5. Since then, users who enable Expand on click on an Image block — or Enlarge on click on a Gallery block — lose the contextual information their caption provides exactly when users most need it: when the image is enlarged and isolated from its surrounding content.

The two Gallery toggles solve the separate-but-related problem that the inline caption is overloaded: it renders both under the image on the page and inside the lightbox. Sometimes authors want both; sometimes they want a compact grid with descriptions surfacing only on enlarge. The toggles cover the full matrix without introducing a separate caption field.

This also unblocks an effort to replace the wordpress.org Plugin Directory's legacy React screenshot gallery with native Gallery + core lightbox (see meta#8083 and WordPress/wordpress.org#524). Plugin screenshot captions typically explain what the screenshot shows, which is only useful when the screenshot is actually enlarged — and plugin pages work best when the grid itself stays compact.

How?

Five files, ~157 lines. All changes scoped to the Image and Gallery blocks.

packages/block-library/src/gallery/block.json

Adds two optional boolean attributes (showCaptionInGallery, showCaptionInLightbox) and exposes them through providesContext, so inner Image blocks can honour them without having to read the parent's state directly.

packages/block-library/src/gallery/edit.js

Adds a single ToolsPanelItem labelled Captions under the existing Navigation button type control, rendered only when the gallery has images with the lightbox enabled. Inside a BaseControl heading (to match the visual weight of the other sections) it renders a VStack of two ToggleControls:

  • Show in gallery — default on
  • Show in lightbox — default on

Resetting the panel item clears both attributes back to undefined (treated as true in PHP), so the default behaviour is full backward compatibility.

packages/block-library/src/image/block.json

Adds showCaptionInGallery and showCaptionInLightbox to usesContext.

packages/block-library/src/image/index.php

Two small additions:

  • block_core_image_render_lightbox() now extracts the caption from the already-rendered block content and stores it in wp_interactivity_state(). When the parent Gallery's context reports showCaptionInLightbox === false, the stored caption is an empty string so the overlay stays empty for those images. The caption is passed through wp_strip_all_tags() because the Interactivity API renders it via data-wp-text, which outputs plain text.
  • block_core_image_print_lightbox_overlay() adds a <figcaption class="wp-lightbox-caption"> inside each of the two overlay <figure> elements, bound via data-wp-text="state.selectedImage.caption" and data-wp-class--has-caption="!!state.selectedImage.caption".
  • A new block_core_image_apply_gallery_caption_visibility() filter (priority 20, after the lightbox filter) strips the <figcaption> from the rendered Image block when the Gallery context reports showCaptionInGallery === false. Running after the lightbox filter means the caption is still captured for the overlay before it is removed from the on-page output.

packages/block-library/src/image/style.scss

  • The legacy .wp-lightbox-overlay .wp-block-image figcaption { display: none } rule is narrowed to figcaption:not(.wp-lightbox-caption) so it keeps hiding any stray inline figcaption nested inside the overlay but leaves our explicit caption element alone.
  • A new .wp-lightbox-caption rule positions the caption as a bottom-aligned bar over the image with a top-fading dark gradient for legibility; pointer-events: none lets clicks on the empty gradient area still close the overlay.
  • A .wp-lightbox-overlay.active .wp-lightbox-caption.has-caption rule fades the caption in once the zoom animation has had a chance to settle (transition: opacity 200ms ease-out 200ms). The inverse fade-out uses a faster 120ms ease-in declared on the base rule.
  • @media (prefers-reduced-motion: reduce) clears the transition on both rules so users opted into reduced motion see the caption appear and disappear instantly.

No JavaScript (view.js) changes were required — setButtonStyles() already accounts for caption height when measuring the figure, so overlay sizing calculations remain intact.

Backward compatibility

  • No existing block attributes were modified; the two new attributes default to undefined, which is treated as true in PHP, so existing posts behave as before — plus they now actually show captions in the lightbox (the behaviour that existed before Image block: refactor and remove data-wp-body #58835).
  • The legacy figcaption { display: none } rule inside the overlay is preserved, just narrowed via :not(.wp-lightbox-caption).
  • Gallery and Image native editor mirrors (*.native.js) were not modified — the new attributes are optional and the native UI simply ignores them.

A note on rich-text captions

The inline caption attribute is a rich-text, so authored markup like <strong> and <a> is preserved at the block level and still renders on the front-end figure. Inside the lightbox overlay the markup is stripped to plain text because the Interactivity API currently has no safe way to bind HTML from state — data-wp-text is the only text-rendering directive. Keeping links live inside the overlay (plus the focus/escape interactions that requires) is worth a separate design discussion.

Testing Instructions

  1. Create a new page.
  2. Add a Gallery block with several images; upload each one with a caption.
  3. From the block toolbar's Link menu pick Enlarge on click.
  4. In the Gallery block sidebar, below Navigation button type, find the new Captions section with two toggles.

Expected default state: both toggles on, captions visible both in the grid and in the lightbox (the pre-#58835 behaviour). Click an image — the lightbox opens and the caption fades in at the bottom once the zoom settles.

Variations to cover:

  • Show in gallery: off, Show in lightbox: on — captions disappear from the grid but remain in the lightbox. This is the main use case this PR is meant to unblock.
  • Show in gallery: on, Show in lightbox: off — captions stay under the thumbnails but the lightbox overlay shows no caption.
  • Both off — captions are authored but never shown (useful for accessibility or migration scenarios).
  • Reduced motion — with prefers-reduced-motion: reduce set in the OS, captions should appear and disappear without a fade.
  • No caption — an image without a caption should render no caption area in the overlay.
  • Long caption — a caption long enough to wrap should wrap inside the image width instead of overflowing.
  • Single Image block outside a gallery — the lightbox should show the caption with default styling; the new Gallery-level toggles do not apply to standalone Image blocks (they're scoped to the Gallery context).
  • Keyboard navigation — the caption should update correctly as you navigate between images with left/right arrow keys.
  • Screen reader — the <figcaption> inside the overlay is still read as the image's caption when the overlay is open.

Screenshots or screencast

Before: caption hidden in the lightbox.
After: caption fades in at the bottom of the lightbox overlay, with Gallery-level controls for where captions should be displayed.

Related work

This PR unblocks the first phase of a longer effort to replace the wordpress.org Plugin Directory's screenshot gallery with core blocks:

A follow-up Gutenberg PR is planned to add per-image overrides for these settings (so an individual image inside a gallery can opt out of the gallery-wide default) and to look at richer caption options in the lightbox (e.g. link support, fixed positions). Those are not required to close this issue and are kept out of this PR to keep the scope focused.

Fixes #60469

…toggles

Renders the inline caption inside the lightbox overlay (hidden since
PR WordPress#58835 shipped in WordPress 6.5) and adds two Gallery-level toggles
so authors can control where captions appear.

Image block:
- Extract caption in `block_core_image_render_lightbox()` and pass it
  to the Interactivity API state (plain text via `wp_strip_all_tags`).
- Add a `<figcaption class="wp-lightbox-caption">` inside the overlay
  template, bound via `data-wp-text`.
- New `block_core_image_apply_gallery_caption_visibility()` filter to
  strip the inline caption when the parent Gallery opts out.

Gallery block:
- New `showCaptionInGallery` and `showCaptionInLightbox` optional
  attributes exposed via `providesContext`.
- New `Captions` section in the Settings panel with two toggles.

Styles fade the overlay caption in after the zoom animation settles,
with `prefers-reduced-motion` disabling the transition.

This unblocks the WordPress.org Plugin Directory screenshot migration
(WordPress/wordpress.org#524, meta#8083). A follow-up PR is planned
for per-image overrides.

Fixes WordPress#60469
@github-actions
Copy link
Copy Markdown

Warning: Type of PR label mismatch

To merge this PR, it requires exactly 1 label indicating the type of PR. Other labels are optional and not being checked here.

  • Required label: Any label starting with [Type].
  • Labels found: .

Read more about Type labels in Gutenberg. Don't worry if you don't have the required permissions to add labels; the PR reviewer should be able to help with the task.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 19, 2026

The following accounts have interacted with this PR and/or linked issues. I will continue to update these lists as activity occurs. You can also manually ask me to refresh this list by adding the props-bot label.

Unlinked Accounts

The following contributors have not linked their GitHub and WordPress.org accounts: @mamaretti.

Contributors, please read how to link your accounts to ensure your work is properly credited in WordPress releases.

If you're merging code through a pull request on GitHub, copy and paste the following into the bottom of the merge commit message.

Unlinked contributors: mamaretti.

Co-authored-by: dan-zakirov <[email protected]>
Co-authored-by: andreawetzel <[email protected]>
Co-authored-by: annezazu <[email protected]>
Co-authored-by: artemiomorales <[email protected]>
Co-authored-by: webzunft <[email protected]>
Co-authored-by: gziolo <[email protected]>
Co-authored-by: t-hamano <[email protected]>

To understand the WordPress project's expectations around crediting contributors, please review the Contributor Attribution page in the Core Handbook.

@github-actions github-actions Bot added [Package] Block library /packages/block-library First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository labels Apr 19, 2026
@github-actions
Copy link
Copy Markdown

👋 Thanks for your first Pull Request and for helping build the future of Gutenberg and WordPress, @dan-zakirov! In case you missed it, we'd love to have you join us in our Slack community.

If you want to learn more about WordPress development in general, check out the Core Handbook full of helpful information.

@andreawetzel
Copy link
Copy Markdown
Contributor

One testing note is that the option toggled Show in gallery: off did not remove the captions from appearing in the gallery in the block editor as I expected it to. It did remove the gallery captions for the published front end page. Thank you for working on this feature.

Addresses testing feedback that `Show in gallery: off` only affected the
published front end and left the caption visible in the block editor.

- `image.js` now reads `showCaptionInGallery` from the provided block
  context and skips rendering the `<Caption>` component when it is
  explicitly false.
- Added `"default": true` to the `showCaptionInGallery` and
  `showCaptionInLightbox` attributes in `gallery/block.json` so the
  context value is a stable boolean; otherwise the serialized block
  context would have coerced the missing attribute to `false`, which
  would have hidden the caption for every gallery in the editor.
@dan-zakirov
Copy link
Copy Markdown
Author

One testing note is that the option toggled Show in gallery: off did not remove the captions from appearing in the gallery in the block editor as I expected it to. It did remove the gallery captions for the published front end page. Thank you for working on this feature.

Pushed 87ca863 — the editor now also hides the caption when Show in gallery is off.

I'm not 100% sure this is the right call: hiding the caption in the editor also removes the UI for editing it. A few ways we could handle this:

  • Keep it visible and editable in the editor, no visual hint (toggle only affects the published output).
  • Keep it visible but render it with a dimmed/"hidden on front-end" style so it's clear the caption won't show on the page.
  • Keep it visible plus a small help icon with a tooltip explaining where the caption will and won't appear.
  • Hide the inline caption in the editor but expose the caption via a sidebar field (similar to Alternative text), so it stays visible and editable from the Inspector.

Happy to go with whichever you think fits the block-librarys patterns best

@dan-zakirov
Copy link
Copy Markdown
Author

Worth mentioning why this matters on our end - it's Phase 1 of the plan outlined in WordPress/wordpress.org#524 (comment): replace the Plugin Directory's React screenshot gallery with native Gallery + core lightbox (meta#8083). Phase 2 will add masonry as a Gallery layout/style variation (#28247) - keeping scope tight here so each phase lands cleanly.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

First-time Contributor Pull request opened by a first-time contributor to Gutenberg repository [Package] Block library /packages/block-library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Lightbox: caption missing when opening lightbox image

2 participants