Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Image Block][Lightbox] console error in frontend when closing lightbox when img tag is added inside picture tag #56541

Closed
wordpressfan opened this issue Nov 27, 2023 · 6 comments · Fixed by #57089
Assignees
Labels
[Block] Image Affects the Image Block [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended

Comments

@wordpressfan
Copy link

Description

When using image optimizer plugin that adds the webp conversion functionality with image block lightbox feature (expand on click), it shows console error when closing the lightbox modal.

image

We shouldn't see any console error in this case.

Step-by-step reproduction instructions

  1. Create a new page with an image block and choose "Expand on click"
  2. Install and activate imagify plugin or any image optimization plugin.
  3. Visit the frontend and click on the image
  4. Close the image lightbox and check the console

Screenshots, screen recording, code snippet

When using image optimizer plugin that adds the webp conversion functionality, it converts every img tag (here this img tag is generated from image block with lightbox enabled) in the page to a picture tag with sources and img tag inside like below:

<picture fetchpriority="high" decoding="async" class="wp-image-37350">
	<source type="image/webp" srcset="https://xxx.xx/wp-content/uploads/2023/11/xxx-1-766x800.jpg.webp 766w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-430x449.jpg.webp 430w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-700x731.jpg.webp 700w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-287x300.jpg.webp 287w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-768x802.jpg.webp 768w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1.jpg.webp 919w" sizes="(max-width: 766px) 100vw, 766px"/>
	<img fetchpriority="high" decoding="async" width="766" height="800" data-wp-effect--setStylesOnResize="effects.core.image.setStylesOnResize" data-wp-effect="effects.core.image.setButtonStyles" data-wp-init="effects.core.image.initOriginImage" data-wp-on--click="actions.core.image.showLightbox" data-wp-on--load="actions.core.image.handleLoad" src="https://xxx.xx/wp-content/uploads/2023/11/xxx-1-766x800.jpg" alt="" srcset="https://xxx.xx/wp-content/uploads/2023/11/xxx-1-766x800.jpg 766w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-430x449.jpg 430w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-700x731.jpg 700w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-287x300.jpg 287w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1-768x802.jpg 768w, https://xxx.xx/wp-content/uploads/2023/11/xxx-1.jpg 919w" sizes="(max-width: 766px) 100vw, 766px"/>
</picture>

image block adds a button with class lightbox-trigger and then in js they use

ref.parentElement.querySelector(
	'.lightbox-trigger'
);

as in here

ref here is the img tag and its parent in our case is the picture tag not the main container tag and this picture tag doesn't contain this button so context.core.image.lightboxTriggerRef equals null in this case, and when closing the lightbox it fails here:

https://github.com/WordPress/gutenberg/blob/trunk/packages/block-library/src/image/view.js#L155

This can be easily fixed by changing this line

context.core.image.lightboxTriggerRef = ref.parentElement.querySelector('.lightbox-trigger' );

To

context.core.image.lightboxTriggerRef = ref.closest('.wp-lightbox-container').querySelector(".lightbox-trigger")

Environment info

No response

Please confirm that you have searched existing issues in the repo.

Yes

Please confirm that you have tested with all plugins deactivated except Gutenberg.

No

@wordpressfan wordpressfan added the [Type] Bug An existing feature does not function as intended label Nov 27, 2023
@wordpressfan
Copy link
Author

Adding more context on how we are trying to fix this issue now:

Here image block is adding a new attribute to the image tag data-wp-init to call the init code that we mentioned above.

based on this document we can define multiple wp-init directives but with the name changed, If we managed to call our init code after theirs, we will be able to check if this mentioned variable inside context is null so we can define it whatever we need.

So we managed using filters to change data-wp-init to be data-wp-init--core and added our init directive data-wp-init--imagify but the problem that I need to extend the effects store for image block without changing it inside the core block view.js

Any idea?

@t-hamano t-hamano added Needs Testing Needs further testing to be confirmed. [Block] Image Affects the Image Block labels Nov 27, 2023
@michalczaplinski
Copy link
Contributor

I've tested the issue and unfortunately, it doesn't seem like this plugin is compatible with the lightbox.

I didn't manage to reproduce the problem but when the plugin is activated, I can see other issues:

  1. the "Enlarge" button is positioned incorrectly
  2. There is a noticeable animation glitch when expanding the lightbox
Screen.Recording.2023-12-07.at.19.51.03.mov

@t-hamano
Copy link
Contributor

I wrote code to reproduce this problem. This is the code to simply wrap the img element with a picture element.

function render_block_image_with_picture( $block_content ) {
	preg_match( '/<img.*?\/>/', $block_content, $matches );

	if ( ! isset( $matches[0] ) ) {
		return $block_content;
	}

	$image_tag     = $matches[0];
	$new_image_tag = sprintf(
		'<picture>%s</picture>',
		$image_tag
	);

	$block_content = str_replace( $image_tag, $new_image_tag, $block_content );

	return $block_content;
}
add_filter( 'render_block_core/image', 'render_block_image_with_picture', 20 );

If you open a Lightbox by clicking on an image on the front end and close the Lightbox, the following error will be logged in the browser console.

view.js:161 Uncaught TypeError: Cannot read properties of null (reading 'focus')
    at view.js:161:29

This hook has a priority of 20, while the Lightbox HTML is added via a hook with a higher priority of 15.

In other words, the following processing is performed:

  • A button with lightbox-trigger class is added next to the img element via a hook with a priority of 15
  • The img element is wrapped in a picture element via a hook with a priority of 20

As a result, HTML similar to the following will be generated.

<figure class="wp-block-image">
	<picture>
		<img class="wp-image-1">
	</picture>
	<button class="lightbox-trigger"><svg><path></path></svg></button>
</figure>

The code below causes an error because the parent of the img element is no longer a figure element (i.e. a block wrapper).

initOriginImage() {
const ctx = getContext();
const { ref } = getElement();
ctx.imageRef = ref;
ctx.lightboxTriggerRef =
ref.parentElement.querySelector( '.lightbox-trigger' );

This instability is also mentioned in #55407.

I think we need to find an approach that allows Lightbox to work correctly without errors, no matter what priority the image block rendering is hooked to.

@t-hamano t-hamano removed the Needs Testing Needs further testing to be confirmed. label Dec 10, 2023
@wordpressfan
Copy link
Author

Exactly @t-hamano I was about to send you a way to test that, but you got it by yourself, many thanks.

Add to that, you can replicate the issue with the filter the_content but yes this is the same idea you mentioned because this filter is firing after (render_block_core/image with priority 20)

I believe this needs to be fixed from the JS side as I mentioned in the issue description:

This can be easily fixed by changing this line

context.core.image.lightboxTriggerRef = ref.parentElement.querySelector('.lightbox-trigger' );

To

context.core.image.lightboxTriggerRef = ref.closest('.wp-lightbox-container').querySelector(".lightbox-trigger")

so this will get the closest container class and move from there, what do u think?

Also I have a question to make workaround for it:
I need to extend the effects store for image block without changing it inside the core block view.js, how could I build the following code:

import { store } from '@wordpress/interactivity';
store(
	{
		effects: {
			core: {
				image: {
					effects: {
						initImagify: ({context, ref}) => {
							context.core.image.lightboxTriggerRef = ref.closest('.wp-lightbox-container').querySelector(".lightbox-trigger");
						},
					}
				}
			}
		}
	}
);

@t-hamano
Copy link
Contributor

I thought of an approach using the wp-init directive instead of a query to get the trigger button ref more stably. See #57089 for details.

@wordpressfan
Copy link
Author

I like this new approach, hope it's approved and released soon.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Block] Image Affects the Image Block [Status] In Progress Tracking issues with work in progress [Type] Bug An existing feature does not function as intended
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants