npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@gruodis/slug-for-strapi

v1.2.7

Published

Does what it says. Slug for Strapi.

Downloads

755

Readme

Slug For Strapi

🚀 Installation

npm install @gruodis/slug-for-strapi
# or
yarn add @gruodis/slug-for-strapi

Config

config/plugins.ts:

module.exports = {
  'slug-for-strapi': {
    enabled: true,
    resolve: './node_modules/@gruodis/slug-for-strapi', // Path to the plugin
    config: {
      enabled: true,                    // Enable/disable plugin globally
      sourceField: 'title',             // Primary field to generate slug from
      fallbackField: 'name',            // Fallback field if primary is empty
      addSuffixForUnique: true,         // Add suffixes for uniqueness
      skipGenerationField: 'skipSlugGeneration', // Field to check if slug generation should be skipped (optional)
      updateExistingSlugs: true,        // Update existing slugs when title changes
      slugifyOptions: {
        lower: true,
        strict: true,
        locale: 'lt'
      },
      defaultPopulateDepth: 5,          // Default depth for deep populate (optional, default: 5)
      populateDepth: {                  // Per-content-type depth overrides (optional)
        'api::article.article': 10,
        'api::category.category': 2
      },
      populatePatterns: {               // Per-content-type custom populate objects (optional)
        'api::main-page.main-page': {
          heroCardCarousel: {
            populate: {
              heroCards: true,
            },
          },
          // ... more complex populate logic
        }
      }
    }
  }
};

📖 Usage

  1. Add a slug field to any content type in your Strapi schema
  2. Create or edit entries - slugs will be automatically generated from title or name fields
  3. String support - Works with regular string fields

Example Content Type Schema

{
  "kind": "collectionType",
  "collectionName": "articles",
  "info": {
    "singularName": "article",
    "pluralName": "articles",
    "displayName": "Articles"
  },
  "attributes": {
    "title": {
      "type": "string"
    },
    "slug": {
      "type": "uid",
      "targetField": "title"
    },
    "skipSlugGeneration": {
      "type": "boolean",
      "default": false
    }
  }
}

🔒 Manual Slug Override (Locking)

To prevent the slug from being auto-updated when you edit the title, you can "lock" it.

  1. Add a Boolean field to your content type (e.g., named skipSlugGeneration).
  2. Enable this field in the "Configure the view" section of your Content Manager (e.g., place it next to the slug).
  3. When checking this box, the plugin will not regenerate the slug, preserving whatever value is in the slug field.

You can customize the field name in the plugin configuration:

    config: {
      // ...
      skipGenerationField: 'myCustomLockField', // Default is 'skipSlugGeneration'
    }

🔧 API Endpoints

🔍 Find By Slug

For every content type with a generated slug, the plugin automatically creates a GET endpoint:

  • GET /api/:pluralApiId/slug/:slug

Features:

  • Deep Populate by Default: The endpoint automatically populates all nested components, dynamic zones, and relations up to a configurable depth (default: 5 levels deep).
  • Localized: Respects the requested locale.
  • Draft/Published: Respects the publicationState parameter (default: live).
  • Sanitized: Response is sanitized to remove sensitive fields based on user permissions.

Example:

  • GET /api/articles/slug/my-awesome-article

Response:

{
  "data": {
    "id": 1,
    "documentId": "...",
    "title": "My Awesome Article",
    "slug": "my-awesome-article",
    "seo": { ... }, // Populated component
    "blocks": [ ... ], // Populated dynamic zone
    "author": { ... }, // Populated relation
    ...
  }
}

Note: These endpoints are read-only and public by default. You can control the depth of population globally or per-content-type using the plugin configuration (defaultPopulateDepth and populateDepth), or provide a custom populate schema using populatePatterns.

⚙️ Advanced Configuration

Custom Populate Patterns

If populateDepth is not flexible enough, you can define exact populate objects for specific content types using populatePatterns. This is useful for single types or complex components structures where you need granular control.

Note: This affects both the findBySlug endpoint (/api/:pluralApiId/slug/:slug) AND the standard find / findOne endpoints (/api/:pluralApiId and /api/:pluralApiId/:documentId) for that content type, automatically injecting the populate schema if no other populate parameter is provided.

// config/plugins.ts
'slug-for-strapi': {
  config: {
    // ...
    populatePatterns: {
      'api::main-page.main-page': {
        heroCardCarousel: {
          populate: {
            heroCards: true,
          },
        },
        seo: {
          fields: ['metaTitle', 'metaDescription'],
          populate: { shareImage: true }
        }
      },
      // Example with top-level fields restriction:
      'api::calendar-event.calendar-event': {
        fields: ['title', 'slug', 'publishDate'],
        populate: {
          tags: true,
          author: {
            fields: ['name', 'email']
          }
        }
      }
    }
  }
}

🏗️ Modular Configuration & Reusability

For large projects with many content types, you can split your configuration into multiple files and reuse common patterns (like SEO or Image population) to avoid repetition.

1. Create a directory structure (e.g., config/slug/):

config/
└── slug/
    ├── common.ts         # Shared patterns (SEO, Images)
    ├── pages.ts          # Page-specific patterns
    ├── blog.ts           # Blog-specific patterns
    └── index.ts          # Main entry point

2. Define shared patterns in config/slug/common.ts:

export const seoPopulate = {
  seo: {
    fields: ['metaTitle', 'metaDescription'],
    populate: { shareImage: true }
  }
};

export const imagePopulate = {
  fields: ['name', 'url', 'alternativeText', 'width', 'height']
};

3. Use them in feature-specific files (e.g., config/slug/blog.ts):

import { seoPopulate, imagePopulate } from './common';

export const blogPatterns = {
  'api::article.article': {
    populate: {
      ...seoPopulate,
      coverImage: {
        populate: imagePopulate
      },
      author: {
        fields: ['name'],
        populate: { avatar: true }
      }
    }
  }
};

4. Aggregate everything in config/slug/index.ts:

import { blogPatterns } from './blog';
import { pagePatterns } from './pages';

export const populatePatterns = {
  ...blogPatterns,
  ...pagePatterns,
};

export const populateDepth = {
  'api::article.article': 10,
  // ...
};

5. Import in config/plugins.ts:

import { populatePatterns, populateDepth } from './slug';

export default ({ env }) => ({
  // ...
  'slug-for-strapi': {
    // ...
    config: {
      populatePatterns,
      populateDepth
    }
  }
});

📝 Field Types Supported

Regular String

{
  "title": "My Article Title"
}

Will generate: my-article-title

Multi-locale Support

The plugin supports different locales for transliteration. You can change the locale in your config/plugins.ts.

🔧 Development



# Install dependencies
npm install

# Build the plugin
npm run build

📄 License

MIT License.