Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
v20.12.0
v20
44 changes: 44 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [1.1.0-beta.1] - 2025-11-28

### Added

- **Custom ID Generator** - Added `idGenerator` option to `StrapiLoaderOptions` allowing custom ID generation from item data instead of using Strapi's `documentId` (#17)
- **Multiple Collections from Same Endpoint** - Added `collectionName` option to create multiple collections from the same Strapi content type with different configurations (#18)
- **Locale Support** - Added `locale` option supporting both single locale (string) and multiple locales (array) for i18n implementations (#19)
- Single locale: Fetch content for one specific language
- Multiple locales: Fetch all specified languages with locale-prefixed IDs
- Automatic `_locale` field added to stored items
- Comprehensive test suite with 27 new tests covering all new features

### Changed

- `StrapiLoaderOptions` interface extended with new optional fields: `collectionName`, `idGenerator`, and `locale`
- `StrapiCollection` interface extended to support new loader options
- `generateCollection` function updated to pass new options to loader

### Fixed

- N/A

### Breaking Changes

- None - fully backward compatible with existing implementations

## [1.0.x] - 2024-XX-XX

### Initial Release

- Basic Strapi loader functionality
- Automatic data loading from Strapi Content API
- Query, filtering and population capabilities
- Authorization token support
- Astro collections system integration
- TypeScript typing support

215 changes: 210 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ yarn add @sensinum/astro-strapi-loader
* Authorization token support
* Astro collections system integration
* TypeScript typing
* **πŸ†• Custom ID generation** - Generate collection IDs from custom fields (e.g., slugs)
* **πŸ†• Multiple collections** - Create multiple collections from same endpoint
* **πŸ†• i18n support** - Built-in locale support for multilingual content

## πŸ–₯️ Usage

Expand All @@ -70,13 +73,16 @@ try {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
}, [{ // leave empty [] to fetch all the collections based on default Strapi settings
name: "my-collection",
name: "homepage",
query: {
populate: {
// ...
},
populate: { seo: true },
},
}, 'yet-another-collection']);
}, {
name: "layout",
query: {
populate: { header: true, footer: true },
},
}, 'simple-collection-name']); // Can also pass just strings
} catch (error) {
console.error(error);
}
Expand All @@ -86,6 +92,8 @@ export const collections = {
};
```

> **βœ… Backward Compatible:** Existing code works without any changes!

2. Use in your Astro component:

```jsx
Expand Down Expand Up @@ -131,9 +139,206 @@ const myCollection = await fetchContent({
|--------|------|----------|-------------|
| `url` | `string` | Yes | Strapi API URL |
| `token` | `string` | No | Strapi API access token |
| `collectionName` | `string` | No | Custom collection name (for multiple collections from same endpoint) |
| `idGenerator` | `function` | No | Custom function to generate IDs from item data |
| `locale` | `string \| string[]` | No | Single locale or array of locales for i18n support |

> **⚠️ Note:** The token must have **read access** to both the **Content API** and the **Content-Type Builder API** *(ONLY to the "Get Content Types" endpoint)*.

### Mixing 1.0.x and 1.1.0+

You can mix old (simple) and new (extended) format in a single `generateCollections` call:

```typescript
strapiCollections = await generateCollections({
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
}, [
// βœ… Old format - works as before
{
name: "homepage",
query: { populate: { seo: true } }
},
{
name: "layout",
query: { populate: { header: true, footer: true } }
},

// βœ… 1.1.0+ - with locale support
{
name: "pages",
collectionName: "pagesEN",
locale: "en",
query: { sort: ['publishedAt:desc'] }
},
{
name: "pages", // Same endpoint, different config!
collectionName: "pagesDE",
locale: "de",
query: { sort: ['publishedAt:desc'] }
},

// βœ… 1.1.0+ - with custom ID
{
name: "blog-posts",
idGenerator: (data) => data.slug as string,
query: { filters: { published: true } }
},

// βœ… 1.1.0+ - combining all features
{
name: "articles",
collectionName: "articlesMultilang",
locale: ["en", "de", "fr"],
idGenerator: (data) => data.slug as string
}
]);

// Result collections:
// - homepage (old format)
// - layout (old format)
// - pagesEN (1.1.0+)
// - pagesDE (1.1.0+)
// - blog-posts (1.1.0+)
// - articlesMultilang (1.1.0+)
```

### Advanced Usage Examples

#### Custom ID Generation

Use slugs or custom fields as collection IDs instead of Strapi's `documentId`:

**Option A:** Using `generateCollections`:

```typescript
strapiCollections = await generateCollections({
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
}, [{
name: "pages",
idGenerator: (data) => data.slug as string,
query: { populate: { seo: true } }
}]);

// Now you can use: getEntry('pages', 'about-us')
```

**Option B:** Using `strapiLoader` directly:

```typescript
import { strapiLoader } from '@sensinum/astro-strapi-loader';
import { defineCollection, z } from 'astro:content';

const pages = defineCollection({
loader: strapiLoader('pages', {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
idGenerator: (data) => data.slug as string
}),
schema: z.object({
slug: z.string(),
title: z.string(),
content: z.string()
})
});
```

#### Multiple Collections from Same Endpoint

**Option A:** Using `generateCollections` (recommended for multiple collections):

```typescript
strapiCollections = await generateCollections({
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
}, [{
name: "pages",
collectionName: "pagesEN",
locale: "en",
query: { sort: ['publishedAt:desc'] }
}, {
name: "pages", // Same endpoint!
collectionName: "pagesDE",
locale: "de",
query: { sort: ['publishedAt:desc'] }
}]);

// Now you have both 'pagesEN' and 'pagesDE' collections
```

**Option B:** Using `strapiLoader` directly:

```typescript
const pagesEN = defineCollection({
loader: strapiLoader('pages', {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
collectionName: 'pagesEN',
locale: 'en'
}),
schema: pageSchema
});

const pagesDE = defineCollection({
loader: strapiLoader('pages', {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
collectionName: 'pagesDE',
locale: 'de'
}),
schema: pageSchema
});

export const collections = { pagesEN, pagesDE };
```

#### Multiple Locales in Single Collection

Fetch all language versions in one collection:

```typescript
const pagesMultilang = defineCollection({
loader: strapiLoader('pages', {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
locale: ['en', 'de', 'fr'] // Array of locales
}),
schema: z.object({
title: z.string(),
content: z.string(),
_locale: z.string() // Automatically added by loader
})
});

// Access by locale-prefixed ID
const page = await getEntry('pagesMultilang', 'en:documentId');

// Or filter by locale
const allPages = await getCollection('pagesMultilang');
const enPages = allPages.filter(p => p.data._locale === 'en');
```

#### Combining All Features

```typescript
const blogMultilang = defineCollection({
loader: strapiLoader('blog-posts', {
url: import.meta.env.STRAPI_URL,
token: import.meta.env.STRAPI_TOKEN,
collectionName: 'blogAllLanguages',
locale: ['en', 'de', 'fr'],
idGenerator: (data) => data.slug as string
}, {
sort: ['publishedAt:desc'],
filters: { status: { $eq: 'published' } }
}),
schema: blogSchema
});

// Access: getEntry('blogAllLanguages', 'en:my-post-slug')
```

### Query Options

| Option | Type | Description | Documentation |
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sensinum/astro-strapi-loader",
"version": "1.0.11",
"version": "1.1.0-beta.1",
"description": "Astro loader for Strapi CMS",
"keywords": [
"astro",
Expand Down
Loading