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": {
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c9a7561..b8f535a 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: carousel-kit.zip
+
+ env:
+
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+
\ No newline at end of file
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/CHANGELOG.md b/CHANGELOG.md
index 3efab97..72d6279 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,10 @@
+# [1.0.1](https://github.com/rtCamp/carousel-system-interactivity-api/compare/1.0.0...1.0.1) (2026-02-16)
+
+### Bug Fixes
+
+* **carousel:** resolve spacing issues in loop mode where gaps were missing between last and first slide
+* **carousel:** allow infinite loop in editor viewport to match frontend behavior
+
# 1.0.0 (2026-02-03)
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 6109183..531d3a2 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
-# Core Carousel
+# Carousel Kit
-
-
+
+
**A modular, high-performance carousel block for WordPress, powered by the Interactivity API and Embla Carousel.**
@@ -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
+
+Carousel Kit 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,14 +58,83 @@ The plugin provides a suite of blocks that work together:
4. **Carousel Controls**: Previous/Next buttons.
5. **Carousel Dots**: Pagination indicators.
+## Screenshots
+
+### Editor View
+
+*Adding and configuring carousel blocks in the WordPress editor.*
+
+### Frontend View
+
+*The carousel in action on the frontend.*
+
+### Settings Panel
+
+
+*Carousel configuration options in the block sidebar.*
+
+## FAQ
+
+### Does it work with Full Site Editing (FSE)?
+
+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?
+
+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/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
- [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
diff --git a/blueprint.json b/blueprint.json
index cb95e0e..1a3b44d 100644
--- a/blueprint.json
+++ b/blueprint.json
@@ -4,30 +4,29 @@
"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://github.com/rtCamp/carousel-kit/releases/latest/download/carousel-kit.zip"
}
},
{
"step": "login",
- "username": "admin",
- "password": "password"
+ "username": "admin"
},
{
"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/carousel-kit.xml b/examples/data/carousel-kit.xml
new file mode 100644
index 0000000..06a26d9
--- /dev/null
+++ b/examples/data/carousel-kit.xml
@@ -0,0 +1,1814 @@
+
+
+
+
+
+Carousel Kit by rtCamp
+ http://carousel-demo.local
+Carousel system built for WordPress using Interactivity API
+Mon, 16 Feb 2026 10:43:07 +0000
+en-US
+1.2
+http://carousel-demo.local
+http://carousel-demo.local
+
+ 1
+ danish
+ danish@local.com
+
+
+
+
+
+ 1
+ uncategorized
+
+
+
+
+ 4
+ wp_template_part_area
+ footer
+
+
+
+
+ 3
+ wp_template_part_area
+ header
+
+
+
+
+ 2
+ wp_theme
+ twentytwentyfive
+
+
+
+
+ 1
+ category
+ uncategorized
+
+
+
+https://wordpress.org/?v=6.9.1
+-
+
+ http://carousel-demo.local/hello-world/
+ Thu, 12 Feb 2026 02:37:17 +0000
+ danish
+ http://carousel-demo.local/?p=1
+
+
+Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
+]]>
+
+ 1
+ 2026-02-12 02:37:17
+ 2026-02-12 02:37:17
+ 2026-02-12 02:37:17
+ 2026-02-12 02:37:17
+ open
+ open
+ hello-world
+ publish
+ 0
+ 0
+ post
+
+ 0
+
+
+-
+
+ http://carousel-demo.local/?page_id=2
+ Thu, 12 Feb 2026 02:37:17 +0000
+ danish
+ http://carousel-demo.local/?page_id=2
+
+
+This is an example page. It's different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:
+
+
+
+
+
+Hi there! I'm a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin' caught in the rain.)
+
+
+
+
+
+...or something like this:
+
+
+
+
+
+The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.
+
+
+
+
+
+As a new WordPress user, you should go to your dashboard to delete this page and create new pages for your content. Have fun!
+]]>
+
+ 2
+ 2026-02-12 02:37:17
+ 2026-02-12 02:37:17
+ 2026-02-12 02:40:03
+ 2026-02-12 02:40:03
+ closed
+ open
+ sample-page__trashed
+ trash
+ 0
+ 0
+ page
+
+ 0
+
+ _wp_page_template
+
+
+
+ _wp_trash_meta_status
+
+
+
+ _wp_trash_meta_time
+
+
+
+ _wp_desired_post_slug
+
+
+
+-
+
+ http://carousel-demo.local/?page_id=3
+ Thu, 12 Feb 2026 02:37:17 +0000
+ danish
+ http://carousel-demo.local/?page_id=3
+
+
+Who we are
+
+
+Suggested text: Our website address is: http://carousel-demo.local.
+
+
+Comments
+
+
+Suggested text: When visitors leave comments on the site we collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
+
+
+An anonymized string created from your email address (also called a hash) may be provided to the Gravatar service to see if you are using it. The Gravatar service privacy policy is available here: https://automattic.com/privacy/. After approval of your comment, your profile picture is visible to the public in the context of your comment.
+
+
+Media
+
+
+Suggested text: If you upload images to the website, you should avoid uploading images with embedded location data (EXIF GPS) included. Visitors to the website can download and extract any location data from images on the website.
+
+
+Cookies
+
+
+Suggested text: If you leave a comment on our site you may opt-in to saving your name, email address and website in cookies. These are for your convenience so that you do not have to fill in your details again when you leave another comment. These cookies will last for one year.
+
+
+If you visit our login page, we will set a temporary cookie to determine if your browser accepts cookies. This cookie contains no personal data and is discarded when you close your browser.
+
+
+When you log in, we will also set up several cookies to save your login information and your screen display choices. Login cookies last for two days, and screen options cookies last for a year. If you select "Remember Me", your login will persist for two weeks. If you log out of your account, the login cookies will be removed.
+
+
+If you edit or publish an article, an additional cookie will be saved in your browser. This cookie includes no personal data and simply indicates the post ID of the article you just edited. It expires after 1 day.
+
+
+Embedded content from other websites
+
+
+Suggested text: Articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website.
+
+
+These websites may collect data about you, use cookies, embed additional third-party tracking, and monitor your interaction with that embedded content, including tracking your interaction with the embedded content if you have an account and are logged in to that website.
+
+
+Who we share your data with
+
+
+Suggested text: If you request a password reset, your IP address will be included in the reset email.
+
+
+How long we retain your data
+
+
+Suggested text: If you leave a comment, the comment and its metadata are retained indefinitely. This is so we can recognize and approve any follow-up comments automatically instead of holding them in a moderation queue.
+
+
+For users that register on our website (if any), we also store the personal information they provide in their user profile. All users can see, edit, or delete their personal information at any time (except they cannot change their username). Website administrators can also see and edit that information.
+
+
+What rights you have over your data
+
+
+Suggested text: If you have an account on this site, or have left comments, you can request to receive an exported file of the personal data we hold about you, including any data you have provided to us. You can also request that we erase any personal data we hold about you. This does not include any data we are obliged to keep for administrative, legal, or security purposes.
+
+
+Where your data is sent
+
+
+Suggested text: Visitor comments may be checked through an automated spam detection service.
+
+]]>
+
+ 3
+ 2026-02-12 02:37:17
+ 2026-02-12 02:37:17
+ 2026-02-12 02:40:05
+ 2026-02-12 02:40:05
+ closed
+ open
+ privacy-policy__trashed
+ trash
+ 0
+ 0
+ page
+
+ 0
+
+ _wp_page_template
+
+
+
+ _wp_trash_meta_status
+
+
+
+ _wp_trash_meta_time
+
+
+
+ _wp_desired_post_slug
+
+
+
+-
+
+ http://carousel-demo.local/navigation/
+ Thu, 12 Feb 2026 02:37:42 +0000
+
+ http://carousel-demo.local/navigation/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 4
+ 2026-02-12 02:37:42
+ 2026-02-12 02:37:42
+ 2026-02-16 09:23:50
+ 2026-02-16 09:23:50
+ closed
+ closed
+ navigation
+ publish
+ 0
+ 0
+ wp_navigation
+
+ 0
+
+-
+
+ http://carousel-demo.local/wp-global-styles-twentytwentyfive/
+ Thu, 12 Feb 2026 02:38:11 +0000
+ danish
+ http://carousel-demo.local/wp-global-styles-twentytwentyfive/
+
+
+
+ 6
+ 2026-02-12 02:38:11
+ 2026-02-12 02:38:11
+ 2026-02-16 08:53:25
+ 2026-02-16 08:53:25
+ closed
+ closed
+ wp-global-styles-twentytwentyfive
+ publish
+ 0
+ 0
+ wp_global_styles
+
+ 0
+
+
+-
+
+ http://carousel-demo.local/
+ Thu, 12 Feb 2026 02:40:15 +0000
+ danish
+ http://carousel-demo.local/?page_id=9
+
+
+What is Carousel Kit?
+
+
+
+Carousel Kit is a an Interactivity API-powered carousel system built for the WordPress Block Editor. It is designed for enterprise-grade performance and extensibility.
+
+
+
+
+
+
+
+
+
+
+
+Examples
+
+
+
+
+
+
+
+
Autoplay
+
+
+
+
Create auto-playing carousels with Carousel Kit.
+
+
+
+
+
+
+
+
+
+
+
+
Infinite Loop
+
+
+
+
Learn how to enable infinite looping easily with Carousel Kit.
+
+
+
+
+
+
+
+
+
+
+
+
Orientation & Direction
+
+
+
+
Create vertical and RTL carousels with Carousel Kit.
+
+
+
+
+
+
+
+
+
+
+
+
Styling Options
+
+
+
+
Learn how to achieve different styling options for your carousel.
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 9
+ 2026-02-12 02:40:15
+ 2026-02-12 02:40:15
+ 2026-02-16 09:14:28
+ 2026-02-16 09:14:28
+ closed
+ closed
+ homepage
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+ _wp_page_template
+
+
+
+-
+
+ http://carousel-demo.local/autoplay/
+ Thu, 12 Feb 2026 03:02:02 +0000
+ danish
+ http://carousel-demo.local/?page_id=12
+
+
+Using Carousel Kit, you can easily create carousels which auto-play. You can configure the duration of each slide and different interactions which pause the auto-play such as hovering over a slide.
+
+
+
+
+
+
+
+
+Excellence is an art won by training and habituation.
+Aristotle
+
+
+
+
+
+
+
+
+I hear and I forget. I see and I remember. I do and I understand.
+Confucius
+
+
+
+
+
+
+
+
+Wisdom begins in wonder.
+Socrates
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 12
+ 2026-02-12 03:02:02
+ 2026-02-12 03:02:02
+ 2026-02-12 03:05:26
+ 2026-02-12 03:05:26
+ closed
+ closed
+ autoplay
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/autoplay/pexels-tahayasiryoney-30617939/
+ Thu, 12 Feb 2026 02:51:02 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-tahayasiryoney-30617939.jpg
+
+
+
+ 13
+ 2026-02-12 02:51:02
+ 2026-02-12 02:51:02
+ 2026-02-12 02:51:02
+ 2026-02-12 02:51:02
+ open
+ closed
+ pexels-tahayasiryoney-30617939
+ inherit
+ 12
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-tahayasiryoney-30617939-scaled.jpg
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/autoplay/pexels-armin-forster-6000542-6441839/
+ Thu, 12 Feb 2026 02:53:28 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-armin-forster-6000542-6441839.jpg
+
+
+
+ 14
+ 2026-02-12 02:53:28
+ 2026-02-12 02:53:28
+ 2026-02-12 02:53:28
+ 2026-02-12 02:53:28
+ open
+ closed
+ pexels-armin-forster-6000542-6441839
+ inherit
+ 12
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-armin-forster-6000542-6441839-scaled.jpg
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/autoplay/pexels-anne-o-sullivan-1478092867-26887007/
+ Thu, 12 Feb 2026 02:57:51 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-anne-o-sullivan-1478092867-26887007.jpg
+
+
+
+ 15
+ 2026-02-12 02:57:51
+ 2026-02-12 02:57:51
+ 2026-02-12 02:57:51
+ 2026-02-12 02:57:51
+ open
+ closed
+ pexels-anne-o-sullivan-1478092867-26887007
+ inherit
+ 12
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-anne-o-sullivan-1478092867-26887007-scaled.jpg
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/header/
+ Thu, 12 Feb 2026 03:02:27 +0000
+ danish
+ http://carousel-demo.local/header/
+
+
+
+]]>
+
+ 17
+ 2026-02-12 03:02:27
+ 2026-02-12 03:02:27
+ 2026-02-12 03:02:27
+ 2026-02-12 03:02:27
+ closed
+ closed
+ header
+ publish
+ 0
+ 0
+ wp_template_part
+
+ 0
+
+
+
+ origin
+
+
+
+-
+
+ http://carousel-demo.local/page/
+ Thu, 12 Feb 2026 03:02:27 +0000
+ danish
+ http://carousel-demo.local/page/
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 18
+ 2026-02-12 03:02:27
+ 2026-02-12 03:02:27
+ 2026-02-13 02:13:27
+ 2026-02-13 02:13:27
+ closed
+ closed
+ page
+ publish
+ 0
+ 0
+ wp_template
+
+ 0
+
+
+ origin
+
+
+
+-
+
+ http://carousel-demo.local/footer/
+ Thu, 12 Feb 2026 03:02:27 +0000
+ danish
+ http://carousel-demo.local/footer/
+
+
+
+
+
+
+
+
Carousel Kit with WordPress & Interactivity API
+
+
+
+
Created with ❤️ by rtCamp
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 20
+ 2026-02-12 03:02:27
+ 2026-02-12 03:02:27
+ 2026-02-16 09:09:53
+ 2026-02-16 09:09:53
+ closed
+ closed
+ footer
+ publish
+ 0
+ 0
+ wp_template_part
+
+ 0
+
+
+
+ origin
+
+
+
+-
+
+ http://carousel-demo.local/page-without-title/
+ Thu, 12 Feb 2026 03:07:34 +0000
+ danish
+ http://carousel-demo.local/page-without-title/
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 27
+ 2026-02-12 03:07:34
+ 2026-02-12 03:07:34
+ 2026-02-12 03:08:04
+ 2026-02-12 03:08:04
+ closed
+ closed
+ page-without-title
+ publish
+ 0
+ 0
+ wp_template
+
+ 0
+
+
+-
+
+ http://carousel-demo.local/add-looping-to-your-carousel/
+ Fri, 13 Feb 2026 01:27:26 +0000
+ danish
+ http://carousel-demo.local/?page_id=32
+
+
+To loop your carousel, all you need to do is select the Carousel block and toggle the "Loop" option.
+
+
+
+
+]]>
+
+ 32
+ 2026-02-13 01:27:26
+ 2026-02-13 01:27:26
+ 2026-02-16 09:24:44
+ 2026-02-16 09:24:44
+ closed
+ closed
+ add-looping-to-your-carousel
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/add-looping-to-your-carousel/pexels-dzikilechu-5112627/
+ Fri, 13 Feb 2026 01:36:26 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-dzikilechu-5112627.jpg
+
+
+
+ 36
+ 2026-02-13 01:36:26
+ 2026-02-13 01:36:26
+ 2026-02-13 01:36:26
+ 2026-02-13 01:36:26
+ open
+ closed
+ pexels-dzikilechu-5112627
+ inherit
+ 32
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/pexels-dzikilechu-5112627-scaled.jpg
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/api/
+ Fri, 13 Feb 2026 02:20:31 +0000
+ danish
+ http://carousel-demo.local/?page_id=48
+
+
+The blocks uses the WordPress Interactivity API to manage state and logic. You can consume this state in your own custom blocks to build advanced features like progress bars, slide counters, or synchronized sliders.
+
+
+
+Store Namespace
+
+
+
+carousel-kit/carousel
+
+
+
+Context (CarouselContext)
+
+
+
+The following properties are exposed in the Interactivity API context:
+
+
+
+Property Type Description isPlayingbooleanIf Autoplay is currently running timerIterationIdnumberIncrements every time the Autoplay timer resets (slide change). Bind to key to restart animations. autoplayboolean|{ delay, ... }Autoplay config or false if disabled. canScrollPrevbooleantrue if there are previous slides (or looping).canScrollNextboolean|truetrue if there are next slides (or looping).selectedIndexnumberThe zero-based index of the current slide. scrollSnaps{ index: number }[]List of snap points (used by Dots block).
+]]>
+
+ 48
+ 2026-02-13 02:20:31
+ 2026-02-13 02:20:31
+ 2026-02-16 01:44:27
+ 2026-02-16 01:44:27
+ closed
+ closed
+ api
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/creating-a-carousel/
+ Mon, 16 Feb 2026 01:34:02 +0000
+ danish
+ http://carousel-demo.local/?page_id=59
+
+
+Carousel Kit uses compound block architecture. Each functional component of a usual carousel is its own block which provides maximum flexibility.
+
+
+
+Blocks
+
+
+
+Carousel Kit comes with the following blocks out of the box:
+
+
+
+
+Carousel (Parent): This parent block provides carousel context and configuration to the blocks inside it.
+
+
+
+Carousel Viewport: Carousel Viewport acts as the container for all the slides. It provides semantic and markup boundary.
+
+
+
+Carousel Slide: Carousel Slide holds the content of the individual slide. It can contain virtually any block. Like the viewport block, it also provides semantic and markup boundary.
+
+
+
+Carousel Controls: Inserts Previous and Next buttons.
+
+
+
+Carousel Dots: Inserts visual pagination indicators.
+
+
+
+
+Creating a Basic Carousel
+
+
+
+1. From your Blocks Library, choose Carousel
+
+
+
+
+
+
+
+2. Add contents to the Carousel Slide by choosing carousel slide and adding any block inside it.
+
+
+
+
+
+
+
+3. To configure your carousel, select the Carousel block and from the right sidebar, configure it as per your needs.
+
+
+
+
+
+
+
+Result
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 59
+ 2026-02-16 01:34:02
+ 2026-02-16 01:34:02
+ 2026-02-16 09:09:10
+ 2026-02-16 09:09:10
+ closed
+ closed
+ creating-a-carousel
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/creating-a-carousel/image/
+ Mon, 16 Feb 2026 01:27:41 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/image.png
+
+
+
+ 60
+ 2026-02-16 01:27:41
+ 2026-02-16 01:27:41
+ 2026-02-16 01:27:41
+ 2026-02-16 01:27:41
+ open
+ closed
+ image
+ inherit
+ 59
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/image.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/creating-a-carousel/image-2/
+ Mon, 16 Feb 2026 01:30:58 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-1.png
+
+
+
+ 61
+ 2026-02-16 01:30:58
+ 2026-02-16 01:30:58
+ 2026-02-16 01:30:58
+ 2026-02-16 01:30:58
+ open
+ closed
+ image-2
+ inherit
+ 59
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-1.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/creating-a-carousel/image-3/
+ Mon, 16 Feb 2026 01:32:28 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-2.png
+
+
+
+ 62
+ 2026-02-16 01:32:28
+ 2026-02-16 01:32:28
+ 2026-02-16 01:32:28
+ 2026-02-16 01:32:28
+ open
+ closed
+ image-3
+ inherit
+ 59
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-2.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/styles/
+ Mon, 16 Feb 2026 01:42:21 +0000
+ danish
+ http://carousel-demo.local/?page_id=64
+
+
+To configure how many slides are visible at once, you can use the style options of the carousel.
+
+
+
+100% Slides (1 slide per view)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+50% Slides (2 slides per view)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+33% Slides (3 slides per view)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+25% Slides (4 slides per view)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Slide Gap
+
+
+
+By default, slides don't have a gap between them. If you have more than 1 slide per view, it might be a good idea to have some gap.
+
+
+
+You can add a gap between using style options.
+
+
+
+
+Select the carousel
+
+
+
+In the right sidebar, choose the "Styles" option
+
+
+
+Specify the gap (in px) in Layout > Slide Gap
+
+
+
+
+
+
+
+
+
+]]>
+
+ 64
+ 2026-02-16 01:42:21
+ 2026-02-16 01:42:21
+ 2026-02-16 09:07:55
+ 2026-02-16 09:07:55
+ closed
+ closed
+ styles
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/styles/screen-recording-2026-02-16-at-02-40-13/
+ Mon, 16 Feb 2026 01:42:08 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/Screen-Recording-2026-02-16-at-02.40.13.gif
+
+
+
+ 65
+ 2026-02-16 01:42:08
+ 2026-02-16 01:42:08
+ 2026-02-16 01:42:08
+ 2026-02-16 01:42:08
+ open
+ closed
+ screen-recording-2026-02-16-at-02-40-13
+ inherit
+ 64
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/Screen-Recording-2026-02-16-at-02.40.13.gif
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/orientation-direction/
+ Mon, 16 Feb 2026 01:51:57 +0000
+ danish
+ http://carousel-demo.local/?page_id=69
+
+
+Using Carousel Kit, you can also choose orientation (axis) and direction of your carousels. This is important if you are creating content for different locales (RTL) or want more flexibility with the presentation of your content.
+
+
+
+Orientation (Axis)
+
+
+
+You can choose the orientation of your carousel by selecting the carousel block and choosing vertical/horizontal orientation.
+
+
+
+If you choose vertical orientation, you will also need to specify a fixed height.
+
+
+
+
+
+
+
+
+Excellence is an art won by training and habituation.
+Aristotle
+
+
+
+
+
+
+
+
+I hear and I forget. I see and I remember. I do and I understand.
+Confucius
+
+
+
+
+
+
+
+
+Wisdom begins in wonder.
+Socrates
+
+
+
+
+
+
+
+
+
+
+
+Direction
+
+
+
+You can also specify direction of your carousel (LTR/RTL). Select the carousel block and in the "Direction" options, choose your desired direction.
+
+
+
+
+
+
+
+
+Excellence is an art won by training and habituation.
+Aristotle
+
+
+
+
+
+
+
+
+I hear and I forget. I see and I remember. I do and I understand.
+Confucius
+
+
+
+
+
+
+
+
+Wisdom begins in wonder.
+Socrates
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 69
+ 2026-02-16 01:51:57
+ 2026-02-16 01:51:57
+ 2026-02-16 01:53:41
+ 2026-02-16 01:53:41
+ closed
+ closed
+ orientation-direction
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/orientation-direction/group-10/
+ Mon, 16 Feb 2026 01:51:05 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/Group-10.png
+
+
+
+ 70
+ 2026-02-16 01:51:05
+ 2026-02-16 01:51:05
+ 2026-02-16 01:51:05
+ 2026-02-16 01:51:05
+ open
+ closed
+ group-10
+ inherit
+ 69
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/Group-10.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/styles/image-4/
+ Mon, 16 Feb 2026 09:07:46 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-3.png
+
+
+
+ 86
+ 2026-02-16 09:07:46
+ 2026-02-16 09:07:46
+ 2026-02-16 09:07:46
+ 2026-02-16 09:07:46
+ open
+ closed
+ image-4
+ inherit
+ 64
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-3.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+-
+
+ http://carousel-demo.local/query-loop/
+ Mon, 16 Feb 2026 09:22:45 +0000
+ danish
+ http://carousel-demo.local/?page_id=93
+
+
+When a Query Loop block is inserted inside Carousel Viewport, Carousel Kit automatically treats each post as an individual slide. This means that you can create dynamic carousels which can show your posts, pages, and any custom post type.
+
+
+
+
+
+
+
+
+
+
+
+
+]]>
+
+ 93
+ 2026-02-16 09:22:45
+ 2026-02-16 09:22:45
+ 2026-02-16 09:23:33
+ 2026-02-16 09:23:33
+ closed
+ closed
+ query-loop
+ publish
+ 0
+ 0
+ page
+
+ 0
+
+-
+
+ http://carousel-demo.local/query-loop/image-5/
+ Mon, 16 Feb 2026 09:23:24 +0000
+ danish
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-4.png
+
+
+
+ 95
+ 2026-02-16 09:23:24
+ 2026-02-16 09:23:24
+ 2026-02-16 09:23:24
+ 2026-02-16 09:23:24
+ open
+ closed
+ image-5
+ inherit
+ 93
+ 0
+ attachment
+
+ 0
+ http://carousel-demo.local/wp-content/uploads/2026/02/image-4.png
+
+ _wp_attached_file
+
+
+
+ _wp_attachment_metadata
+
+
+
+
+
diff --git a/examples/data/core-carousel.xml b/examples/data/core-carousel.xml
deleted file mode 100644
index cc31a4e..0000000
--- a/examples/data/core-carousel.xml
+++ /dev/null
@@ -1,507 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Core Carousel
- https://carousel.local
-
- Mon, 09 Feb 2026 13:02:36 +0000
- en-US
- 1.2
- https://carousel.local
- https://carousel.local
-
- 1
-
-
- 1
-
-
-
-
-
- 2
-
-
-
-
-
-
- 1
-
-
-
-
-
-
- https://wordpress.org/?v=6.9.1
-
- -
-
- https://carousel.local/2026/02/09/hello-world/
- Mon, 09 Feb 2026 13:00:32 +0000
-
- https://carousel.local/?p=1
-
-
-Welcome to WordPress. This is your first post. Edit or delete it, then start writing!
-]]>
-
- 1
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
-
- 1
-
-
- https://wordpress.org/
-
-
-
- Gravatar.]]>
-
-
- 0
- 0
-
-
- -
-
- https://carousel.local/sample-page/
- Mon, 09 Feb 2026 13:00:32 +0000
-
- https://carousel.local/?page_id=2
-
-
-This is an example page. It's different from a blog post because it will stay in one place and will show up in your site navigation (in most themes). Most people start with an About page that introduces them to potential site visitors. It might say something like this:
-
-
-
-
-
-Hi there! I'm a bike messenger by day, aspiring actor by night, and this is my website. I live in Los Angeles, have a great dog named Jack, and I like piña coladas. (And gettin' caught in the rain.)
-
-
-
-
-
-...or something like this:
-
-
-
-
-
-The XYZ Doohickey Company was founded in 1971, and has been providing quality doohickeys to the public ever since. Located in Gotham City, XYZ employs over 2,000 people and does all kinds of awesome things for the Gotham community.
-
-
-
-
-
-As a new WordPress user, you should go to your dashboard to delete this page and create new pages for your content. Have fun!
-]]>
-
- 2
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
-
-
-
-
- -
-
- https://carousel.local/?page_id=3
- Mon, 09 Feb 2026 13:00:32 +0000
-
- https://carousel.local/?page_id=3
-
-
-Who we are
-
-
-Suggested text: Our website address is: https://carousel.local.
-
-
-Comments
-
-
-Suggested text: When visitors leave comments on the site we collect the data shown in the comments form, and also the visitor’s IP address and browser user agent string to help spam detection.
-
-
-An anonymized string created from your email address (also called a hash) may be provided to the Gravatar service to see if you are using it. The Gravatar service privacy policy is available here: https://automattic.com/privacy/. After approval of your comment, your profile picture is visible to the public in the context of your comment.
-
-
-Media
-
-
-Suggested text: If you upload images to the website, you should avoid uploading images with embedded location data (EXIF GPS) included. Visitors to the website can download and extract any location data from images on the website.
-
-
-Cookies
-
-
-Suggested text: If you leave a comment on our site you may opt-in to saving your name, email address and website in cookies. These are for your convenience so that you do not have to fill in your details again when you leave another comment. These cookies will last for one year.
-
-
-If you visit our login page, we will set a temporary cookie to determine if your browser accepts cookies. This cookie contains no personal data and is discarded when you close your browser.
-
-
-When you log in, we will also set up several cookies to save your login information and your screen display choices. Login cookies last for two days, and screen options cookies last for a year. If you select "Remember Me", your login will persist for two weeks. If you log out of your account, the login cookies will be removed.
-
-
-If you edit or publish an article, an additional cookie will be saved in your browser. This cookie includes no personal data and simply indicates the post ID of the article you just edited. It expires after 1 day.
-
-
-Embedded content from other websites
-
-
-Suggested text: Articles on this site may include embedded content (e.g. videos, images, articles, etc.). Embedded content from other websites behaves in the exact same way as if the visitor has visited the other website.
-
-
-These websites may collect data about you, use cookies, embed additional third-party tracking, and monitor your interaction with that embedded content, including tracking your interaction with the embedded content if you have an account and are logged in to that website.
-
-
-Who we share your data with
-
-
-Suggested text: If you request a password reset, your IP address will be included in the reset email.
-
-
-How long we retain your data
-
-
-Suggested text: If you leave a comment, the comment and its metadata are retained indefinitely. This is so we can recognize and approve any follow-up comments automatically instead of holding them in a moderation queue.
-
-
-For users that register on our website (if any), we also store the personal information they provide in their user profile. All users can see, edit, or delete their personal information at any time (except they cannot change their username). Website administrators can also see and edit that information.
-
-
-What rights you have over your data
-
-
-Suggested text: If you have an account on this site, or have left comments, you can request to receive an exported file of the personal data we hold about you, including any data you have provided to us. You can also request that we erase any personal data we hold about you. This does not include any data we are obliged to keep for administrative, legal, or security purposes.
-
-
-Where your data is sent
-
-
-Suggested text: Visitor comments may be checked through an automated spam detection service.
-
-]]>
-
- 3
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
-
-
-
-
- -
-
- https://carousel.local/2026/02/09/navigation/
- Mon, 09 Feb 2026 13:00:32 +0000
-
- https://carousel.local/2026/02/09/navigation/
-
- ]]>
-
- 4
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
- -
-
- https://carousel.local/
- Mon, 09 Feb 2026 13:01:18 +0000
-
- https://carousel.local/?page_id=6
-
-
-
-
-
-
-
Welcome to Our Site
-
-
-
-
Discover amazing content and experiences
-
-
-
-
-
-
-
-
-
-
-
-
Build Something Amazing
-
-
-
-
Powerful tools for modern creators
-
-
-
-
-
-
-
-
Join Our Community
-
-
-
-
Connect with thousands of users worldwide
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
Trusted By Leading Companies
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
What Our Customers Say
-
-
-
-
-
-
-
"This product changed my workflow completely. Highly recommended!"
-
-
-
-
-
-
-
-
Sarah Johnson CEO, Tech Corp
-
-
-
-
-
-
-
-
"Excellent support and amazing features. Worth every penny!"
-
-
-
-
-
-
-
-
Michael Chen Designer, Creative Studio
-
-
-
-
-
-
-
-
"Simple, elegant, and powerful. Best investment we made!"
-
-
-
-
-
-
-
-
Emma Williams Marketing Director, Brand Co
-
-
-
-
-
-
-
-
-]]>
-
- 6
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
- -
-
- https://carousel.local/2026/02/09/wp-global-styles-twentytwentyfive/
- Mon, 09 Feb 2026 13:01:04 +0000
-
- https://carousel.local/2026/02/09/wp-global-styles-twentytwentyfive/
-
-
-
- 7
-
-
-
-
-
-
-
-
- 0
- 0
-
-
- 0
-
-
-
-
-
\ No newline at end of file
diff --git a/examples/patterns/hero-carousel.php b/examples/patterns/hero-carousel.php
index 2644ce8..564cd54 100644
--- a/examples/patterns/hero-carousel.php
+++ b/examples/patterns/hero-carousel.php
@@ -1,17 +1,17 @@
-
-
-
-
-
+
+
+
+
+
Welcome to Our Site
@@ -31,10 +31,10 @@
-
+
-
-
+
+
Build Something Amazing
@@ -47,10 +47,10 @@
-
+
-
-
+
+
Join Our Community
@@ -63,24 +63,24 @@
-
+
-
+
-
-
-
+
diff --git a/examples/patterns/logo-showcase.php b/examples/patterns/logo-showcase.php
index b1a2b70..7c7e817 100644
--- a/examples/patterns/logo-showcase.php
+++ b/examples/patterns/logo-showcase.php
@@ -1,66 +1,66 @@
-
-
+
+
Trusted By Leading Companies
-
-
-
-
+
+
+
+
-
+
-
-
+
+
-
+
-
-
+
+
-
+
-
-
-
+
-
-
-
+
diff --git a/examples/patterns/query-loop.php b/examples/patterns/query-loop.php
index 97ae3ab..3b82ee5 100644
--- a/examples/patterns/query-loop.php
+++ b/examples/patterns/query-loop.php
@@ -1,17 +1,17 @@
-
-
-
-
-
+
+
+
+
-
+
-
-
-
+
diff --git a/examples/patterns/testimonial-carousel.php b/examples/patterns/testimonial-carousel.php
index c096562..47a466b 100644
--- a/examples/patterns/testimonial-carousel.php
+++ b/examples/patterns/testimonial-carousel.php
@@ -1,21 +1,21 @@
-
-
+
+
What Our Customers Say
-
-
-
-
+
+
+
+
"This product changed my workflow completely. Highly recommended!"
@@ -30,10 +30,10 @@
-
+
-
-
+
+
"Excellent support and amazing features. Worth every penny!"
@@ -48,10 +48,10 @@
-
+
-
-
+
+
"Simple, elegant, and powerful. Best investment we made!"
@@ -66,24 +66,24 @@
-
+
-
+
-
-
-
+
-
+
diff --git a/inc/Plugin.php b/inc/Plugin.php
index da438b2..48196f3 100644
--- a/inc/Plugin.php
+++ b/inc/Plugin.php
@@ -2,14 +2,14 @@
/**
* Plugin manifest class.
*
- * @package Core_Carousel
+ * @package Carousel_Kit
*/
declare(strict_types=1);
-namespace Core_Carousel;
+namespace Carousel_Kit;
-use Core_Carousel\Traits\Singleton;
+use Carousel_Kit\Traits\Singleton;
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
@@ -53,8 +53,8 @@ public function register_block_category( array $categories ): array {
$categories,
[
[
- 'slug' => 'core-carousel',
- 'title' => __( 'Core Carousel', 'core-carousel' ),
+ 'slug' => 'carousel-kit',
+ 'title' => __( 'Carousel Kit', 'carousel-kit' ),
],
]
);
@@ -76,11 +76,11 @@ public function register_blocks(): void {
foreach ( $blocks as $block ) {
// Ensure path constant is defined before use to avoid fatal errors.
- if ( ! defined( 'CORE_CAROUSEL_BUILD_PATH' ) ) {
+ if ( ! defined( 'CAROUSEL_KIT_BUILD_PATH' ) ) {
continue;
}
- register_block_type( CORE_CAROUSEL_BUILD_PATH . '/blocks/' . $block );
+ register_block_type( CAROUSEL_KIT_BUILD_PATH . '/blocks/' . $block );
}
}
@@ -91,10 +91,10 @@ public function register_blocks(): void {
*/
public function register_pattern_category(): void {
register_block_pattern_category(
- 'core-carousel',
+ 'carousel-kit',
[
- 'label' => __( 'Core Carousel', 'core-carousel' ),
- 'description' => __( 'Pre-configured carousel patterns for various use cases.', 'core-carousel' ),
+ 'label' => __( 'Carousel Kit', 'carousel-kit' ),
+ 'description' => __( 'Pre-configured carousel patterns for various use cases.', 'carousel-kit' ),
]
);
}
@@ -108,12 +108,12 @@ public function register_pattern_category(): void {
* @return void
*/
public function register_block_patterns(): void {
- if ( ! defined( 'CORE_CAROUSEL_PATH' ) ) {
+ if ( ! defined( 'CAROUSEL_KIT_PATH' ) ) {
return;
}
// Use cached patterns if available and not in debug mode.
- $cache_key = 'core_carousel_patterns_cache';
+ $cache_key = 'carousel_kit_patterns_cache';
$patterns = get_transient( $cache_key );
if ( ( defined( 'WP_DEBUG' ) && WP_DEBUG ) || false === $patterns ) {
@@ -138,7 +138,7 @@ public function register_block_patterns(): void {
* @return array
*/
private function load_patterns_from_disk(): array {
- $patterns_dir = CORE_CAROUSEL_PATH . '/examples/patterns';
+ $patterns_dir = CAROUSEL_KIT_PATH . '/examples/patterns';
$data = [];
if ( ! is_dir( $patterns_dir ) ) {
@@ -183,7 +183,7 @@ private function load_patterns_from_disk(): array {
// Parse categories.
$categories = ! empty( $file_headers['categories'] )
? array_filter( array_map( 'trim', explode( ',', $file_headers['categories'] ) ) )
- : [ 'core-carousel' ];
+ : [ 'carousel-kit' ];
$data[] = [
'slug' => $file_headers['slug'],
diff --git a/inc/Traits/Singleton.php b/inc/Traits/Singleton.php
index 8b313b5..385b270 100644
--- a/inc/Traits/Singleton.php
+++ b/inc/Traits/Singleton.php
@@ -22,10 +22,10 @@
*
* If you specifically need multiple objects, then use a normal class.
*
- * @package core-carousel
+ * @package carousel-kit
*/
-namespace Core_Carousel\Traits;
+namespace Carousel_Kit\Traits;
trait Singleton {
@@ -75,9 +75,9 @@ final public static function get_instance() {
$instance[ $called_class ] = new $called_class();
/**
- * Dependent items can use the core_carousel_singleton_init_{$called_class} hook to execute code
+ * Dependent items can use the carousel_kit_singleton_init_{$called_class} hook to execute code
*/
- do_action( sprintf( 'core_carousel_singleton_init_%s', $called_class ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
+ do_action( sprintf( 'carousel_kit_singleton_init_%s', $called_class ) ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
}
return $instance[ $called_class ];
diff --git a/jest.config.js b/jest.config.js
index 9c127e7..06836b2 100644
--- a/jest.config.js
+++ b/jest.config.js
@@ -1,5 +1,5 @@
/**
- * Jest configuration for Core Carousel plugin.
+ * Jest configuration for Carousel Kit plugin.
*
* Extends @wordpress/scripts default configuration with:
* - Custom test setup for WordPress and Embla mocks
@@ -15,7 +15,7 @@ module.exports = {
...defaultConfig,
// Display name for clarity in multi-project setups
- displayName: 'core-carousel',
+ displayName: 'carousel-kit',
// Test setup files run after Jest environment is set up
setupFilesAfterEnv: [
diff --git a/package-lock.json b/package-lock.json
index b4313f8..0773b20 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,11 +1,11 @@
{
- "name": "core-carousel",
+ "name": "carousel-kit",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
- "name": "core-carousel",
+ "name": "carousel-kit",
"version": "1.0.0",
"dependencies": {
"@wordpress/babel-preset-default": "8.38.0",
@@ -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..337a513 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
- "name": "core-carousel",
- "version": "1.0.0",
+ "name": "carousel-kit",
+ "version": "1.0.1",
"description": "Carousel block using Embla and WordPress Interactivity API",
"author": "rtCamp",
"private": true,
@@ -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",
diff --git a/phpcs.xml.dist b/phpcs.xml.dist
index fc4dee8..9e12413 100644
--- a/phpcs.xml.dist
+++ b/phpcs.xml.dist
@@ -1,6 +1,6 @@
@@ -9,7 +9,7 @@
./src/inc/
- ./core-carousel.php
+ ./carousel-kit.php
**/build/**
@@ -219,7 +219,7 @@
-
+
diff --git a/phpstan.neon.dist b/phpstan.neon.dist
index 796a838..5ccb477 100644
--- a/phpstan.neon.dist
+++ b/phpstan.neon.dist
@@ -20,7 +20,7 @@ parameters:
bootstrapFiles:
- tests/phpstan/constants.php
paths:
- - core-carousel.php
+ - carousel-kit.php
- src/inc/
- templates/
- examples/
diff --git a/phpunit.xml.dist b/phpunit.xml.dist
index 04adb04..d9e4e8f 100644
--- a/phpunit.xml.dist
+++ b/phpunit.xml.dist
@@ -17,7 +17,7 @@
inc
- core-carousel.php
+ carousel-kit.php
vendor
diff --git a/src/blocks/carousel/__tests__/view.test.ts b/src/blocks/carousel/__tests__/view.test.ts
index ee8c22a..0fca857 100644
--- a/src/blocks/carousel/__tests__/view.test.ts
+++ b/src/blocks/carousel/__tests__/view.test.ts
@@ -12,20 +12,16 @@
* @package
*/
-import {
- store,
- getContext,
- getElement,
-} from '@wordpress/interactivity';
+import { store, getContext, getElement } from '@wordpress/interactivity';
import EmblaCarousel, { type EmblaCarouselType } from 'embla-carousel';
// Symbol key used by the view.ts for Embla instances
-const EMBLA_KEY = Symbol.for( 'core-carousel.carousel' );
+const EMBLA_KEY = Symbol.for( 'carousel-kit.carousel' );
// Type for viewport element with Embla instance attached
type EmblaViewportElement = HTMLElement & {
- [ EMBLA_KEY ]?: EmblaCarouselType;
+ [EMBLA_KEY]?: EmblaCarouselType;
};
import type { CarouselContext } from '../types';
@@ -35,29 +31,31 @@ import '../view';
// Get the store config that was passed to store()
const storeCall = ( store as jest.Mock ).mock.calls.find(
- ( call: unknown[] ) => call[ 0 ] === 'core-carousel/carousel',
+ ( call: unknown[] ) => call[ 0 ] === 'carousel-kit/carousel',
);
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,13 +71,15 @@ 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' );
viewport.className = 'embla';
const wrapper = document.createElement( 'div' );
- wrapper.className = 'core-carousel';
+ wrapper.className = 'carousel-kit';
wrapper.appendChild( viewport );
const button = document.createElement( 'button' );
@@ -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(),
@@ -112,7 +114,7 @@ describe( 'Carousel View Module', () => {
// storeCall being defined proves store was called with the correct namespace
expect( storeCall ).toBeDefined();
expect( storeConfig ).not.toBeNull();
- expect( storeCall[ 0 ] ).toBe( 'core-carousel/carousel' );
+ expect( storeCall[ 0 ] ).toBe( 'carousel-kit/carousel' );
} );
it( 'should register store with all required sections', () => {
@@ -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();
diff --git a/src/blocks/carousel/block.json b/src/blocks/carousel/block.json
index 6a06653..af51de7 100644
--- a/src/blocks/carousel/block.json
+++ b/src/blocks/carousel/block.json
@@ -2,14 +2,14 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"version": "1.0.0",
- "name": "core-carousel/carousel",
+ "name": "carousel-kit/carousel",
"title": "Carousel",
- "category": "core-carousel",
+ "category": "carousel-kit",
"icon": "columns",
"description": "Carousel container using Embla and Interactivity API.",
- "textdomain": "core-carousel",
+ "textdomain": "carousel-kit",
"providesContext": {
- "core-carousel/carousel/allowedSlideBlocks": "allowedSlideBlocks"
+ "carousel-kit/carousel/allowedSlideBlocks": "allowedSlideBlocks"
},
"supports": {
"interactivity": true,
diff --git a/src/blocks/carousel/controls/block.json b/src/blocks/carousel/controls/block.json
index 763c4b9..bf7c3c1 100644
--- a/src/blocks/carousel/controls/block.json
+++ b/src/blocks/carousel/controls/block.json
@@ -2,15 +2,15 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"version": "1.0.0",
- "name": "core-carousel/carousel-controls",
+ "name": "carousel-kit/carousel-controls",
"title": "Carousel Controls",
- "category": "core-carousel",
+ "category": "carousel-kit",
"icon": "button",
"ancestor": [
- "core-carousel/carousel"
+ "carousel-kit/carousel"
],
"description": "Navigation buttons for the carousel.",
- "textdomain": "core-carousel",
+ "textdomain": "carousel-kit",
"attributes": {},
"supports": {
"interactivity": true
diff --git a/src/blocks/carousel/controls/components/icons.tsx b/src/blocks/carousel/controls/components/icons.tsx
index 5c39111..b9a0704 100644
--- a/src/blocks/carousel/controls/components/icons.tsx
+++ b/src/blocks/carousel/controls/components/icons.tsx
@@ -1,7 +1,7 @@
export const PreviousIcon = () => {
return (
{
export const NextIcon = () => {
return (
( null );
const blockProps = useBlockProps( {
- className: 'core-carousel-controls',
+ className: 'carousel-kit-controls',
} );
const getEmblaFromDOM = () => {
if ( ! ref.current ) {
return null;
}
- const wrapper = ref.current.closest( '.core-carousel' );
+ const wrapper = ref.current.closest( '.carousel-kit' );
if ( ! wrapper ) {
return null;
}
@@ -49,26 +49,26 @@ export default function Edit() {
return (
{
e.stopPropagation();
handleScroll( 'prev' );
} }
type="button"
disabled={ ! canScrollPrev }
- aria-label={ __( 'Previous Slide', 'core-carousel' ) }
+ aria-label={ __( 'Previous Slide', 'carousel-kit' ) }
>
{
e.stopPropagation();
handleScroll( 'next' );
} }
type="button"
disabled={ ! canScrollNext }
- aria-label={ __( 'Next Slide', 'core-carousel' ) }
+ aria-label={ __( 'Next Slide', 'carousel-kit' ) }
>
diff --git a/src/blocks/carousel/controls/save.tsx b/src/blocks/carousel/controls/save.tsx
index 5d88aad..e37645b 100644
--- a/src/blocks/carousel/controls/save.tsx
+++ b/src/blocks/carousel/controls/save.tsx
@@ -4,26 +4,26 @@ import { NextIcon, PreviousIcon } from './components/icons';
export default function Save() {
const blockProps = useBlockProps.save( {
- className: 'core-carousel-controls',
+ className: 'carousel-kit-controls',
} );
return (
diff --git a/src/blocks/carousel/controls/style.scss b/src/blocks/carousel/controls/style.scss
index 98f3819..64b5b0f 100644
--- a/src/blocks/carousel/controls/style.scss
+++ b/src/blocks/carousel/controls/style.scss
@@ -1,49 +1,49 @@
/**
* Styles for the controls (previous/next) buttons
*/
-.core-carousel-controls {
+.carousel-kit-controls {
display: flex;
gap: var(--wp--style--block-gap, 1rem);
}
-.core-carousel-controls__btn {
+.carousel-kit-controls__btn {
display: flex;
gap: 0.5rem;
justify-content: center;
align-items: center;
- background-color: var(--core-carousel-control-bg, unset);
- color: var(--core-carousel-control-color, inherit);
+ background-color: var(--carousel-kit-control-bg, unset);
+ color: var(--carousel-kit-control-color, inherit);
cursor: pointer;
- padding: var(--core-carousel-control-padding, 0.5rem);
- border: var(--core-carousel-control-border, 1.25px solid rgba(28, 28, 28, 0.3));
- border-radius: var(--core-carousel-control-radius, 50%);
+ padding: var(--carousel-kit-control-padding, 0.5rem);
+ border: var(--carousel-kit-control-border, 1.25px solid rgba(28, 28, 28, 0.3));
+ border-radius: var(--carousel-kit-control-radius, 50%);
transition: all 0.125s ease-in-out;
- width: var(--core-carousel-control-size, 2.5rem);
- height: var(--core-carousel-control-size, 2.5rem);
+ width: var(--carousel-kit-control-size, 2.5rem);
+ height: var(--carousel-kit-control-size, 2.5rem);
}
-.core-carousel-controls__btn:not(:disabled):hover {
- background-color: var(--core-carousel-control-bg-hover, rgba(248, 248, 248, 1));
- border: var(--core-carousel-control-border-hover, 1.25px solid rgba(28, 28, 28, 0.75));
- color: var(--core-carousel-control-color-hover, inherit);
+.carousel-kit-controls__btn:not(:disabled):hover {
+ background-color: var(--carousel-kit-control-bg-hover, rgba(248, 248, 248, 1));
+ border: var(--carousel-kit-control-border-hover, 1.25px solid rgba(28, 28, 28, 0.75));
+ color: var(--carousel-kit-control-color-hover, inherit);
}
-.core-carousel-controls__btn:disabled {
+.carousel-kit-controls__btn:disabled {
cursor: not-allowed;
opacity: 0.25;
}
// In RTL mode, rotate the icons 180 degrees to flip their direction
-[dir="rtl"] .core-carousel-controls__btn svg {
+[dir="rtl"] .carousel-kit-controls__btn svg {
transform: rotate(180deg);
}
// Vertical mode adjustments
-.core-carousel[data-axis="y"] .core-carousel-controls__btn svg {
+.carousel-kit[data-axis="y"] .carousel-kit-controls__btn svg {
transform: rotate(90deg);
}
// Handle RTL + Vertical intersection if needed (optional)
-.core-carousel[data-axis="y"][dir="rtl"] .core-carousel-controls__btn svg {
+.carousel-kit[data-axis="y"][dir="rtl"] .carousel-kit-controls__btn svg {
transform: rotate(-90deg); // or 270deg
}
diff --git a/src/blocks/carousel/dots/block.json b/src/blocks/carousel/dots/block.json
index ad033cb..ca16f35 100644
--- a/src/blocks/carousel/dots/block.json
+++ b/src/blocks/carousel/dots/block.json
@@ -2,15 +2,15 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"version": "1.0.0",
- "name": "core-carousel/carousel-dots",
+ "name": "carousel-kit/carousel-dots",
"title": "Carousel Dots",
- "category": "core-carousel",
+ "category": "carousel-kit",
"icon": "ellipsis",
"ancestor": [
- "core-carousel/carousel"
+ "carousel-kit/carousel"
],
"description": "Navigation dots for the carousel.",
- "textdomain": "core-carousel",
+ "textdomain": "carousel-kit",
"attributes": {},
"supports": {
"interactivity": true
diff --git a/src/blocks/carousel/dots/edit.tsx b/src/blocks/carousel/dots/edit.tsx
index 1a3e8ac..d49060b 100644
--- a/src/blocks/carousel/dots/edit.tsx
+++ b/src/blocks/carousel/dots/edit.tsx
@@ -4,11 +4,11 @@ import { EditorCarouselContext } from '../editor-context';
import { useContext, useEffect, useRef, useState } from '@wordpress/element';
import type { EmblaCarouselType } from 'embla-carousel';
-const EMBLA_KEY = Symbol.for( 'core-carousel.carousel' );
+const EMBLA_KEY = Symbol.for( 'carousel-kit.carousel' );
export default function Edit() {
const blockProps = useBlockProps( {
- className: 'core-carousel-dots',
+ className: 'carousel-kit-dots',
} );
const { emblaApi: contextApi } = useContext( EditorCarouselContext );
@@ -20,7 +20,7 @@ export default function Edit() {
if ( ! ref.current ) {
return null;
}
- const wrapper = ref.current.closest( '.core-carousel' );
+ const wrapper = ref.current.closest( '.carousel-kit' );
if ( ! wrapper ) {
return null;
}
@@ -89,7 +89,7 @@ export default function Edit() {
{ dotsToRender.map( ( _, index ) => (
{
const api = contextApi || getEmblaFromDOM();
if ( api ) {
@@ -98,7 +98,7 @@ export default function Edit() {
} }
type="button"
/* translators: %d: slide number */
- aria-label={ sprintf( __( 'Go to slide %d', 'core-carousel' ), index + 1 ) }
+ aria-label={ sprintf( __( 'Go to slide %d', 'carousel-kit' ), index + 1 ) }
/>
) ) }
diff --git a/src/blocks/carousel/dots/save.tsx b/src/blocks/carousel/dots/save.tsx
index 5d6edbb..12ed235 100644
--- a/src/blocks/carousel/dots/save.tsx
+++ b/src/blocks/carousel/dots/save.tsx
@@ -2,7 +2,7 @@ import { useBlockProps } from '@wordpress/block-editor';
export default function Save() {
const blockProps = useBlockProps.save( {
- className: 'core-carousel-dots',
+ className: 'carousel-kit-dots',
} );
return (
@@ -11,7 +11,7 @@ export default function Save() {
block.name ) || [];
const blockProps = useBlockProps( {
- className: 'core-carousel',
+ className: 'carousel-kit',
dir: direction,
'data-axis': axis,
+ 'data-loop': loop ? 'true' : undefined,
style: {
- '--core-carousel-gap': `${ attributes.slideGap }px`,
- '--core-carousel-height': axis === 'y' ? height : undefined,
+ '--carousel-kit-gap': `${ attributes.slideGap }px`,
+ '--carousel-kit-height': axis === 'y' ? height : undefined,
} as React.CSSProperties,
} );
@@ -119,29 +120,29 @@ export default function Edit( {
return (
-
+
setAttributes( { loop: value } ) }
help={ __(
'Infinite scrolling of slides (Frontend only). Disabled in editor for stability.',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
setAttributes( { dragFree: value } ) }
- help={ __( 'Enables momentum scrolling.', 'core-carousel' ) }
+ help={ __( 'Enables momentum scrolling.', 'carousel-kit' ) }
/>
setAttributes( {
@@ -150,12 +151,12 @@ export default function Edit( {
}
/>
setAttributes( {
@@ -164,18 +165,18 @@ export default function Edit( {
}
help={ __(
'Prevents excess scrolling at the beginning or end.',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
setAttributes( { slidesToScroll: isAuto ? 'auto' : '1' } ) }
- help={ __( 'Scrolls the number of slides currently visible in the viewport.', 'core-carousel' ) }
+ help={ __( 'Scrolls the number of slides currently visible in the viewport.', 'carousel-kit' ) }
/>
{ slidesToScroll !== 'auto' && (
setAttributes( { slidesToScroll: ( value || 1 ).toString() } )
@@ -185,11 +186,11 @@ export default function Edit( {
/>
) }
setAttributes( {
@@ -198,15 +199,15 @@ export default function Edit( {
}
help={ __(
'Choose content direction. RTL is typically used for Arabic, Hebrew, and other right-to-left languages.',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
setAttributes( {
@@ -216,29 +217,29 @@ export default function Edit( {
/>
{ axis === 'y' && (
setAttributes( { height: value } ) }
help={ __(
'Set a fixed height for vertical carousel (e.g., 400px).',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
) }
setAttributes( { autoplay: value } ) }
/>
{ autoplay && (
<>
setAttributes( { autoplayDelay: value ?? 1000 } )
@@ -248,25 +249,25 @@ export default function Edit( {
step={ 100 }
/>
setAttributes( { autoplayStopOnInteraction: value } )
}
help={ __(
'Stop autoplay when user interacts with carousel.',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
setAttributes( { autoplayStopOnMouseEnter: value } )
}
help={ __(
'Stop autoplay when mouse hovers over carousel.',
- 'core-carousel',
+ 'carousel-kit',
) }
/>
>
@@ -275,12 +276,12 @@ export default function Edit( {
setAttributes( { ariaLabel: value } ) }
help={ __(
"Provide a descriptive label for screen readers (e.g., 'Featured Products').",
- 'core-carousel',
+ 'carousel-kit',
) }
/>
{ /* FormTokenField does not allow "help" prop */ }
@@ -289,13 +290,13 @@ export default function Edit( {
<>
{ __(
'Use this to allow only certain blocks in the slide. If empty, all blocks will be allowed.',
- 'core-carousel',
+ 'carousel-kit',
) }
>
}
>
-
+
setAttributes( { slideGap: value ?? 0 } ) }
min={ 0 }
diff --git a/src/blocks/carousel/editor-context.ts b/src/blocks/carousel/editor-context.ts
index 3cc12a0..9937ba0 100644
--- a/src/blocks/carousel/editor-context.ts
+++ b/src/blocks/carousel/editor-context.ts
@@ -25,10 +25,10 @@ const defaultValue: EditorCarouselContextType = {
carouselOptions: {},
};
-let context = window.__CORE_CAROUSEL_CONTEXT__;
+let context = window.__CAROUSEL_KIT_CONTEXT__;
if ( ! context ) {
context = createContext( defaultValue );
- window.__CORE_CAROUSEL_CONTEXT__ = context;
+ window.__CAROUSEL_KIT_CONTEXT__ = context;
}
export const EditorCarouselContext = context;
diff --git a/src/blocks/carousel/editor.scss b/src/blocks/carousel/editor.scss
index b6ed13f..efc8e99 100644
--- a/src/blocks/carousel/editor.scss
+++ b/src/blocks/carousel/editor.scss
@@ -1,7 +1,7 @@
/**
* Editor-only styles for Carousel
*/
-.core-carousel {
+.carousel-kit {
/* Ensure selectable area */
padding: 0.625rem;
border: 1px dashed #ccc;
diff --git a/src/blocks/carousel/index.ts b/src/blocks/carousel/index.ts
index 89493af..b38e3fc 100644
--- a/src/blocks/carousel/index.ts
+++ b/src/blocks/carousel/index.ts
@@ -19,12 +19,12 @@ registerBlockType( metadata as BlockConfiguration, {
const styles = [
{
name: 'default',
- label: __( 'Default (100%)', 'core-carousel' ),
+ label: __( 'Default (100%)', 'carousel-kit' ),
isDefault: true,
},
- { name: 'columns-2', label: __( '2 Columns (50%)', 'core-carousel' ) },
- { name: 'columns-3', label: __( '3 Columns (33%)', 'core-carousel' ) },
- { name: 'columns-4', label: __( '4 Columns (25%)', 'core-carousel' ) },
+ { name: 'columns-2', label: __( '2 Columns (50%)', 'carousel-kit' ) },
+ { name: 'columns-3', label: __( '3 Columns (33%)', 'carousel-kit' ) },
+ { name: 'columns-4', label: __( '4 Columns (25%)', 'carousel-kit' ) },
];
styles.forEach( ( style ) => registerBlockStyle( metadata.name, style ) );
diff --git a/src/blocks/carousel/save.tsx b/src/blocks/carousel/save.tsx
index a71ccc6..45ba944 100644
--- a/src/blocks/carousel/save.tsx
+++ b/src/blocks/carousel/save.tsx
@@ -49,22 +49,23 @@ export default function Save( {
canScrollPrev: false,
canScrollNext: false,
/* translators: %d: slide number */
- ariaLabelPattern: __( 'Go to slide %d', 'core-carousel' ),
+ ariaLabelPattern: __( 'Go to slide %d', 'carousel-kit' ),
};
const blockProps = useBlockProps.save( {
- className: 'core-carousel',
+ className: 'carousel-kit',
role: 'region',
'aria-roledescription': 'carousel',
'aria-label': ariaLabel,
dir: direction,
'data-axis': axis,
- 'data-wp-interactive': 'core-carousel/carousel',
+ 'data-loop': loop ? 'true' : undefined,
+ 'data-wp-interactive': 'carousel-kit/carousel',
'data-wp-context': JSON.stringify( context ),
'data-wp-init': 'callbacks.initCarousel', // Use init for mounting
style: {
- '--core-carousel-gap': `${ slideGap }px`,
- '--core-carousel-height': axis === 'y' ? height : undefined,
+ '--carousel-kit-gap': `${ slideGap }px`,
+ '--carousel-kit-height': axis === 'y' ? height : undefined,
} as React.CSSProperties,
} );
diff --git a/src/blocks/carousel/slide/block.json b/src/blocks/carousel/slide/block.json
index cefffd3..f56bcdc 100644
--- a/src/blocks/carousel/slide/block.json
+++ b/src/blocks/carousel/slide/block.json
@@ -2,18 +2,18 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"version": "1.0.0",
- "name": "core-carousel/carousel-slide",
+ "name": "carousel-kit/carousel-slide",
"title": "Carousel Slide",
- "category": "core-carousel",
+ "category": "carousel-kit",
"icon": "slides",
"parent": [
- "core-carousel/carousel-viewport"
+ "carousel-kit/carousel-viewport"
],
"description": "A single slide within the carousel.",
- "textdomain": "core-carousel",
+ "textdomain": "carousel-kit",
"attributes": {},
"usesContext": [
- "core-carousel/carousel/allowedSlideBlocks"
+ "carousel-kit/carousel/allowedSlideBlocks"
],
"editorScript": "file:./index.js"
}
\ No newline at end of file
diff --git a/src/blocks/carousel/slide/edit.tsx b/src/blocks/carousel/slide/edit.tsx
index 4367744..1ab72e6 100644
--- a/src/blocks/carousel/slide/edit.tsx
+++ b/src/blocks/carousel/slide/edit.tsx
@@ -5,9 +5,9 @@ export default function Edit( {
context,
}: {
attributes: CarouselSlideAttributes;
- context: { 'core-carousel/carousel/allowedSlideBlocks'?: string[] };
+ context: { 'carousel-kit/carousel/allowedSlideBlocks'?: string[] };
} ) {
- const allowedBlocks = context[ 'core-carousel/carousel/allowedSlideBlocks' ];
+ const allowedBlocks = context[ 'carousel-kit/carousel/allowedSlideBlocks' ];
const blockProps = useBlockProps( {
className: 'embla__slide',
diff --git a/src/blocks/carousel/slide/save.tsx b/src/blocks/carousel/slide/save.tsx
index 78319d7..1f74ebf 100644
--- a/src/blocks/carousel/slide/save.tsx
+++ b/src/blocks/carousel/slide/save.tsx
@@ -5,7 +5,7 @@ export default function Save() {
className: 'embla__slide',
role: 'group',
'aria-roledescription': 'slide',
- 'data-wp-interactive': 'core-carousel/carousel',
+ 'data-wp-interactive': 'carousel-kit/carousel',
'data-wp-class--is-active': 'callbacks.isSlideActive',
'data-wp-bind--aria-current': 'callbacks.isSlideActive',
} );
diff --git a/src/blocks/carousel/styles/_core.scss b/src/blocks/carousel/styles/_core.scss
index 13c01f7..e230bf7 100644
--- a/src/blocks/carousel/styles/_core.scss
+++ b/src/blocks/carousel/styles/_core.scss
@@ -1,68 +1,92 @@
-:where(.core-carousel) {
+:where(.carousel-kit) {
position: relative;
width: 100%;
- --core-carousel-slide-width: 100%;
+ --carousel-kit-slide-width: 100%;
}
-:where(.core-carousel) .embla {
+:where(.carousel-kit) .embla {
overflow: hidden;
}
/* Ensure the default container and Query Loop list are flex rows */
-:where(.core-carousel) .embla__container,
-:where(.core-carousel) .embla .wp-block-post-template {
+:where(.carousel-kit) .embla__container,
+:where(.carousel-kit) .embla .wp-block-post-template {
display: flex;
flex-wrap: nowrap;
width: 100%;
margin: 0;
padding: 0;
list-style: none;
- gap: 0;
grid-template-columns: none;
- gap: var(--core-carousel-gap, 0);
+ gap: var(--carousel-kit-gap, 0);
}
/* Ensure intermediate wrappers (like wp-block-query) don't shrink */
-:where(.core-carousel) .embla .wp-block-query {
+:where(.carousel-kit) .embla .wp-block-query {
width: 100%;
min-width: 100%;
}
/* Force slides (including posts) to respect a configurable width variable */
-:where(.core-carousel) .embla__slide,
-:where(.core-carousel) .embla .wp-block-post-template li {
+:where(.carousel-kit) .embla__slide,
+:where(.carousel-kit) .embla .wp-block-post-template li {
display: block;
- flex: 0 0 var(--core-carousel-slide-width, 100%);
- width: var(--core-carousel-slide-width, 100%);
- max-width: var(--core-carousel-slide-width, 100%);
+ flex: 0 0 var(--carousel-kit-slide-width, 100%);
+ width: var(--carousel-kit-slide-width, 100%);
+ max-width: var(--carousel-kit-slide-width, 100%);
min-width: 0;
box-sizing: border-box;
- /* Reset vertical margins to align slides */
+ /* Reset margins by default (use gap instead) */
+ margin-inline-end: 0;
margin-block-start: 0;
margin-block-end: 0;
}
+/**
+ * Fix for Embla Carousel Loop + Gap
+ * When looping is enabled, Embla v8 doesn't support CSS 'gap'.
+ * We switch to margin for consistent spacing in loop mode.
+ */
+:where(.carousel-kit[data-loop="true"]) .embla__container,
+:where(.carousel-kit[data-loop="true"]) .embla .wp-block-post-template {
+ gap: 0;
+}
+
+:where(.carousel-kit[data-loop="true"]) .embla__slide,
+:where(.carousel-kit[data-loop="true"]) .embla .wp-block-post-template li {
+ margin-inline-end: var(--carousel-kit-gap, 0);
+}
+
/* Vertical Axis adjustments */
-:where(.core-carousel[data-axis="y"]) {
+:where(.carousel-kit[data-axis="y"]) {
display: flex;
flex-direction: column;
}
-:where(.core-carousel[data-axis="y"]) .embla {
- height: var(--core-carousel-height);
+:where(.carousel-kit[data-axis="y"]) .embla {
+ height: var(--carousel-kit-height);
}
-:where(.core-carousel[data-axis="y"]) .embla__container {
+:where(.carousel-kit[data-axis="y"]) .embla__container {
flex-direction: column;
height: 100%;
min-height: 100%;
}
-:where(.core-carousel[data-axis="y"]) .embla__slide,
-:where(.core-carousel[data-axis="y"]) .embla .wp-block-post-template li {
- flex: 0 0 var(--core-carousel-slide-width, 100%);
+:where(.carousel-kit[data-axis="y"]) .embla__slide,
+:where(.carousel-kit[data-axis="y"]) .embla .wp-block-post-template li {
+ flex: 0 0 var(--carousel-kit-slide-width, 100%);
width: 100%;
max-width: 100%;
margin-inline-end: 0;
}
+
+/* Vertical + Loop specific */
+:where(.carousel-kit[data-axis="y"][data-loop="true"]) .embla__slide,
+:where(.carousel-kit[data-axis="y"][data-loop="true"])
+ .embla
+ .wp-block-post-template
+ li {
+ margin-block-end: var(--carousel-kit-gap, 0);
+}
diff --git a/src/blocks/carousel/styles/_variants.scss b/src/blocks/carousel/styles/_variants.scss
index b9acc43..87eb4fc 100644
--- a/src/blocks/carousel/styles/_variants.scss
+++ b/src/blocks/carousel/styles/_variants.scss
@@ -3,19 +3,19 @@
*/
/* 2 Columns */
-:where(.core-carousel).is-style-columns-2,
-:where(.core-carousel) .embla .wp-block-post-template.columns-2 {
- --core-carousel-slide-width: 50%;
+:where(.carousel-kit).is-style-columns-2,
+:where(.carousel-kit) .embla .wp-block-post-template.columns-2 {
+ --carousel-kit-slide-width: 50%;
}
/* 3 Columns */
-:where(.core-carousel).is-style-columns-3,
-:where(.core-carousel) .embla .wp-block-post-template.columns-3 {
- --core-carousel-slide-width: 33.333%;
+:where(.carousel-kit).is-style-columns-3,
+:where(.carousel-kit) .embla .wp-block-post-template.columns-3 {
+ --carousel-kit-slide-width: 33.333%;
}
/* 4 Columns */
-:where(.core-carousel).is-style-columns-4,
-:where(.core-carousel) .embla .wp-block-post-template.columns-4 {
- --core-carousel-slide-width: 25%;
+:where(.carousel-kit).is-style-columns-4,
+:where(.carousel-kit) .embla .wp-block-post-template.columns-4 {
+ --carousel-kit-slide-width: 25%;
}
diff --git a/src/blocks/carousel/view.ts b/src/blocks/carousel/view.ts
index 65da929..293aa22 100644
--- a/src/blocks/carousel/view.ts
+++ b/src/blocks/carousel/view.ts
@@ -10,7 +10,7 @@ type ElementWithRef = {
ref?: HTMLElement | null;
};
-const EMBLA_KEY = Symbol.for( 'core-carousel.carousel' );
+const EMBLA_KEY = Symbol.for( 'carousel-kit.carousel' );
type EmblaViewportElement = HTMLElement & {
[EMBLA_KEY]?: EmblaCarouselType;
@@ -35,7 +35,7 @@ const getEmblaFromElement = (
if ( ! element ) {
return null;
}
- const wrapper = element.closest( '.core-carousel' );
+ const wrapper = element.closest( '.carousel-kit' );
const viewport = wrapper?.querySelector(
'.embla',
) as EmblaViewportElement | null;
@@ -46,7 +46,7 @@ const getEmblaFromElement = (
return emblaInstances.get( viewport ) || viewport[ EMBLA_KEY ] || null;
};
-store( 'core-carousel/carousel', {
+store( 'carousel-kit/carousel', {
state: {
get canScrollPrev() {
const context = getContext();
diff --git a/src/blocks/carousel/viewport/block.json b/src/blocks/carousel/viewport/block.json
index 3276bfb..6951d52 100644
--- a/src/blocks/carousel/viewport/block.json
+++ b/src/blocks/carousel/viewport/block.json
@@ -2,15 +2,15 @@
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"version": "1.0.0",
- "name": "core-carousel/carousel-viewport",
+ "name": "carousel-kit/carousel-viewport",
"title": "Carousel Viewport",
- "category": "core-carousel",
+ "category": "carousel-kit",
"icon": "cover-image",
"parent": [
- "core-carousel/carousel"
+ "carousel-kit/carousel"
],
"description": "Viewport container for carousel slides.",
- "textdomain": "core-carousel",
+ "textdomain": "carousel-kit",
"attributes": {},
"supports": {
"interactivity": true
diff --git a/src/blocks/carousel/viewport/edit.tsx b/src/blocks/carousel/viewport/edit.tsx
index cab3d65..7f7d940 100644
--- a/src/blocks/carousel/viewport/edit.tsx
+++ b/src/blocks/carousel/viewport/edit.tsx
@@ -45,8 +45,8 @@ export default function Edit( {
},
{
orientation: carouselOptions?.axis === 'y' ? 'vertical' : 'horizontal',
- allowedBlocks: [ 'core-carousel/carousel-slide', 'core/query' ],
- template: [ [ 'core-carousel/carousel-slide' ] ],
+ allowedBlocks: [ 'carousel-kit/carousel-slide', 'core/query' ],
+ template: [ [ 'carousel-kit/carousel-slide' ] ],
},
);
@@ -56,7 +56,7 @@ export default function Edit( {
const { insertBlock } = useDispatch( 'core/block-editor' );
const addSlide = () => {
- const block = createBlock( 'core-carousel/carousel-slide' );
+ const block = createBlock( 'carousel-kit/carousel-slide' );
insertBlock( block, undefined, clientId );
};
@@ -81,7 +81,7 @@ export default function Edit( {
const options = carouselOptions as any;
embla = EmblaCarousel( emblaRef.current!, {
- loop: false,
+ loop: options?.loop ?? false,
dragFree: options?.dragFree ?? false,
containScroll: options?.containScroll || 'trimSnaps',
axis: options?.axis || 'x',
@@ -173,14 +173,14 @@ export default function Edit( {
-
+
- { __( 'Add Slide', 'core-carousel' ) }
+ { __( 'Add Slide', 'carousel-kit' ) }
diff --git a/src/types.d.ts b/src/types.d.ts
index d239a7e..f6eca72 100644
--- a/src/types.d.ts
+++ b/src/types.d.ts
@@ -3,7 +3,7 @@ import type React from 'react';
declare global {
interface Window {
- __CORE_CAROUSEL_CONTEXT__?: React.Context;
+ __CAROUSEL_KIT_CONTEXT__?: React.Context;
}
}
diff --git a/tests/js/setup.ts b/tests/js/setup.ts
index a95a3c0..41fd148 100644
--- a/tests/js/setup.ts
+++ b/tests/js/setup.ts
@@ -1,5 +1,5 @@
/**
- * Jest setup file for Core Carousel tests.
+ * Jest setup file for Carousel Kit tests.
*
* This file runs before each test file and sets up global mocks
* for WordPress and Embla Carousel dependencies.
diff --git a/tests/php/Unit/PluginTest.php b/tests/php/Unit/PluginTest.php
index 7d60751..50636dc 100644
--- a/tests/php/Unit/PluginTest.php
+++ b/tests/php/Unit/PluginTest.php
@@ -9,17 +9,17 @@
* - Block pattern registration and caching
* - Error handling and edge cases
*
- * @package Core_Carousel\Tests\Unit
+ * @package Carousel_Kit\Tests\Unit
*/
declare(strict_types=1);
-namespace Core_Carousel\Tests\Unit;
+namespace Carousel_Kit\Tests\Unit;
use Brain\Monkey\Actions;
use Brain\Monkey\Filters;
use Brain\Monkey\Functions;
-use Core_Carousel\Plugin;
+use Carousel_Kit\Plugin;
/**
* Tests for the Plugin class.
@@ -84,8 +84,8 @@ public function test_register_block_category_adds_category(): void {
$result = $this->invokeMethod( $instance, 'register_block_category', [ $existing_categories ] );
$this->assertCount( 2, $result );
- $this->assertSame( 'core-carousel', $result[1]['slug'] );
- $this->assertSame( 'Core Carousel', $result[1]['title'] );
+ $this->assertSame( 'carousel-kit', $result[1]['slug'] );
+ $this->assertSame( 'Carousel Kit', $result[1]['title'] );
}
/**
@@ -114,7 +114,7 @@ public function test_register_block_category_preserves_existing(): void {
$this->assertCount( 3, $result );
$this->assertSame( 'media', $result[0]['slug'] );
$this->assertSame( 'design', $result[1]['slug'] );
- $this->assertSame( 'core-carousel', $result[2]['slug'] );
+ $this->assertSame( 'carousel-kit', $result[2]['slug'] );
}
/**
@@ -129,7 +129,7 @@ public function test_register_block_category_with_empty_array(): void {
$result = $this->invokeMethod( $instance, 'register_block_category', [ [] ] );
$this->assertCount( 1, $result );
- $this->assertSame( 'core-carousel', $result[0]['slug'] );
+ $this->assertSame( 'carousel-kit', $result[0]['slug'] );
}
/**
@@ -217,7 +217,7 @@ public function test_register_pattern_category_registers_category(): void {
Functions\expect( 'register_block_pattern_category' )
->once()
->with(
- 'core-carousel',
+ 'carousel-kit',
\Mockery::type( 'array' )
)
->andReturnUsing(
@@ -246,7 +246,7 @@ public function test_register_pattern_category_includes_label(): void {
Functions\expect( 'register_block_pattern_category' )
->once()
->with(
- 'core-carousel',
+ 'carousel-kit',
\Mockery::on(
function ( $args ) use ( &$captured_args ): bool {
$captured_args = $args;
@@ -261,7 +261,7 @@ function ( $args ) use ( &$captured_args ): bool {
$this->assertIsArray( $captured_args );
$this->assertNotNull( $captured_args );
$this->assertArrayHasKey( 'label', $captured_args );
- $this->assertSame( 'Core Carousel', $captured_args['label'] );
+ $this->assertSame( 'Carousel Kit', $captured_args['label'] );
}
/**
@@ -272,7 +272,7 @@ function ( $args ) use ( &$captured_args ): bool {
public function test_register_block_patterns_uses_cache(): void {
$cached_patterns = [
[
- 'slug' => 'core-carousel/test-pattern',
+ 'slug' => 'carousel-kit/test-pattern',
'args' => [
'title' => 'Test Pattern',
'content' => 'Test
',
@@ -285,12 +285,12 @@ public function test_register_block_patterns_uses_cache(): void {
Functions\when( '__' )->returnArg();
Functions\expect( 'get_transient' )
->once()
- ->with( 'core_carousel_patterns_cache' )
+ ->with( 'carousel_kit_patterns_cache' )
->andReturn( $cached_patterns );
Functions\expect( 'register_block_pattern' )
->once()
- ->with( 'core-carousel/test-pattern', \Mockery::type( 'array' ) )
+ ->with( 'carousel-kit/test-pattern', \Mockery::type( 'array' ) )
->andReturnUsing(
function () use ( &$pattern_registered ): void {
$pattern_registered = true;
@@ -311,7 +311,7 @@ function () use ( &$pattern_registered ): void {
public function test_register_block_patterns_handles_empty(): void {
Functions\expect( 'get_transient' )
->once()
- ->with( 'core_carousel_patterns_cache' )
+ ->with( 'carousel_kit_patterns_cache' )
->andReturn( [] );
Functions\expect( 'register_block_pattern' )->never();
@@ -331,21 +331,21 @@ public function test_register_block_patterns_handles_empty(): void {
public function test_register_block_patterns_registers_multiple(): void {
$cached_patterns = [
[
- 'slug' => 'core-carousel/pattern-one',
+ 'slug' => 'carousel-kit/pattern-one',
'args' => [
'title' => 'Pattern One',
'content' => 'One
',
],
],
[
- 'slug' => 'core-carousel/pattern-two',
+ 'slug' => 'carousel-kit/pattern-two',
'args' => [
'title' => 'Pattern Two',
'content' => 'Two
',
],
],
[
- 'slug' => 'core-carousel/pattern-three',
+ 'slug' => 'carousel-kit/pattern-three',
'args' => [
'title' => 'Pattern Three',
'content' => 'Three
',
@@ -372,9 +372,9 @@ function ( $slug ) use ( &$registered_patterns ): void {
$this->invokeMethod( $instance, 'register_block_patterns' );
$this->assertCount( 3, $registered_patterns );
- $this->assertContains( 'core-carousel/pattern-one', $registered_patterns );
- $this->assertContains( 'core-carousel/pattern-two', $registered_patterns );
- $this->assertContains( 'core-carousel/pattern-three', $registered_patterns );
+ $this->assertContains( 'carousel-kit/pattern-one', $registered_patterns );
+ $this->assertContains( 'carousel-kit/pattern-two', $registered_patterns );
+ $this->assertContains( 'carousel-kit/pattern-three', $registered_patterns );
}
/**
@@ -386,7 +386,7 @@ public function test_register_block_patterns_handles_invalid_structure(): void {
// Pattern missing 'args' key
$cached_patterns = [
[
- 'slug' => 'core-carousel/valid-pattern',
+ 'slug' => 'carousel-kit/valid-pattern',
'args' => [
'title' => 'Valid',
'content' => 'Valid
',
diff --git a/tests/php/Unit/Traits/SingletonTest.php b/tests/php/Unit/Traits/SingletonTest.php
index 92511a6..51337cf 100644
--- a/tests/php/Unit/Traits/SingletonTest.php
+++ b/tests/php/Unit/Traits/SingletonTest.php
@@ -2,16 +2,16 @@
/**
* Unit tests for the Singleton trait.
*
- * @package Core_Carousel\Tests\Unit\Traits
+ * @package Carousel_Kit\Tests\Unit\Traits
*/
declare(strict_types=1);
-namespace Core_Carousel\Tests\Unit\Traits;
+namespace Carousel_Kit\Tests\Unit\Traits;
use Brain\Monkey\Actions;
-use Core_Carousel\Tests\Unit\UnitTestCase;
-use Core_Carousel\Traits\Singleton;
+use Carousel_Kit\Tests\Unit\UnitTestCase;
+use Carousel_Kit\Traits\Singleton;
/**
* Test class A for singleton tests.
@@ -56,7 +56,7 @@ class SingletonTest extends UnitTestCase {
* @return void
*/
public function test_get_instance_returns_instance(): void {
- Actions\expectDone( 'core_carousel_singleton_init_' . SingletonTestClassA::class )->once();
+ Actions\expectDone( 'carousel_kit_singleton_init_' . SingletonTestClassA::class )->once();
$instance = SingletonTestClassA::get_instance();
@@ -69,7 +69,7 @@ public function test_get_instance_returns_instance(): void {
* @return void
*/
public function test_get_instance_returns_same_instance(): void {
- Actions\expectDone( 'core_carousel_singleton_init_' . SingletonTestClassB::class )->once();
+ Actions\expectDone( 'carousel_kit_singleton_init_' . SingletonTestClassB::class )->once();
$instance1 = SingletonTestClassB::get_instance();
$instance2 = SingletonTestClassB::get_instance();
@@ -83,7 +83,7 @@ public function test_get_instance_returns_same_instance(): void {
* @return void
*/
public function test_constructor_is_called(): void {
- Actions\expectDone( 'core_carousel_singleton_init_' . SingletonTestClassC::class )->once();
+ Actions\expectDone( 'carousel_kit_singleton_init_' . SingletonTestClassC::class )->once();
$instance = SingletonTestClassC::get_instance();
diff --git a/tests/php/Unit/UnitTestCase.php b/tests/php/Unit/UnitTestCase.php
index da71133..a4ecbe0 100644
--- a/tests/php/Unit/UnitTestCase.php
+++ b/tests/php/Unit/UnitTestCase.php
@@ -1,13 +1,13 @@