From 9abebabb862156f2bb2bb83c72451d36fd7a4d93 Mon Sep 17 00:00:00 2001 From: Masud Rana Date: Wed, 11 Feb 2026 18:19:17 +0600 Subject: [PATCH 01/13] docs: Update README with requirements, browser support, and FAQs --- README.md | 91 +++++++++++++++++++++++++++++++++++++++++++++++ core-carousel.php | 2 +- 2 files changed, 92 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 6109183..d0d1029 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,29 @@ Easily create dynamic, accessible, and customizable carousels for any content ty - **Accessibility**: W3C-compliant roles, labels, and keyboard navigation. - **RTL Support**: Built-in support for Right-to-Left languages. +## Requirements + +| Requirement | Minimum | Recommended | +|-------------|---------|-------------| +| WordPress | 6.5+ | 6.6+ | +| PHP | 7.4+ | 8.2+ | +| Gutenberg | Not required | — | + +> **Note:** The Interactivity API became stable in WordPress 6.5. This plugin works with WordPress core—no Gutenberg plugin required. + +## Browser Support + +Core Carousel supports all modern browsers: + +| Browser | Minimum Version | +|---------|-----------------| +| Chrome | 80+ | +| Firefox | 74+ | +| Safari | 14+ | +| Edge | 80+ | + +> **Note:** Internet Explorer is not supported. The plugin requires ES2020+ features (optional chaining, nullish coalescing) and CSS custom properties. + ## Documentation - **[Installation](docs/INSTALLATION.md)**: How to install via ZIP or Composer. @@ -35,6 +58,74 @@ The plugin provides a suite of blocks that work together: 4. **Carousel Controls**: Previous/Next buttons. 5. **Carousel Dots**: Pagination indicators. +## Screenshots + +### Editor View +![Editor View](https://github.com/user-attachments/assets/3117b2d6-33be-49ea-8dee-c4ca3a637ec8) +*Adding and configuring carousel blocks in the WordPress editor.* + +### Frontend View +![Frontend View](https://github.com/user-attachments/assets/32f719e5-5f20-4243-8967-4eef880519ae) +*The carousel in action on the frontend.* + +### Settings Panel +![Settings Panel](https://github.com/user-attachments/assets/e0510e0b-44ba-4c56-ab15-d0ce9bd47322) +*Carousel configuration options in the block sidebar.* + +## FAQ + +### Does it work with Full Site Editing (FSE)? + +Yes! Core Carousel is fully compatible with Full Site Editing. You can use the carousel block in templates, template parts, and anywhere blocks are supported. + +### Can I nest other blocks inside slides? + +Absolutely. Each slide is a container that accepts any WordPress block—images, paragraphs, groups, columns, and even other third-party blocks. + +### Does it support the Query Loop block? + +Yes. Simply add a Query Loop block inside the Carousel Viewport, and each post in the loop becomes a slide automatically. No special configuration needed. + +### Is it accessible? + +Yes. The carousel follows W3C accessibility guidelines with proper ARIA roles, labels, and full keyboard navigation support. + +### Can I have multiple carousels on the same page? + +Yes. Each carousel instance maintains its own independent state. + +## Changelog + +### 1.0.0 (2026-02-03) + +**Features:** +- Initial release with compound block architecture +- Embla Carousel integration with Interactivity API +- Query Loop support for dynamic content +- Autoplay with configurable delay and interaction controls +- Vertical and horizontal axis support +- Slides to scroll option +- Example patterns: Hero, Logo Showcase, Testimonials + +**Bug Fixes:** +- Fixed gap issue for carousel items + +See [CHANGELOG.md](CHANGELOG.md) for full release history. + +## Roadmap + +Planned features for upcoming releases: + +- [ ] **Parallax transition effect** — Parallax animation effect +- [ ] **Thumbnail navigation** — Visual slide previews for navigation +- [ ] **Lazy loading** — Defer off-screen slide content loading +- [ ] **Loop/infinite scroll** — Seamless continuous scrolling +- [ ] **Progress bar indicator** — Visual autoplay progress +- [ ] **Breakpoint-specific settings** — Different slides per view at different screen sizes +- [ ] **Additional patterns** — More pre-built carousel patterns + +Have a feature request? [Open an issue](https://github.com/rtCamp/core-carousel/issues) on GitHub. + ## Live Demo [**🚀 Try the Interactive Demo in WordPress Playground**](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/rtCamp/core-carousel/main/blueprint.json) diff --git a/core-carousel.php b/core-carousel.php index 06db0a4..70e2db1 100644 --- a/core-carousel.php +++ b/core-carousel.php @@ -3,7 +3,7 @@ * Plugin Name: Core Carousel * Description: Carousel block using Embla and WordPress Interactivity API. * Plugin URI: https://github.com/rtCamp/core-carousel - * Requires at least: 6.1 + * Requires at least: 6.5 * Requires PHP: 7.4 * Author: rtCamp * Author URI: https://rtcamp.com From 1208152b3423eb1b724076bef3fc05e4684a6951 Mon Sep 17 00:00:00 2001 From: Masud Rana Date: Wed, 11 Feb 2026 18:24:32 +0600 Subject: [PATCH 02/13] docs: Update contributor link for Masud Rana and add spacing in README --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index d0d1029..1d9a60a 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,7 @@ The plugin provides a suite of blocks that work together: ### Settings Panel ![Settings Panel](https://github.com/user-attachments/assets/e0510e0b-44ba-4c56-ab15-d0ce9bd47322) + *Carousel configuration options in the block sidebar.* ## FAQ @@ -133,7 +134,7 @@ Have a feature request? [Open an issue](https://github.com/rtCamp/core-carousel/ ## Contributors - [Danish Shakeel](https://github.com/danish17) -- [Masud Rana](https://github.com/mr-masudrana00) +- [Masud Rana](https://github.com/theMasudRana) ## License GPL-2.0-or-later From 424c29cd9b7739591cf16f0a283e1c025ae49080 Mon Sep 17 00:00:00 2001 From: Danish Shakeel Date: Thu, 12 Feb 2026 03:11:02 +0100 Subject: [PATCH 03/13] feat: remove dist branch creation on release --- .github/workflows/release.yml | 43 ++++++++++++++++------------------- 1 file changed, 19 insertions(+), 24 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9a7561..d906c07 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -34,27 +34,22 @@ jobs: - name: Build Plugin ZIP run: make zip - - name: Create Release and Upload Asset - uses: softprops/action-gh-release@v1 - with: - tag_name: v${{ steps.get_version.outputs.VERSION }} - name: v${{ steps.get_version.outputs.VERSION }} - generate_release_notes: true - files: core-carousel.zip - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - - name: Prepare Distribution Bundle - run: | - mkdir dist-bundle - cp core-carousel.zip dist-bundle/ - - - name: Deploy to Dist Branch - uses: s0/git-publish-subdir-action@develop - env: - REPO: self - BRANCH: dist - FOLDER: dist-bundle - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - MESSAGE: "chore: distribution build v${{ steps.get_version.outputs.VERSION }}" - SKIP_EMPTY_COMMITS: true \ No newline at end of file + - name: Create Release and Upload Asset + + uses: softprops/action-gh-release@v1 + + with: + + tag_name: v${{ steps.get_version.outputs.VERSION }} + + name: v${{ steps.get_version.outputs.VERSION }} + + generate_release_notes: true + + files: core-carousel.zip + + env: + + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + \ No newline at end of file From 38fe6716c07829ed9683eaccba83e077806cacdf Mon Sep 17 00:00:00 2001 From: Danish Shakeel Date: Thu, 12 Feb 2026 03:12:00 +0100 Subject: [PATCH 04/13] fix: change plugin url to github releases --- blueprint.json | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/blueprint.json b/blueprint.json index cb95e0e..f43cad8 100644 --- a/blueprint.json +++ b/blueprint.json @@ -10,13 +10,12 @@ "step": "installPlugin", "pluginData": { "resource": "url", - "url": "https://cdn.statically.io/gh/rtCamp/core-carousel@dist/core-carousel.zip" + "url": "https://github.com/rtCamp/core-carousel/releases/latest/download/core-carousel.zip" } }, { "step": "login", - "username": "admin", - "password": "password" + "username": "admin" }, { "step": "importWxr", From 01a8002a15eda89c5da8902d37f2e1510217b382 Mon Sep 17 00:00:00 2001 From: Danish Shakeel Date: Thu, 12 Feb 2026 03:24:53 +0100 Subject: [PATCH 05/13] chore: update packages --- package-lock.json | 12 ++++++------ package.json | 4 ++-- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4313f8..d43f770 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,7 +27,7 @@ "devDependencies": { "@commitlint/cli": "20.4.1", "@commitlint/config-conventional": "20.4.1", - "@testing-library/jest-dom": "^6.6.3", + "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "^16.1.0", "@types/jest": "^29.5.14", "@types/react": "^18.3.27", @@ -11139,14 +11139,14 @@ } }, "node_modules/axios": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.2.tgz", - "integrity": "sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==", + "version": "1.13.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", + "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.4", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, diff --git a/package.json b/package.json index d933fc4..b4761d2 100644 --- a/package.json +++ b/package.json @@ -45,7 +45,7 @@ "devDependencies": { "@commitlint/cli": "20.4.1", "@commitlint/config-conventional": "20.4.1", - "@testing-library/jest-dom": "^6.6.3", + "@testing-library/jest-dom": "6.9.1", "@testing-library/react": "^16.1.0", "@types/jest": "^29.5.14", "@types/react": "^18.3.27", @@ -63,4 +63,4 @@ "react-dom": "^18.3.1", "webpack-dev-server": ">=5.2.1" } -} \ No newline at end of file +} From 6ab9931a924bb170adcd6381d8c1ba7a9d828aec Mon Sep 17 00:00:00 2001 From: Danish Shakeel Date: Thu, 12 Feb 2026 03:35:19 +0100 Subject: [PATCH 06/13] feat: add tests tsconfig --- .eslintrc.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.eslintrc.json b/.eslintrc.json index 8c5701a..7dc6ff5 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -36,7 +36,7 @@ "parserOptions": { "ecmaFeatures": { "jsx": true }, "sourceType": "module", - "project": "./tsconfig.json" + "project": ["./tsconfig.json", "./tests/js/tsconfig.json"] }, "plugins": ["@typescript-eslint"], "rules": { From f2abd09245b8be2dca7c5fc783b881d70d3b392d Mon Sep 17 00:00:00 2001 From: Danish Shakeel Date: Thu, 12 Feb 2026 03:35:38 +0100 Subject: [PATCH 07/13] fix: doc params --- src/blocks/carousel/__tests__/view.test.ts | 91 ++++++++++------------ 1 file changed, 42 insertions(+), 49 deletions(-) diff --git a/src/blocks/carousel/__tests__/view.test.ts b/src/blocks/carousel/__tests__/view.test.ts index ee8c22a..9640019 100644 --- a/src/blocks/carousel/__tests__/view.test.ts +++ b/src/blocks/carousel/__tests__/view.test.ts @@ -12,11 +12,7 @@ * @package */ -import { - store, - getContext, - getElement, -} from '@wordpress/interactivity'; +import { store, getContext, getElement } from '@wordpress/interactivity'; import EmblaCarousel, { type EmblaCarouselType } from 'embla-carousel'; @@ -25,7 +21,7 @@ const EMBLA_KEY = Symbol.for( 'core-carousel.carousel' ); // Type for viewport element with Embla instance attached type EmblaViewportElement = HTMLElement & { - [ EMBLA_KEY ]?: EmblaCarouselType; + [EMBLA_KEY]?: EmblaCarouselType; }; import type { CarouselContext } from '../types'; @@ -41,23 +37,25 @@ const storeConfig = storeCall ? storeCall[ 1 ] : null; /** * Helper to set Embla instance on a viewport element. - * @param viewport The viewport element to attach the Embla instance to. - * @param embla The Embla instance to attach. + * + * @param {HTMLElement} viewport The viewport element to attach the Embla instance to. + * @param {Partial} embla The Embla instance to attach. */ const setEmblaOnViewport = ( viewport: HTMLElement, - embla: Partial< EmblaCarouselType >, + embla: Partial, ) => { - ( viewport as EmblaViewportElement )[ EMBLA_KEY ] = - embla as EmblaCarouselType; + ( viewport as EmblaViewportElement )[ EMBLA_KEY ] = embla as EmblaCarouselType; }; /** * Helper to create mock carousel context with customizable properties. - * @param overrides Partial properties to override in the default context. + * + * @param {Partial} overrides Partial properties to override in the default context. + * @return {CarouselContext} The mock carousel context. */ const createMockContext = ( - overrides: Partial< CarouselContext > = {}, + overrides: Partial = {}, ): CarouselContext => ( { options: { loop: true }, autoplay: false, @@ -73,6 +71,8 @@ const createMockContext = ( /** * Helper to create a mock DOM element structure for carousel. + * + * @return {Object} The mock DOM elements. */ const createMockCarouselDOM = () => { const viewport = document.createElement( 'div' ); @@ -90,7 +90,9 @@ const createMockCarouselDOM = () => { /** * Helper to create mock Embla instance with all required methods. - * @param overrides Partial methods to override in the default mock instance. + * + * @param {Object} overrides Partial methods to override in the default mock instance. + * @return {Object} The mock Embla instance. */ const createMockEmblaInstance = ( overrides = {} ) => ( { scrollPrev: jest.fn(), @@ -227,9 +229,7 @@ describe( 'Carousel View Module', () => { } ); it( 'should log warning when embla instance not found', () => { - const consoleSpy = jest - .spyOn( console, 'warn' ) - .mockImplementation(); + const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation(); const button = document.createElement( 'button' ); ( getElement as jest.Mock ).mockReturnValue( { ref: button } ); @@ -244,9 +244,7 @@ describe( 'Carousel View Module', () => { } ); it( 'should handle null element gracefully', () => { - const consoleSpy = jest - .spyOn( console, 'warn' ) - .mockImplementation(); + const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation(); ( getElement as jest.Mock ).mockReturnValue( null ); expect( () => storeConfig.actions.scrollPrev() ).not.toThrow(); @@ -279,9 +277,7 @@ describe( 'Carousel View Module', () => { } ); it( 'should log warning when embla instance not found', () => { - const consoleSpy = jest - .spyOn( console, 'warn' ) - .mockImplementation(); + const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation(); const button = document.createElement( 'button' ); ( getElement as jest.Mock ).mockReturnValue( { ref: button } ); @@ -309,8 +305,9 @@ describe( 'Carousel View Module', () => { setEmblaOnViewport( viewport, mockEmbla ); const mockContext = createMockContext(); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 2 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 2, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); ( getElement as jest.Mock ).mockReturnValue( { ref: button } ); @@ -338,8 +335,9 @@ describe( 'Carousel View Module', () => { setEmblaOnViewport( viewport, mockEmbla ); const mockContext = createMockContext(); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 0 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 0, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); ( getElement as jest.Mock ).mockReturnValue( { ref: button } ); @@ -362,9 +360,7 @@ describe( 'Carousel View Module', () => { describe( 'isSlideActive', () => { it( 'should be defined as a function', () => { expect( storeConfig?.callbacks?.isSlideActive ).toBeDefined(); - expect( typeof storeConfig?.callbacks?.isSlideActive ).toBe( - 'function', - ); + expect( typeof storeConfig?.callbacks?.isSlideActive ).toBe( 'function' ); } ); it( 'should return false when element is null', () => { @@ -446,8 +442,9 @@ describe( 'Carousel View Module', () => { it( 'should return true when snap.index matches selectedIndex', () => { const mockContext = createMockContext( { selectedIndex: 2 } ); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 2 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 2, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); @@ -458,8 +455,9 @@ describe( 'Carousel View Module', () => { it( 'should return false when snap.index does not match selectedIndex', () => { const mockContext = createMockContext( { selectedIndex: 0 } ); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 2 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 2, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); @@ -479,8 +477,9 @@ describe( 'Carousel View Module', () => { const mockContext = createMockContext( { ariaLabelPattern: 'Go to slide %d', } ); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 2 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 2, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); @@ -493,8 +492,9 @@ describe( 'Carousel View Module', () => { const mockContext = createMockContext( { ariaLabelPattern: 'Slide %d of 5', } ); - ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = - { index: 0 }; + ( mockContext as CarouselContext & { snap?: { index: number } } ).snap = { + index: 0, + }; ( getContext as jest.Mock ).mockReturnValue( mockContext ); @@ -519,15 +519,11 @@ describe( 'Carousel View Module', () => { describe( 'initCarousel', () => { it( 'should be defined as a function', () => { expect( storeConfig?.callbacks?.initCarousel ).toBeDefined(); - expect( typeof storeConfig?.callbacks?.initCarousel ).toBe( - 'function', - ); + expect( typeof storeConfig?.callbacks?.initCarousel ).toBe( 'function' ); } ); it( 'should return early and log warning for invalid element', () => { - const consoleSpy = jest - .spyOn( console, 'warn' ) - .mockImplementation(); + const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation(); const mockContext = createMockContext(); ( getContext as jest.Mock ).mockReturnValue( mockContext ); @@ -545,9 +541,7 @@ describe( 'Carousel View Module', () => { } ); it( 'should log warning when viewport not found', () => { - const consoleSpy = jest - .spyOn( console, 'warn' ) - .mockImplementation(); + const consoleSpy = jest.spyOn( console, 'warn' ).mockImplementation(); const mockContext = createMockContext(); const element = document.createElement( 'div' ); @@ -596,8 +590,7 @@ describe( 'Carousel View Module', () => { describe( 'Embla Carousel Integration', () => { // Type-safe helper to get mocked Embla instance - const getMockedEmblaCarousel = () => - EmblaCarousel as unknown as jest.Mock; + const getMockedEmblaCarousel = () => EmblaCarousel as unknown as jest.Mock; it( 'should have EmblaCarousel mocked', () => { expect( EmblaCarousel ).toBeDefined(); From 438c969d8e9c2ef20b2b7043f4215bd73cd5e381 Mon Sep 17 00:00:00 2001 From: Masud Rana Date: Fri, 13 Feb 2026 02:51:44 +0600 Subject: [PATCH 08/13] Refactor Core Carousel to Carousel Kit - Updated block.json files to change names and categories from "core-carousel" to "carousel-kit". - Modified edit.tsx, save.tsx, and style.scss files to reflect new class names and attributes. - Adjusted editor-context.ts and editor.scss for context and styling changes. - Updated index.ts and view.ts to register and manage the new block structure. - Refactored tests to align with the new "carousel-kit" namespace and structure. - Ensured all references to "core-carousel" are replaced with "carousel-kit" across the codebase. --- .github/workflows/release.yml | 4 +- .gitignore | 2 +- DEVELOPMENT.md | 2 +- Makefile | 2 +- README.md | 14 +- blueprint.json | 8 +- carousel-kit.php | 33 +++++ composer.json | 6 +- core-carousel.php | 33 ----- docs/API.md | 12 +- docs/CONTRIBUTING.md | 4 +- docs/INSTALLATION.md | 4 +- docs/THEMING.md | 46 +++---- docs/USAGE.md | 18 +-- examples/data/core-carousel.xml | 130 +++++++++--------- examples/patterns/hero-carousel.php | 48 +++---- examples/patterns/logo-showcase.php | 56 ++++---- examples/patterns/query-loop.php | 30 ++-- examples/patterns/testimonial-carousel.php | 50 +++---- inc/Plugin.php | 28 ++-- inc/Traits/Singleton.php | 8 +- jest.config.js | 4 +- package-lock.json | 4 +- package.json | 2 +- phpcs.xml.dist | 6 +- phpstan.neon.dist | 2 +- phpunit.xml.dist | 2 +- src/blocks/carousel/__tests__/view.test.ts | 8 +- src/blocks/carousel/block.json | 8 +- src/blocks/carousel/controls/block.json | 8 +- .../carousel/controls/components/icons.tsx | 4 +- src/blocks/carousel/controls/edit.tsx | 12 +- src/blocks/carousel/controls/save.tsx | 10 +- src/blocks/carousel/controls/style.scss | 34 ++--- src/blocks/carousel/dots/block.json | 8 +- src/blocks/carousel/dots/edit.tsx | 10 +- src/blocks/carousel/dots/save.tsx | 4 +- src/blocks/carousel/dots/style.scss | 24 ++-- src/blocks/carousel/edit.tsx | 88 ++++++------ src/blocks/carousel/editor-context.ts | 4 +- src/blocks/carousel/editor.scss | 2 +- src/blocks/carousel/index.ts | 8 +- src/blocks/carousel/save.tsx | 10 +- src/blocks/carousel/slide/block.json | 10 +- src/blocks/carousel/slide/edit.tsx | 4 +- src/blocks/carousel/slide/save.tsx | 2 +- src/blocks/carousel/styles/_core.scss | 38 ++--- src/blocks/carousel/styles/_variants.scss | 18 +-- src/blocks/carousel/view.ts | 6 +- src/blocks/carousel/viewport/block.json | 8 +- src/blocks/carousel/viewport/edit.tsx | 12 +- src/types.d.ts | 2 +- tests/js/setup.ts | 2 +- tests/php/Unit/PluginTest.php | 42 +++--- tests/php/Unit/Traits/SingletonTest.php | 14 +- tests/php/Unit/UnitTestCase.php | 6 +- tests/php/bootstrap.php | 14 +- tests/phpstan/constants.php | 10 +- 58 files changed, 494 insertions(+), 494 deletions(-) create mode 100644 carousel-kit.php delete mode 100644 core-carousel.php diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c9a7561..3b01c35 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,14 +40,14 @@ jobs: tag_name: v${{ steps.get_version.outputs.VERSION }} name: v${{ steps.get_version.outputs.VERSION }} generate_release_notes: true - files: core-carousel.zip + files: carousel-kit.zip env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - name: Prepare Distribution Bundle run: | mkdir dist-bundle - cp core-carousel.zip dist-bundle/ + cp carousel-kit.zip dist-bundle/ - name: Deploy to Dist Branch uses: s0/git-publish-subdir-action@develop diff --git a/.gitignore b/.gitignore index f904867..5000c74 100644 --- a/.gitignore +++ b/.gitignore @@ -36,4 +36,4 @@ phpstan.neon # Build build/ tsconfig.tsbuildinfo -core-carousel.zip +carousel-kit.zip diff --git a/DEVELOPMENT.md b/DEVELOPMENT.md index 249c6e0..1188ff2 100644 --- a/DEVELOPMENT.md +++ b/DEVELOPMENT.md @@ -69,7 +69,7 @@ npm run test:actions ## Directory Structure - `src/` - Source code for blocks (React/TypeScript/SCSS). -- `inc/` - PHP classes and traits (PSR-4 `Core_Carousel`). +- `inc/` - PHP classes and traits (PSR-4 `Carousel_Kit`). - `build/` - Compiled assets (generated by `npm run build`). - `docs/` - Documentation files. - `examples/` - Block patterns and examples. diff --git a/Makefile b/Makefile index 630e85f..d34a365 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,5 @@ # Configuration -PLUGIN_SLUG := core-carousel +PLUGIN_SLUG := carousel-kit PLUGIN_VERSION := 1.0.0 BUILD_DIR := build-dist ZIP_NAME := $(PLUGIN_SLUG).zip diff --git a/README.md b/README.md index 1d9a60a..531d3a2 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ -# Core Carousel +# Carousel Kit -![Build Status](https://github.com/rtCamp/core-carousel/actions/workflows/release.yml/badge.svg?branch=main) -![Latest Release](https://img.shields.io/github/v/release/rtCamp/core-carousel) +![Build Status](https://github.com/rtCamp/carousel-kit/actions/workflows/release.yml/badge.svg?branch=main) +![Latest Release](https://img.shields.io/github/v/release/rtCamp/carousel-kit) **A modular, high-performance carousel block for WordPress, powered by the Interactivity API and Embla Carousel.** @@ -28,7 +28,7 @@ Easily create dynamic, accessible, and customizable carousels for any content ty ## Browser Support -Core Carousel supports all modern browsers: +Carousel Kit supports all modern browsers: | Browser | Minimum Version | |---------|-----------------| @@ -77,7 +77,7 @@ The plugin provides a suite of blocks that work together: ### Does it work with Full Site Editing (FSE)? -Yes! Core Carousel is fully compatible with Full Site Editing. You can use the carousel block in templates, template parts, and anywhere blocks are supported. +Yes! Carousel Kit is fully compatible with Full Site Editing. You can use the carousel block in templates, template parts, and anywhere blocks are supported. ### Can I nest other blocks inside slides? @@ -125,11 +125,11 @@ Planned features for upcoming releases: - [ ] **Breakpoint-specific settings** — Different slides per view at different screen sizes - [ ] **Additional patterns** — More pre-built carousel patterns -Have a feature request? [Open an issue](https://github.com/rtCamp/core-carousel/issues) on GitHub. +Have a feature request? [Open an issue](https://github.com/rtCamp/carousel-kit/issues) on GitHub. ## Live Demo -[**🚀 Try the Interactive Demo in WordPress Playground**](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/rtCamp/core-carousel/main/blueprint.json) +[**🚀 Try the Interactive Demo in WordPress Playground**](https://playground.wordpress.net/?blueprint-url=https://raw.githubusercontent.com/rtCamp/carousel-kit/main/blueprint.json) ## Contributors diff --git a/blueprint.json b/blueprint.json index cb95e0e..bca981d 100644 --- a/blueprint.json +++ b/blueprint.json @@ -4,13 +4,13 @@ "php": "8.2", "wp": "latest" }, - "landingPage": "/core-carousel", + "landingPage": "/carousel-kit", "steps": [ { "step": "installPlugin", "pluginData": { "resource": "url", - "url": "https://cdn.statically.io/gh/rtCamp/core-carousel@dist/core-carousel.zip" + "url": "https://cdn.statically.io/gh/rtCamp/carousel-kit@dist/carousel-kit.zip" } }, { @@ -22,12 +22,12 @@ "step": "importWxr", "file": { "resource": "url", - "url": "https://raw.githubusercontent.com/rtCamp/core-carousel/main/examples/data/core-carousel.xml" + "url": "https://raw.githubusercontent.com/rtCamp/carousel-kit/main/examples/data/carousel-kit.xml" } }, { "step": "runPHP", - "code": "'page', 'title'=>'Core Carousel Interactive Demo']); if($posts) { update_option('show_on_front', 'page'); update_option('page_on_front', $posts[0]->ID); }" + "code": "'page', 'title'=>'Carousel Kit Interactive Demo']); if($posts) { update_option('show_on_front', 'page'); update_option('page_on_front', $posts[0]->ID); }" } ] } \ No newline at end of file diff --git a/carousel-kit.php b/carousel-kit.php new file mode 100644 index 0000000..f00d170 --- /dev/null +++ b/carousel-kit.php @@ -0,0 +1,33 @@ + @@ -78,8 +78,8 @@ Highlight slide content when active using the `callbacks.isSlideActive` helper. ### Editor Interactivity: "Find & Bind" Gutenberg's `InnerBlocks` can isolate React Contexts, causing state sync issues between parent and deeply nested children in the editor. To guarantee reliable interactivity: -1. **Attach**: The Viewport component attaches the vanilla Embla instance directly to its DOM node using a Symbol key: `element[Symbol.for("core-carousel.carousel")] = embla`. -2. **Find**: Child components (Controls/Dots) attempt to find the API via Context first. If missing, they traverse the DOM up to the common wrapper (`.core-carousel`) and then search for the sibling `.embla` viewport. +1. **Attach**: The Viewport component attaches the vanilla Embla instance directly to its DOM node using a Symbol key: `element[Symbol.for("carousel-kit.carousel")] = embla`. +2. **Find**: Child components (Controls/Dots) attempt to find the API via Context first. If missing, they traverse the DOM up to the common wrapper (`.carousel-kit`) and then search for the sibling `.embla` viewport. 3. **Bind**: A retry mechanism (`setTimeout` + `useEffect`) ensures the Viewport has finished initializing before binding listeners. ### Dots Implementation diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 35840e5..e40a8c8 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -1,4 +1,4 @@ -# Contributing to Core Carousel +# Contributing to Carousel Kit Thank you for your interest in contributing! We welcome all contributions, from bug reports to feature requests and code changes. @@ -38,4 +38,4 @@ To create a production-ready ZIP file: make zip ``` -This will create `core-carousel.zip` in the project root, optimized for distribution (no dev dependencies). +This will create `carousel-kit.zip` in the project root, optimized for distribution (no dev dependencies). diff --git a/docs/INSTALLATION.md b/docs/INSTALLATION.md index 398b800..22519ee 100644 --- a/docs/INSTALLATION.md +++ b/docs/INSTALLATION.md @@ -5,7 +5,7 @@ - PHP 8.2 or higher ## Manual Installation -1. Download the `core-carousel.zip` file from the [Releases](https://github.com/rtCamp/carousel-system-interactivity-api/releases) page. +1. Download the `carousel-kit.zip` file from the [Releases](https://github.com/rtCamp/carousel-system-interactivity-api/releases) page. 2. Log in to your WordPress admin dashboard. 3. Go to **Plugins > Add New Plugin**. 4. Click **Upload Plugin**. @@ -16,5 +16,5 @@ If you are managing your WordPress project with Composer: ```bash -composer require rtcamp/core-carousel +composer require rtcamp/carousel-kit ``` diff --git a/docs/THEMING.md b/docs/THEMING.md index 3efcb17..c88498d 100644 --- a/docs/THEMING.md +++ b/docs/THEMING.md @@ -7,32 +7,32 @@ Easily theme the carousel using CSS variables or block supports. Navigation bloc ### Core Layout | Variable | Description | | :--- | :--- | -| `--core-carousel-gap` | Controlled by the `slideGap` attribute. Applied as margin to slides. | -| `--core-carousel-slide-width` | Controls the width of each slide. Defaults to 100% or set by column variants. | +| `--carousel-kit-gap` | Controlled by the `slideGap` attribute. Applied as margin to slides. | +| `--carousel-kit-slide-width` | Controls the width of each slide. Defaults to 100% or set by column variants. | ### Controls (Buttons) | Variable | Default | Description | | ----------------------------------------- | ------------------------------------- | --------------------------- | -| `--core-carousel-control-bg` | `unset` | Background color of buttons | -| `--core-carousel-control-color` | `inherit` | Icon color | -| `--core-carousel-control-size` | `2.5rem` | Width/Height of buttons | -| `--core-carousel-control-padding` | `0.5rem` | Padding inside buttons | -| `--core-carousel-control-border` | `1.25px solid rgba(28, 28, 28, 0.3)` | Border style | -| `--core-carousel-control-radius` | `1rem` | Border radius | -| `--core-carousel-control-bg-hover` | `rgba(248, 248, 248, 1)` | Background on hover | -| `--core-carousel-control-border-hover` | `1.25px solid rgba(28, 28, 28, 0.75)` | Border on hover | -| `--core-carousel-control-color-hover` | `inherit` | Icon color on hover | +| `--carousel-kit-control-bg` | `unset` | Background color of buttons | +| `--carousel-kit-control-color` | `inherit` | Icon color | +| `--carousel-kit-control-size` | `2.5rem` | Width/Height of buttons | +| `--carousel-kit-control-padding` | `0.5rem` | Padding inside buttons | +| `--carousel-kit-control-border` | `1.25px solid rgba(28, 28, 28, 0.3)` | Border style | +| `--carousel-kit-control-radius` | `1rem` | Border radius | +| `--carousel-kit-control-bg-hover` | `rgba(248, 248, 248, 1)` | Background on hover | +| `--carousel-kit-control-border-hover` | `1.25px solid rgba(28, 28, 28, 0.75)` | Border on hover | +| `--carousel-kit-control-color-hover` | `inherit` | Icon color on hover | ### Dots (Pagination) | Variable | Default | Description | | ------------------------------------- | --------------------- | ---------------------- | -| `--core-carousel-dots-gap` | `0.5rem` | Gap between dots | -| `--core-carousel-dot-size` | `0.5rem` | Size of inactive dots | -| `--core-carousel-dot-color` | `rgb(221, 221, 221)` | Color of inactive dots | -| `--core-carousel-dot-radius` | `50%` | Shape of the dots | -| `--core-carousel-dot-border` | `none` | Border style for dots | -| `--core-carousel-dot-active-size` | `0.75rem` | Size of active dot | -| `--core-carousel-dot-active-color` | `rgba(28, 28, 28, 1)` | Color of active dot | +| `--carousel-kit-dots-gap` | `0.5rem` | Gap between dots | +| `--carousel-kit-dot-size` | `0.5rem` | Size of inactive dots | +| `--carousel-kit-dot-color` | `rgb(221, 221, 221)` | Color of inactive dots | +| `--carousel-kit-dot-radius` | `50%` | Shape of the dots | +| `--carousel-kit-dot-border` | `none` | Border style for dots | +| `--carousel-kit-dot-active-size` | `0.75rem` | Size of active dot | +| `--carousel-kit-dot-active-color` | `rgba(28, 28, 28, 1)` | Color of active dot | ## Overriding Styles @@ -41,9 +41,9 @@ You can override these variables globally in your theme's stylesheet or via `the ### Global CSS (`style.css`) ```css :root { - --core-carousel-control-bg: #000000; - --core-carousel-dot-active-color: #ff0000; - --core-carousel-gap: 20px; + --carousel-kit-control-bg: #000000; + --carousel-kit-dot-active-color: #ff0000; + --carousel-kit-gap: 20px; } ``` @@ -52,8 +52,8 @@ You can override these variables globally in your theme's stylesheet or via `the { "styles": { "blocks": { - "core-carousel/carousel": { - "css": "--core-carousel-control-bg: #000000;" + "carousel-kit/carousel": { + "css": "--carousel-kit-control-bg: #000000;" } } } diff --git a/docs/USAGE.md b/docs/USAGE.md index c9f3eb3..8918d62 100644 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -2,7 +2,7 @@ ## Block Configuration -### Parent Block: `core-carousel/carousel` +### Parent Block: `carousel-kit/carousel` The parent block acts as the controller and wrapper. It handles configuration, state, and context for all child blocks. #### Attributes @@ -32,14 +32,14 @@ The parent block acts as the controller and wrapper. It handles configuration, s To create a specialized carousel (e.g., testimonials only), set the `allowedSlideBlocks` attribute on the parent block: ```json - + - - + + - - - + + + ``` --- @@ -62,5 +62,5 @@ You can create dynamic post sliders or content carousels using the WordPress Que | Use Case | Recommended Block | | :--- | :--- | | Dynamic Content (Posts, Pages, Products, Custom Post Types) | Query Loop (`core/query`) | -| Static Content (Hero Slider, Logo Showcase, Manual Testimonials) | Carousel Slide (`core-carousel/carousel-slide`) | -| Mixed Content (Slide 1 is a Video, Slide 2 is Text) | Carousel Slide (`core-carousel/carousel-slide`) | +| Static Content (Hero Slider, Logo Showcase, Manual Testimonials) | Carousel Slide (`carousel-kit/carousel-slide`) | +| Mixed Content (Slide 1 is a Video, Slide 2 is Text) | Carousel Slide (`carousel-kit/carousel-slide`) | diff --git a/examples/data/core-carousel.xml b/examples/data/core-carousel.xml index cc31a4e..81e2590 100644 --- a/examples/data/core-carousel.xml +++ b/examples/data/core-carousel.xml @@ -26,7 +26,7 @@ > - Core Carousel + Carousel Kit https://carousel.local Mon, 09 Feb 2026 13:02:36 +0000 @@ -282,16 +282,16 @@ Commenter avatars come from Gravatar.]]>0 - <![CDATA[Core Carousel]]> + <![CDATA[Carousel Kit]]> https://carousel.local/ Mon, 09 Feb 2026 13:01:18 +0000 https://carousel.local/?page_id=6 - -