slugify

package module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 4, 2026 License: MIT Imports: 20 Imported by: 0

README

Slugify

Generate PocketBase slugs from one or more record fields.

The plugin combines configured input fields in order, normalizes the text to lowercase alphanumeric segments separated by hyphens, truncates the result to the configured length, and adds numeric suffixes when needed to keep slugs unique.

Installation

Build PocketBase with the plugin:

xpb build --with github.com/mjadobson/pb-plugin-slug@latest

Setup

On startup the plugin creates a shared _plugins collection if it doesn't already exist.

Create or update the slugify row in _plugins with:

  • plugin_name: slugify
  • enabled: true or false
  • config: JSON config

Example config value:

[
  {
    "collection_name": "posts",
    "input_fields": ["title", "docs.name"],
    "output_field": "slug",
    "length": 64,
    "recalculate": true
  },
  {
    "collection_name": "pages",
    "input_fields": ["title"],
    "output_field": "slug",
    "length": 32
  }
]

Then make sure each target collection has:

  • the fields listed in input_fields
  • a text or editor field matching output_field
  • a single-column UNIQUE index on output_field (recommended with WHERE output_field != '')

The plugin runs after successful record create and update operations. It reloads its active config whenever any row in _plugins is created, updated, or deleted. It also reloads when collections are created, updated, or deleted so deferred configs can become active after schema changes. It does not backfill slugs for existing records unless you set recalculate: true on a config entry.

Unique Index Requirement

output_field must have its own single-column unique index.

This plugin checks for existing slugs before saving, but concurrent writes can still race unless the database also enforces uniqueness. The unique index is what guarantees two records cannot end up with the same slug.

For SQLite-backed PocketBase collections, a good pattern is:

CREATE UNIQUE INDEX `idx_posts_slug_unique` ON `posts` (`slug`) WHERE `slug` != ''

Replace posts and slug with your collection and field names.

Plugin Config

[].collection_name

The PocketBase collection name to watch.

[].input_fields

The fields to combine, in order, before generating the slug.

Use dotted paths such as docs.name to pull values from related collections. Intermediate segments must be relation fields.

[].output_field

The text or editor field where the slug should be written.

[].length

The maximum slug length.

[].recalculate

Optional. When set to true, the plugin rewrites that config entry to recalculating: true, recalculates matching records in batches of 100, and then removes recalculating when the pass finishes.

Behaviour

  • Input field values are joined with spaces in config order.
  • Array-like input values are flattened and joined with spaces before slugging.
  • Accents are removed where possible.
  • Non-alphanumeric characters become hyphens.
  • Repeated separators are collapsed and trimmed.
  • Slugs are lowercased and truncated to length.
  • If the slug already exists in the same collection, -1, -2, and so on are appended while staying within length.
  • If all configured inputs are blank, the output slug is cleared.
  • The output field must have its own unique index so concurrent writes cannot create duplicate slugs.
  • Invalid config entries are skipped individually so valid rules can continue to run.

Development

go mod tidy
GOCACHE=/tmp/go-build go test ./...
GOCACHE=/tmp/go-build go build ./...

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Plugin

type Plugin struct {
	// contains filtered or unexported fields
}

func (*Plugin) Description

func (p *Plugin) Description() string

func (*Plugin) Init

func (p *Plugin) Init(app core.App) error

func (*Plugin) Name

func (p *Plugin) Name() string

func (*Plugin) Version

func (p *Plugin) Version() string

type SlugConfig

type SlugConfig struct {
	CollectionName string   `json:"collection_name"`
	InputFields    []string `json:"input_fields"`
	OutputField    string   `json:"output_field"`
	Length         int      `json:"length"`
	Recalculate    bool     `json:"recalculate,omitempty"`
	Recalculating  bool     `json:"recalculating,omitempty"`
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL