Skip to content

fix: Ensure tabs are properly saved and backfill deprecations - #188

Open
milindmore22 wants to merge 16 commits into
developfrom
fix/210-deprecations
Open

fix: Ensure tabs are properly saved and backfill deprecations#188
milindmore22 wants to merge 16 commits into
developfrom
fix/210-deprecations

Conversation

@milindmore22

Copy link
Copy Markdown
Contributor

Summary

This pull request refactors the deprecated versions of the Carousel block to improve maintainability and test coverage. It introduces a shared attributes and supports schema for all deprecated entries, adds a new SaveV210 function for the v2.1.0 save implementation, and provides comprehensive tests for the deprecations. Additionally, it removes the translation function from the ariaLabelPattern field in all save implementations.

Refactoring and Code Maintenance

  • Introduced a sharedAttributes and sharedSupports object to unify the schema for all deprecated Carousel block versions, reducing duplication and making future updates easier. [1] [2]
  • Added a new SaveV210 function to represent the v2.1.0 save logic, and updated the deprecated array to include this version as the latest deprecation entry. [1] [2]
  • Exported SaveV200, SaveV203, and SaveV210 for use in tests and other modules.

Testing Improvements

  • Added a new test file deprecated.test.tsx to verify the structure and behavior of the deprecated Carousel block versions, including attribute schemas and context output.

Internationalization

  • Removed the translation function (__) from the ariaLabelPattern field in all save implementations for both current and deprecated Carousel block versions, standardizing it as a plain string. [1] [2] [3]

Type of change

  • Bug fix
  • New feature
  • Enhancement/refactor
  • Documentation update
  • Test update
  • Build/CI/tooling

Related issue(s)

N/A

What changed

  • Added a new SaveV210 function to represent the v2.1.0 save logic, and updated the deprecated array to include this version as the latest deprecation entry. [1] [2]
  • Exported SaveV200, SaveV203, and SaveV210 for use in tests and other modules.

Breaking changes

Does this introduce a breaking change? If yes, describe the impact and migration path below.

  • Yes — migration path:
  • No

Testing

Describe how this was tested.

  • Unit tests
  • Manual testing
  • Cross-browser testing (if UI changes)

Test details:

Screenshots / recordings

If applicable, add screenshots or short recordings.

Checklist

  • I have self-reviewed this PR
  • I have added/updated tests where needed
  • I have updated docs where needed
  • I have checked for breaking changes

Copilot AI balanced review requested due to automatic review settings August 7, 2026 09:49

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Warning

Copilot couldn't run its full agentic review because it didn't start before the timeout. Make sure your repository has a runner available, or add a copilot-code-review.yml file specifying one with the runs-on attribute. See the docs for more details.

Refactors Carousel block deprecations by centralizing shared schema/support definitions, adding a v2.1.0 deprecated save implementation, and standardizing ariaLabelPattern as a plain string for saved output.

Changes:

  • Added SaveV210 and updated the deprecated array ordering to include it as the latest deprecated save.
  • Introduced sharedAttributes / sharedSupports to reduce duplication across deprecated entries.
  • Added unit tests for deprecated entries and exported deprecated save functions for testability.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 5 comments.

File Description
src/blocks/carousel/save.tsx Removes translation call from ariaLabelPattern in the current save output.
src/blocks/carousel/deprecated.tsx Adds SaveV210, centralizes deprecated schema/supports, and removes translation call from deprecated ariaLabelPattern.
src/blocks/carousel/tests/deprecated.test.tsx Adds tests validating the deprecated array structure and SaveV210 context output.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/blocks/carousel/deprecated.tsx
Comment thread src/blocks/carousel/deprecated.tsx Outdated
Comment thread src/blocks/carousel/save.tsx Outdated
Comment thread src/blocks/carousel/deprecated.tsx Outdated
Comment thread src/blocks/carousel/deprecated.tsx Outdated
…t translation of ariaLabelPattern for consistent markup
Copilot AI review requested due to automatic review settings August 7, 2026 10:18

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 3 out of 3 changed files in this pull request and generated 3 comments.

Suppressed comments (2)

src/blocks/carousel/save.tsx:66

  • This makes ariaLabelPattern permanently English in saved output. Because this value is intended for ARIA label text, hard-coding it prevents localization for non-English sites (accessibility regression). A better approach is to keep saved markup stable while still localizing at runtime (e.g., store a stable message key/identifier in saved context and translate in the interactive script), rather than persisting an English string.
		// Un-translated pattern to keep saved block markup consistent across translations
		ariaLabelPattern: 'Go to slide %d',

src/blocks/carousel/tests/deprecated.test.tsx:59

  • This test is brittle because it hard-codes the total number of deprecated entries. Adding a future deprecation (which is expected over time) will fail the test even if ordering and behavior remain correct. Consider asserting the relative ordering of these known entries (e.g., first entry is SaveV210, and SaveV203 appears before SaveV200) without asserting the exact array length.
	it( 'should export a deprecated array with three deprecation entries', () => {
		expect( Array.isArray( deprecated ) ).toBe( true );
		expect( deprecated ).toHaveLength( 3 );
		expect( deprecated[ 0 ].save ).toBe( SaveV210 );
		expect( deprecated[ 1 ].save ).toBe( SaveV203 );
		expect( deprecated[ 2 ].save ).toBe( SaveV200 );
	} );

Comment thread src/blocks/carousel/deprecated.tsx
Comment thread src/blocks/carousel/deprecated.tsx Outdated
Comment thread src/blocks/carousel/deprecated.tsx

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Suppressed comments (4)

src/blocks/carousel/types.ts:31

  • carouselId is optional in CarouselAttributes, but block.json defines it as a string attribute with a default (\"\"), and the save implementations treat it as a string. Consider making this carouselId: string; to keep TS types aligned with the block schema and reduce the need for runtime fallback logic.
	autoScrollStopOnInteraction: boolean;
	autoScrollStopOnMouseEnter: boolean;
	useTabs: boolean;
	carouselId?: string;
};

src/blocks/carousel/save.tsx:90

  • This fallback is redundant given carouselId is already defaulted during destructuring (carouselId = ''). If you still want a defensive fallback, prefer nullish coalescing (carouselId ?? '') to avoid treating other falsy values as empty (and otherwise just pass carouselId).
		carouselId: carouselId || '',

src/blocks/carousel/deprecated.tsx:276

  • The comment on ariaLabelPattern indicates the goal is locale-independent saved markup, but countLabelPattern and announcementPattern are still translated during save, which keeps data-wp-context locale-dependent. To fully avoid validation drift across locales, consider also making these un-translated in save (and translating at runtime in JS), or revising the comment/rationale so it’s not misleading.
		// Un-translated pattern to keep saved block markup consistent across translations
		ariaLabelPattern: 'Go to slide %d',
		/* translators: {{currentSlide}}: current slide number, {{totalSlides}}: total slide count. */
		countLabelPattern: __(
			'Slide {{currentSlide}} of {{totalSlides}}',
			'rt-carousel',
		),
		announcement: '',
		shouldAnnounce: false,
		/* translators: {{currentSlide}}: current slide number, {{totalSlides}}: total slide count. */
		announcementPattern: __(
			'Slide {{currentSlide}} of {{totalSlides}}',
			'rt-carousel',
		),

src/blocks/carousel/block.json:131

  • This PR introduces a new persisted attribute (carouselId) in the block schema, and it’s now serialized into data-wp-context in save.tsx. The PR description focuses on deprecated refactors + ariaLabelPattern; consider explicitly calling out this schema/API addition (even if non-breaking) so downstream consumers understand the new attribute.
		"useTabs": {
			"type": "boolean",
			"default": false
		},
		"carouselId": {
			"type": "string",
			"default": ""
		}

Comment thread src/blocks/carousel/__tests__/deprecated.test.tsx Outdated
Comment thread src/blocks/carousel/save.tsx Outdated
Comment thread src/blocks/carousel/save.tsx Outdated
Comment thread src/blocks/carousel/deprecated.tsx Outdated
@milindmore22
milindmore22 requested review from Copilot and removed request for Copilot August 10, 2026 08:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated 1 comment.

Suppressed comments (2)

src/blocks/carousel/types.ts:31

  • carouselId is defined with a default of \"\" in block.json (and in the deprecated attribute schema), so it will be present as a string at runtime. Making it optional in CarouselAttributes can create unnecessary undefined handling and mismatch the block schema; consider making it a required string instead (or ensure all attribute access sites treat it as optional consistently).
	autoScrollStopOnInteraction: boolean;
	autoScrollStopOnMouseEnter: boolean;
	useTabs: boolean;
	carouselId?: string;
};

src/blocks/carousel/tests/deprecated.test.tsx:71

  • The new tests primarily validate array structure and SaveV210 output; they don’t exercise SaveV200 / SaveV203 rendering or key serialization behaviors (notably the ariaLabelPattern change described in the PR summary). To better cover the refactor and prevent regressions, add assertions that SaveV200/SaveV203 produce the expected wrapper props/context (and explicitly validate ariaLabelPattern is a plain string for each save implementation).
describe( 'Carousel Deprecations', () => {
	it( 'should export a deprecated array with three deprecation entries', () => {
		expect( Array.isArray( deprecated ) ).toBe( true );
		expect( deprecated ).toHaveLength( 3 );
		expect( deprecated[ 0 ].save ).toBe( SaveV210 );
		expect( deprecated[ 1 ].save ).toBe( SaveV203 );
		expect( deprecated[ 2 ].save ).toBe( SaveV200 );
	} );

	it( 'should include all attributes in shared attributes schema across deprecation entries', () => {
		deprecated.forEach( ( entry ) => {
			expect( entry.attributes ).toHaveProperty( 'transition' );
			expect( entry.attributes ).toHaveProperty( 'lazyLoadImages' );
			expect( entry.attributes ).toHaveProperty( 'autoScroll' );
			expect( entry.attributes ).toHaveProperty( 'useTabs' );
		} );
	} );

	describe( 'SaveV210', () => {
		it( 'renders correctly without transition but with autoScroll and useTabs in raw JSON context', () => {
			const { container } = render( <SaveV210 attributes={ mockAttributes } /> );

Comment thread src/blocks/carousel/deprecated.tsx
Copilot AI review requested due to automatic review settings August 10, 2026 08:57

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 4 out of 4 changed files in this pull request and generated no new comments.

Suppressed comments (3)

src/blocks/carousel/types.ts:31

  • carouselId is typed as optional in CarouselAttributes, but block.json (and sharedAttributes in deprecations) define a default of \"\", which makes it effectively always present at runtime. To keep the public type aligned with the block schema, consider making carouselId non-optional (carouselId: string) or removing the default in the schema if undefined is a meaningful state.
	autoScrollStopOnInteraction: boolean;
	autoScrollStopOnMouseEnter: boolean;
	useTabs: boolean;
	carouselId?: string;
};

src/blocks/carousel/deprecated.tsx:288

  • carouselId is now part of the attributes schema (including deprecated schemas), but SaveV210 hard-codes context.carouselId to an empty string and does not read from attributes. If carouselId is intended to be a persisted attribute, set context.carouselId from attributes.carouselId (with an empty-string fallback). If it is strictly runtime-only, consider removing it from the block/deprecated attribute schemas to avoid a confusing attribute that is never honored by save output.
			}
			: false,
		useTabs,
		carouselId: '', // Set at runtime by initCarousel in view.ts
	};

src/blocks/carousel/deprecated.tsx:385

  • The new tests exercise SaveV210, but the refactor also changes the deprecated wiring for SaveV203 and SaveV200 (they now share the same attribute/support objects). Add targeted assertions for SaveV203 and SaveV200 saves as well (e.g., verifying data-wp-context serialization still matches expectations, including the ariaLabelPattern string behavior), so regressions in older deprecations are caught.
const deprecated = [
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV210,
	},
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV203,
	},
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV200,
	},

@milindmore22
milindmore22 requested review from Copilot and removed request for Copilot August 10, 2026 09:06
Copilot AI review requested due to automatic review settings August 11, 2026 07:26
@milindmore22
milindmore22 removed the request for review from Copilot August 11, 2026 07:29
Copilot AI review requested due to automatic review settings August 12, 2026 01:50
@justlevine justlevine changed the title Refactor carousel block deprecations and ariaLabelPattern fix: Ensure tabs are properly saved and backfill deprecations Aug 12, 2026

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 7 out of 7 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

src/blocks/carousel/deprecated.tsx:151

  • The PR description says the translation function was removed from ariaLabelPattern “in all save implementations”, but SaveV201 still wraps ariaLabelPattern with __(). To match the stated intent (and the shipped-markup tests’ approach), set ariaLabelPattern to the plain string value here (and any other deprecated saves where it’s still translated).
		/* translators: %d: slide number */
		ariaLabelPattern: __( 'Go to slide %d', 'rt-carousel' ),
		announcement: '',
		shouldAnnounce: false,
		/* translators: {{currentSlide}}: current slide number, {{totalSlides}}: total slide count. */
		announcementPattern: __(
			'Slide {{currentSlide}} of {{totalSlides}}',
			'rt-carousel',
		),

tests/php/stubs.php:122

  • In the stub, remove_attribute() directly indexes $this->elements[ $this->cursor ] without the defensive ?? null behavior you added via current_element(). If remove_attribute() is called when the cursor isn’t positioned on a valid element, this will trigger an undefined offset / property access error in tests. Prefer using current_element() (and returning false when it’s null) to keep stub behavior predictable and consistent with the new helper.
		public function remove_attribute( string $name ): bool {
			$element = $this->elements[ $this->cursor ];

			if ( ! $element->hasAttribute( $name ) ) {
				return false;
			}

			$element->removeAttribute( $name );

			return true;
		}

src/blocks/carousel/slide/tests/save.test.tsx:30

  • These tests assert exact innerHTML strings, which is brittle (attribute ordering/serialization can change across React/test-renderer updates without changing semantics). To make the tests more resilient while still protecting “no markup drift”, consider asserting via DOM queries/attribute checks (e.g., role, classes, and presence/absence of specific attributes) rather than full-string equality.
		expect( renderSave( {} ) ).toBe( SHIPPED_MARKUP );

src/blocks/carousel/slide/tests/save.test.tsx:39

  • These tests assert exact innerHTML strings, which is brittle (attribute ordering/serialization can change across React/test-renderer updates without changing semantics). To make the tests more resilient while still protecting “no markup drift”, consider asserting via DOM queries/attribute checks (e.g., role, classes, and presence/absence of specific attributes) rather than full-string equality.
		expect( renderSave( { verticalAlignment: 'center' } ) ).toBe(
			SHIPPED_MARKUP.replace(
				'class="embla__slide"',
				'class="embla__slide is-vertically-aligned-center"',
			),
		);

Comment thread inc/Plugin.php
Comment on lines +415 to +419
$processor = \WP_HTML_Processor::create_fragment( $block_content );

if ( null === $processor ) {
return $block_content;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the minimum WP version is 6.6, it's the preexisting conditional checks that are AI slop

Copilot AI review requested due to automatic review settings August 12, 2026 20:45

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 17 out of 17 changed files in this pull request and generated 1 comment.

Suppressed comments (4)

src/blocks/carousel/deprecated.tsx:144

  • These deprecated save implementations embed translated strings into the saved HTML context (data-wp-context). That makes the output locale-dependent and can cause block invalidation / mismatches across locales, and it also conflicts with the PR description stating the translation function was removed from ariaLabelPattern in save implementations. Use plain, non-translated strings for ariaLabelPattern (and consider doing the same for the other context patterns if the goal is deterministic saved markup), and remove the associated translators: comments if translation is no longer used here.
		/* translators: %d: slide number */
		ariaLabelPattern: __( 'Go to slide %d', 'rt-carousel' ),

src/blocks/carousel/deprecated.tsx:151

  • These deprecated save implementations embed translated strings into the saved HTML context (data-wp-context). That makes the output locale-dependent and can cause block invalidation / mismatches across locales, and it also conflicts with the PR description stating the translation function was removed from ariaLabelPattern in save implementations. Use plain, non-translated strings for ariaLabelPattern (and consider doing the same for the other context patterns if the goal is deterministic saved markup), and remove the associated translators: comments if translation is no longer used here.
		announcementPattern: __(
			'Slide {{currentSlide}} of {{totalSlides}}',
			'rt-carousel',
		),

tests/php/stubs.php:122

  • In the stub, remove_attribute() directly indexes $this->elements[ $this->cursor ] without a bounds check. If the cursor is not positioned on an element (or test code calls remove_attribute() at the wrong time), this can raise an undefined index / fatal in PHP tests. Align the stub with safer behavior by using the new current_element() helper (or a null coalescing guard) and returning false when there is no current element.
		public function remove_attribute( string $name ): bool {
			$element = $this->elements[ $this->cursor ];

			if ( ! $element->hasAttribute( $name ) ) {
				return false;
			}

			$element->removeAttribute( $name );

			return true;
		}

src/blocks/carousel/deprecated.tsx:363

  • The PR description mentions adding a SaveV210 deprecation entry (v2.1.0) and exporting SaveV200, SaveV203, and SaveV210, but in this diff hunk the deprecated list only includes SaveV203, SaveV201, and SaveV200 and shows no SaveV210. Either add the v2.1.0 entry here (if it’s intended) or update the PR description to match what’s actually being changed.
const deprecated = [
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV203,
	},
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV201,
	},
	{
		attributes: sharedAttributes,
		supports: sharedSupports,
		save: SaveV200,
	},
];

Comment thread src/blocks/carousel/carousel-tab-list/block.json
Copilot AI review requested due to automatic review settings August 13, 2026 00:54

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 25 out of 25 changed files in this pull request and generated no new comments.

Suppressed comments (5)

tests/php/stubs.php:122

  • remove_attribute() reads $this->elements[ $this->cursor ] without guarding for an unset/invalid cursor, which can emit PHP notices in tests (and differs from real WP_HTML_Tag_Processor behavior, which should fail gracefully when not parked on a tag). Consider using current_element() and returning false when it is null.
		public function remove_attribute( string $name ): bool {
			$element = $this->elements[ $this->cursor ];

			if ( ! $element->hasAttribute( $name ) ) {
				return false;
			}

			$element->removeAttribute( $name );

			return true;
		}

inc/Plugin.php:341

  • handle_block_markup() can result in two full HTML-processor passes in tabs mode (one in mark_query_loop_slides(), then another in mark_tab_panels()). Since these run on every render of the carousel block, this adds avoidable CPU cost for large carousels/pages. A concrete improvement would be to refactor so a single WP_HTML_Processor walk performs both transformations (or so mark_query_loop_slides() can accept/reuse an existing processor).
	public function handle_block_markup( string $block_content, array $parsed_block ): string {
		// Handle before marking tab panels so that Query Loop slides get the active-slide directives first.
		$block_content = $this->mark_query_loop_slides( $block_content );

		return $this->mark_tab_panels( $block_content, $parsed_block );
	}

src/blocks/carousel/deprecated.tsx:144

  • PR description says the translation function was removed from ariaLabelPattern in all save implementations (including deprecated ones), but the new SaveV201 still uses __() for ariaLabelPattern/announcementPattern. If the intent is not to change deprecated output (often necessary to match historically localized saved markup), the description should be updated to clarify that only current saves were de-i18n’d while deprecations retain __() for compatibility; otherwise, update deprecated saves too (with the risk that non-English historical content may stop matching deprecations).
		/* translators: %d: slide number */
		ariaLabelPattern: __( 'Go to slide %d', 'rt-carousel' ),

src/blocks/carousel/deprecated.tsx:151

  • PR description says the translation function was removed from ariaLabelPattern in all save implementations (including deprecated ones), but the new SaveV201 still uses __() for ariaLabelPattern/announcementPattern. If the intent is not to change deprecated output (often necessary to match historically localized saved markup), the description should be updated to clarify that only current saves were de-i18n’d while deprecations retain __() for compatibility; otherwise, update deprecated saves too (with the risk that non-English historical content may stop matching deprecations).
		announcementPattern: __(
			'Slide {{currentSlide}} of {{totalSlides}}',
			'rt-carousel',
		),

examples/patterns/logo-showcase.php:22

  • This pattern change introduces \"autoplay\":true (previously omitted), which is a functional behavior change for the example, but it isn’t mentioned in the PR description. If the intent of the PR is strictly “tabs saved properly / deprecations backfill,” consider reverting this autoplay change or explicitly calling it out (and ensuring it aligns with desired default behavior for the Logo Showcase pattern).
<!-- wp:rt-carousel/carousel {"loop":true,"autoplay":true,"autoplayDelay":3000,"autoplayStopOnInteraction":false,"ariaLabel":"Partner Logos","metadata":{"categories":["rt-carousel"],"patternName":"rt-carousel/logo-showcase","name":"rtCarousel: Logo Showcase"},"className":"is-style-columns-3"} -->

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants