{"id":36971447,"url":"https://github.com/wazum/sluggi","last_synced_at":"2026-04-19T12:01:19.700Z","repository":{"id":37733912,"uuid":"175367692","full_name":"wazum/sluggi","owner":"wazum","description":"TYPO3 CMS URL path \u0026 slug manager — auto-sync, redirects, locking, access control, duplicate prevention \u0026 more","archived":false,"fork":false,"pushed_at":"2026-04-19T07:22:21.000Z","size":3755,"stargazers_count":40,"open_issues_count":0,"forks_count":29,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-04-19T08:32:10.136Z","etag":null,"topics":["cms","extension","path","php","realurl","redirects","seo","slug","typo3","typo3-cms","typo3-cms-extension","typo3-extension","url","url-management"],"latest_commit_sha":null,"homepage":"https://wazum.github.io/sluggi/","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/wazum.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"custom":["https://www.paypal.me/wazum","https://smile.amazon.de/hz/wishlist/ls/307SIOOD654GF/"]}},"created_at":"2019-03-13T07:22:22.000Z","updated_at":"2026-04-19T06:47:18.000Z","dependencies_parsed_at":"2024-06-12T15:43:55.454Z","dependency_job_id":"3d6f26d2-066b-406e-9fc5-9749845c8e7a","html_url":"https://github.com/wazum/sluggi","commit_stats":{"total_commits":12,"total_committers":2,"mean_commits":6.0,"dds":0.08333333333333337,"last_synced_commit":"8382d2e43d2979d677b466c1c73628996a249bb4"},"previous_names":[],"tags_count":80,"template":false,"template_full_name":null,"purl":"pkg:github/wazum/sluggi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazum%2Fsluggi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazum%2Fsluggi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazum%2Fsluggi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazum%2Fsluggi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/wazum","download_url":"https://codeload.github.com/wazum/sluggi/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/wazum%2Fsluggi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32005831,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-18T20:23:30.271Z","status":"online","status_checked_at":"2026-04-19T02:00:07.110Z","response_time":55,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cms","extension","path","php","realurl","redirects","seo","slug","typo3","typo3-cms","typo3-cms-extension","typo3-extension","url","url-management"],"created_at":"2026-01-13T21:53:44.938Z","updated_at":"2026-04-19T12:01:19.649Z","avatar_url":"https://github.com/wazum.png","language":"PHP","funding_links":["https://www.paypal.me/wazum","https://smile.amazon.de/hz/wishlist/ls/307SIOOD654GF/"],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"Resources/Public/Icons/Extension.svg\" alt=\"sluggi\" width=\"80\" height=\"80\"\u003e\n\u003c/p\u003e\n\u003ch1 align=\"center\"\u003esluggi\u003c/h1\u003e\n\u003cp align=\"center\"\u003e\u003cem\u003eThe URL Path Manager TYPO3 CMS deserves.\u003c/em\u003e\u003c/p\u003e\n\u003cbr\u003e\n\n[![Tests](https://github.com/wazum/sluggi/workflows/Tests/badge.svg)](https://github.com/wazum/sluggi/actions)\n[![PHP](https://img.shields.io/badge/PHP-8.2%20|%208.3%20|%208.4-blue.svg)](https://www.php.net/)\n[![TYPO3](https://img.shields.io/badge/TYPO3-12.4%20|%2013.4.26%2B%20|%2014-orange.svg)](https://typo3.org/)\n[![Total Downloads](https://img.shields.io/packagist/dt/wazum/sluggi.svg)](https://packagist.org/packages/wazum/sluggi)\n[![GitHub Stars](https://img.shields.io/github/stars/wazum/sluggi?style=flat)](https://github.com/wazum/sluggi/stargazers)\n[![License](https://img.shields.io/badge/License-GPL%20v2-blue.svg)](LICENSE)\n\nURLs that stay in sync when titles change. Automatic redirects. Duplicate prevention on copy, move, and recycler restore. Locking, access control, conflict detection – everything you need to manage URL paths with confidence.\n\n\u003e [!NOTE]\n\u003e **TYPO3 13.4** has a core bug where `TemporaryPermissionMutationService` does not grant page-level access for redirect storage. Non-admin editors without the site root page in their webmounts cannot create redirects on slug changes. Sluggi includes a workaround; this does not affect TYPO3 12 or 14.\n\nOne `composer require`, sensible defaults – [highly configurable](#configuration) when you need it.\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://wazum.github.io/sluggi/\"\u003e\u003cstrong\u003eTry the interactive demo\u003c/strong\u003e\u003c/a\u003e\u003cbr\u003e\n  See every feature live in your browser – no installation required.\n\u003c/p\u003e\n\n## Installation\n\n```bash\ncomposer require wazum/sluggi\n```\n\n\u003e **Version 14** is a complete rewrite of _sluggi_ – modern, fully tested, and **compatible** with **TYPO3 12.4, 13.4.26+, and 14**.\n\u003e \n\u003e This is the version you should install regardless of your TYPO3 version. Previous major versions are no longer maintained.\n\n## What You Get\n\n![sluggi editor](Documentation/sluggi_full_editor_view.png)\n\n**Automatic sync** – Rename a page, the URL updates. All child pages follow. Redirects are created automatically.\n\n**Conflict detection** – Duplicate URLs are caught instantly with unique alternatives proposed.\n\n**Locking** – Pin critical URLs so nobody accidentally breaks them.\n\n**Access control** – Let editors change the last segment only, or restrict editing based on their page tree permissions.\n\n**Duplicate prevention** – Unique slugs on copy, move, and recycler restore. No more 500 errors from slug collisions.\n\n**Redirect control** – Editors choose whether to create redirects when changing a URL.\n\n**Redirect info** – See how many redirects point to a page, with a direct link to manage them.\n\n**Any table** – Works with pages, news, events, or any record with a TCA slug field.\n\n## Features\n\n### Modern URL Path Editor\n\nOut of the box, _sluggi_ replaces the default slug field with a clean, focused interface:\n\n![Default view](Documentation/sluggi_default_view.png)\n\n### Auto-Sync: Change a Title, Update the URL\n\nWhen sync is enabled, URL paths regenerate automatically when source fields (e.g. title, nav_title) change. A badge on the source field shows it drives the URL:\n\n![Sync badge](Documentation/sluggi_sync.png)\n\n- Per-record sync toggle – disable it for pages or records with manually crafted URLs\n- Child pages update recursively when a parent path changes\n- Redirects from old to new URL are created automatically via EXT:redirects\n- Works for any table with a slug field (news, events, custom records)\n\n### Lock URLs to Prevent Accidental Changes\n\n![Locked URL](Documentation/sluggi_lock.png)\n\n- Locked URLs cannot be edited and are skipped during auto-sync\n- Optionally lock all descendant paths when an ancestor is locked\n- Editing the full path auto-locks it to prevent sync from overwriting your work\n\n### Translated Pages\n\n![Translated page](Documentation/sluggi_translated.png)\n\nTranslated pages inherit the sync and lock settings from the default language record. The toggles are disabled and display the parent's state – translations cannot override these flags independently. This ensures consistent URL behavior across all language versions.\n\n### Non-Page Tables (News, Events, Custom Records)\n\n![Non-page table sync](Documentation/sluggi_non_page_sync.png)\n\nTables configured in `synchronize_tables` (e.g. `tx_news_domain_model_news`) get the same per-record sync toggle as pages. Editors can disable auto-sync for individual records where they've manually crafted a slug for SEO:\n\n- Sync defaults to **on** for new records – slugs auto-generate from source fields\n- Toggle sync **off** to keep a hand-crafted slug that won't change when the title is edited\n- Source field badges appear when sync is active, showing which fields drive the slug\n- Translated records inherit the sync state from their default language parent\n- Sync state is stored in a separate reference table – no changes to your extension's database schema\n\n### Granular Access Control for Editors\n\n**Last segment only** – Non-admins edit just the final path segment. The parent path is read-only:\n\n![Last segment editing](Documentation/sluggi_last_segment_only.png)\n\n**Full path editing** – A button lets permitted users temporarily unlock the full path:\n\n![Full path edit button](Documentation/sluggi_edit_full_path_url.png)\n\n![Full path editing enabled](Documentation/sluggi_transient_full_path_edit.png)\n\n**Hierarchy permissions** – Editing is restricted based on page tree permissions. Users can only modify segments for pages they're allowed to edit:\n\n![Hierarchy permissions](Documentation/sluggi_restricted_permissions.png)\n\n### Out-of-Sync URL Detection\n\nWhen a page's URL path doesn't match the page hierarchy (e.g. after a page move, a manual admin edit, or a database import), _sluggi_ detects the mismatch and informs the editor with a subtle amber highlight on the prefix, a one-time notification, and an inline note below the field:\n\n![Broken prefix](Documentation/sluggi_broken_prefix.png)\n\n![Broken prefix notification](Documentation/sluggi_broken_prefix_notification.png)\n\nThe messages are tailored to the editor's permissions:\n- Editors who can lock URLs are advised to either regenerate or lock the slug to keep a custom URL\n- Editors without lock access are pointed to the regenerate button or advised to ask an administrator\n- Admins see the full URL path with the mismatched portion highlighted\n\nLocked and synced pages suppress the indicator entirely – locked pages have intentional custom URLs, and synced pages will self-correct on the next title change.\n\n### Redirect Info\n\nSee at a glance how many redirects target a page, with a direct link to the redirects module:\n\n![Redirect info](Documentation/sluggi_redirect_display.png)\n\nOnly shown to editors with access to the redirects module and `sys_redirect` table.\n\n### Redirect Control\n\nLet editors decide whether to create redirects when a URL changes:\n\n![Redirect modal](Documentation/sluggi_create_redirects.png)\n\nThe choice applies recursively to all affected child pages. Self-referencing redirects are prevented automatically, and stale redirect cleanup only affects auto-created redirects – manually created redirects are never touched.\n\n### Re-apply URL Paths Recursively\n\nRight-click any page in the page tree and select **More options \u003e Re-apply URL paths recursively** to regenerate URL paths for all descendant pages based on their current source fields (e.g. title, nav_title):\n\n![Context menu](Documentation/sluggi_context_update.png)\n\n- Useful after reverting a slug change via TYPO3's undo notification, or when child pages have stale prefixes\n- Slugs are regenerated from scratch using source fields – not by prefix replacement\n- Hidden pages are included, locked pages are skipped (descendants still update unless `lock_descendants` is enabled)\n- All changes share a single correlation ID – TYPO3's undo notification lets you revert everything at once\n- Admin users only\n\n### Copy URL to Clipboard\n\n![URL copied](Documentation/sluggi_url_copied_clipboard.png)\n\n### Slug Normalization\n\nTYPO3 core turns a title like \"Products/Services\" into `/products/services` (two segments) instead of `/products-services` (one segment). _sluggi_ fixes this globally – for manual edits, auto-sync, regeneration, and page tree inline editing. Optional underscore preservation (RFC 3986) is also available.\n\n### Duplicate Prevention Where TYPO3 Core Doesn't\n\n- **Copy**: Copied pages get unique slugs in the target location\n- **Move**: Child slugs update to reflect the new parent path\n- **Recycler restore**: Restored records get deduplicated slugs instead of causing 500 errors\n\n### Excluded Page Types\n\nRemove URL paths from page types that don't need them (Sysfolder, Recycler, Spacer). An upgrade wizard cleans up existing slugs.\n\n## Configuration\n\nAll features work out of the box with sensible defaults. Fine-tune via **System \u003e Settings \u003e Extension Configuration \u003e _sluggi_**:\n\n**Basic**\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `exclude_doktypes` | Comma-separated doktypes excluded from slug path generation. The default `199,254` matches TYPO3 core's built-in exclusion of Spacer and Sysfolder (see `SlugHelper::resolveParentPageRecord()`). Add `255` to also exclude Recycler pages. If you use [b13/masi](https://github.com/b13/masi) to include sysfolders in URL paths, remove `254` from this list. | `199,254` |\n| `preserve_underscore` | Keep underscores in URL paths instead of converting them to dashes. Useful when your URL convention or external systems require underscores (RFC 3986 compliant). | Off |\n| `copy_url` | Show a button to copy the full page URL to the clipboard. Saves editors from navigating to the frontend just to grab a link for emails, documents, or tickets. | On |\n| `last_segment_only` | Non-admin editors can only change the last segment of a URL path. The parent path stays read-only, preventing editors from accidentally breaking the site's URL hierarchy. | Off |\n| `allow_full_path_editing` | Show a button that lets permitted editors temporarily unlock the full path for editing (requires `last_segment_only`). The slug auto-locks afterwards to prevent sync from overwriting the custom path. | Off |\n\n**Sync**\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `synchronize` | Keep URLs in sync with page titles automatically. When an editor renames a page, the URL path updates instantly – no manual work, no stale URLs. Redirects from old to new are created via EXT:redirects. | On |\n| `synchronize_default` | Turn on sync for every newly created page. Editors can still disable it per page for manually crafted URLs. | On |\n| `synchronize_tables` | Extend auto-sync beyond pages to any table with a slug field. Comma-separated list, e.g. `tx_news_domain_model_news`. Each configured table gets a per-record sync toggle so editors can opt out individually. Supports multi-field generation with `fieldSeparator`. | – |\n\n**Lock**\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `lock` | Let editors pin important URLs so they can't be changed accidentally. Locked paths are also skipped during auto-sync, giving you full control over critical landing page URLs. | Off |\n| `lock_descendants` | When a parent page has a locked URL, protect all child page URLs too. Useful for entire sections of your site where URL stability is critical (e.g. campaign landing pages). | Off |\n\n**Redirect**\n\n| Setting | Description | Default |\n|---------|-------------|---------|\n| `redirect_control` | Show a modal when a URL changes, letting the editor decide whether to create a redirect. Gives editors control instead of silently creating redirects they may not want. The choice applies recursively to all affected child pages. | Off |\n| `show_redirects` | Display the number of active redirects targeting a page below the slug field, with a link to the redirects module pre-filtered by target page. Only shown to users with access to the redirects module. Requires EXT:redirects. | Off |\n\nFor deployment or version-controlled configuration, set values in `config/system/additional.php`:\n\n```php\n$GLOBALS['TYPO3_CONF_VARS']['EXTENSIONS']['sluggi'] = [\n    'synchronize' =\u003e '1',\n    'synchronize_default' =\u003e '1',\n    'synchronize_tables' =\u003e 'tx_news_domain_model_news',\n    'lock' =\u003e '1',\n    'lock_descendants' =\u003e '0',\n    'last_segment_only' =\u003e '1',\n    'allow_full_path_editing' =\u003e '1',\n    'exclude_doktypes' =\u003e '199,254,255',\n    'copy_url' =\u003e '1',\n    'preserve_underscore' =\u003e '0',\n    'redirect_control' =\u003e '1',\n    'show_redirects' =\u003e '1',\n];\n```\n\n## Site Configuration: Redirects \u0026 Recursive Slug Updates\n\n_sluggi_ requires [EXT:redirects](https://docs.typo3.org/c/typo3/cms-redirects/main/en-us/) which controls what happens when a page slug changes: whether child pages update recursively, whether redirects are created, how long they live, and which HTTP status code they use.\n\nThese settings are configured **per site** via [TYPO3 site sets](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/SiteHandling/SiteSettings.html). To activate them, add the `typo3/redirects` set to your site's `config.yaml` and override the defaults in `settings.yaml`.\n\n### Step 1: Add the redirects site set\n\nIn `config/sites/\u003cyour-site\u003e/config.yaml`, add `typo3/redirects` to the `dependencies` list:\n\n```yaml\nbase: 'https://example.com/'\nrootPageId: 1\ndependencies:\n  - typo3/redirects\nlanguages:\n  # ...\n```\n\n### Step 2: Override settings\n\nCreate `config/sites/\u003cyour-site\u003e/settings.yaml` with the settings you want to change:\n\n```yaml\nredirects:\n  autoUpdateSlugs: true\n  autoCreateRedirects: true\n  redirectTTL: 0\n  httpStatusCode: 301\n```\n\n### Available Settings\n\n| Setting | Type | Default | Description |\n|---------|------|---------|-------------|\n| `redirects.autoUpdateSlugs` | bool | `true` | Recursively update child page slugs when a parent slug changes. Works together with _sluggi_'s auto-sync – when a title change triggers a slug update on a parent page, all descendants get their slug prefix replaced automatically. |\n| `redirects.autoCreateRedirects` | bool | `true` | Create redirect records from old to new URL when a slug changes. Only applies in the **live workspace** – editing in a workspace does not create redirects until the change is published. |\n| `redirects.redirectTTL` | int | `0` | Lifetime in **days** for auto-created redirects. `0` means no expiration. When set, the redirect's `endtime` is calculated as creation time + TTL days. |\n| `redirects.httpStatusCode` | int | `307` | HTTP status code for auto-created redirects. Does not affect manually created redirects. Common values: `301` (Moved Permanently – best for SEO), `302` (Found), `307` (Temporary Redirect – the default). |\n\n\u003e **How this relates to sluggi:** When _sluggi_'s auto-sync regenerates a slug (because the page title changed), EXT:redirects picks up the change and applies the settings above. If `autoUpdateSlugs` is enabled, child pages update recursively. If `autoCreateRedirects` is enabled, redirect records are created for the old URLs. The `redirectTTL` and `httpStatusCode` settings control the properties of those redirect records. When _sluggi_'s `redirect_control` feature is enabled, editors can override `autoCreateRedirects` on a per-change basis via a modal dialog.\n\n### Ready-to-Use Configuration Presets\n\n_sluggi_ ships ready-to-use presets in [`Configuration/SiteSettings/`](Configuration/SiteSettings/). TYPO3's YAML loader supports [`imports`](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/YamlApi/Index.html#imports) with `EXT:` paths, so you can reference them directly from your `settings.yaml` without copying files.\n\nCreate `config/sites/\u003cyour-site\u003e/settings.yaml` with an import:\n\n```yaml\nimports:\n  - { resource: 'EXT:sluggi/Configuration/SiteSettings/recommended.settings.yaml' }\n```\n\nYou can override individual values after the import:\n\n```yaml\nimports:\n  - { resource: 'EXT:sluggi/Configuration/SiteSettings/recommended.settings.yaml' }\n\n# Override just the TTL from the preset\nredirects:\n  redirectTTL: 180\n```\n\n**Available presets:**\n\n| Preset | Status code | TTL | Description |\n|--------|:-----------:|:---:|-------------|\n| [recommended](Configuration/SiteSettings/recommended.settings.yaml) | 301 | permanent | Best for production sites where SEO matters |\n| [temporary-with-ttl](Configuration/SiteSettings/temporary-with-ttl.settings.yaml) | 307 | 90 days | Sites with frequently changing content (news, events, campaigns) |\n| [no-auto-redirects](Configuration/SiteSettings/no-auto-redirects.settings.yaml) | – | – | Recursive slug updates only, redirects managed externally or manually |\n| [manual-only](Configuration/SiteSettings/manual-only.settings.yaml) | – | – | No recursive updates, no auto-redirects, full manual control |\n\n### How It All Fits Together\n\n| What happens | `autoUpdateSlugs` | `autoCreateRedirects` | sluggi `synchronize` | sluggi `redirect_control` |\n|---|:---:|:---:|:---:|:---:|\n| Title changes → slug updates | – | – | **controls this** | – |\n| Parent slug changes → child slugs update | **controls this** | – | – | – |\n| Old URL → redirect to new URL | – | **controls this** | – | – |\n| Editor chooses whether to create redirect | – | must be `true` | – | **controls this** |\n\nFor the full EXT:redirects documentation, see the [TYPO3 Redirects Setup](https://docs.typo3.org/c/typo3/cms-redirects/main/en-us/Setup/Index.html). For details on TYPO3 site sets and settings, see [Site Settings](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/SiteHandling/SiteSettings.html).\n\n## Permissions\n\nEvery _sluggi_ feature integrates with TYPO3's standard backend user and group permissions. You decide per user group which editors can see and use which controls – the same way you manage access to any other field in TYPO3:\n\n| Field | Permission controls |\n|-------|---------------------|\n| `pages:slug` | Edit the URL path |\n| `pages:tx_sluggi_sync` | Toggle sync on/off |\n| `pages:slug_locked` | Lock/unlock URLs |\n| `pages:tx_sluggi_full_path` | Use full path editing |\n\nExample setup for a typical editorial team:\n\n| | Admin | Senior Editor | Editor |\n|---|:---:|:---:|:---:|\n| Edit URL path | ✓ | ✓ | ✓ |\n| Toggle sync | ✓ | ✓ | – |\n| Lock/unlock URLs | ✓ | ✓ | – |\n| Full path editing | ✓ | ✓ | – |\n\n**Admin** – Full control over all URL features.\n\n**Senior Editor** – Can lock critical URLs before a campaign launch, toggle sync for pages with manually crafted paths, and edit full URL paths when needed.\n\n**Editor** – Can edit the last segment of a URL (with `last_segment_only` enabled), but cannot disable sync or unlock a locked URL. URLs stay consistent without extra training.\n\n## User Settings\n\nUsers can enable compact controls via **User Settings \u003e Personalization** to collapse controls behind a menu icon.\n\n## Slug Source Fields\n\n_sluggi_ reads the source fields for slug generation from the standard TCA [`generatorOptions.fields`](https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ColumnsConfig/Type/Slug/Index.html) configuration of the `slug` column. All referenced fields are automatically detected — they get a badge in the backend and the frontend component listens to them for real-time sync.\n\n```php\n'slug' =\u003e [\n    'config' =\u003e [\n        'type' =\u003e 'slug',\n        'generatorOptions' =\u003e [\n            'fields' =\u003e [['nav_title', 'title']],\n        ],\n    ],\n],\n```\n\nFor more configuration options (e.g. multiple fields, fallback chains, field separators), see the [TYPO3 TCA slug documentation](https://docs.typo3.org/m/typo3/reference-tca/main/en-us/ColumnsConfig/Type/Slug/Index.html).\n\nFor non-page tables, add the table name to the `synchronize_tables` extension setting. The slug auto-regenerates whenever a source field changes on save, unless the editor has disabled sync for that specific record via the per-record toggle.\n\n## Requirements\n\n- TYPO3 12.4, 13.4.26+, or 14.x\n- PHP 8.2+\n- EXT:redirects\n\n## Suggested Extensions\n\n- [news-redirect-slug-change](https://github.com/georgringer/news-redirect-slug-change) – Redirects when news slugs change\n- [ig-slug](https://github.com/internetgalerie/ig_slug) – Rebuild URL slugs in bulk\n- [masi](https://github.com/b13/masi) – Exclude specific page slugs from subpage URL generation\n- [content_slug](https://github.com/sebkln/content_slug) – Slug field for human-readable content element anchors (`#my-section`)\n\n## Fixes for TYPO3 Core Issues\n\n_sluggi_ works around these known TYPO3 core issues:\n\n- [#108375](https://forge.typo3.org/issues/108375) – When multiple pages are updated in a single DataHandler operation (e.g. recursive slug update), TYPO3 core assigns each page its own correlation ID, making it impossible to revert all changes at once via the undo notification. _sluggi_ shares one correlation ID across all pages in the operation so the entire batch can be reverted with a single click.\n- [#108870](https://forge.typo3.org/issues/108870) – The \"Revert update\" notification after a slug change only rolls back child page slugs and redirect records, but not the parent page's own slug change. _sluggi_ extends the rollback to include the parent page so the entire change is fully reverted.\n- [#106152](https://forge.typo3.org/issues/106152) – Restoring pages from the recycler does not check for slug conflicts, which can result in duplicate URLs and 500 errors. _sluggi_ validates and deduplicates slugs on restore.\n- [#86740](https://forge.typo3.org/issues/86740) – TYPO3 core treats slashes in page titles as path separators, turning \"Products/Services\" into two URL segments instead of one. _sluggi_ normalizes slashes to the fallback character globally.\n- [#103833](https://forge.typo3.org/issues/103833) – Renaming a slug back to a previous value can leave behind a self-referencing redirect. _sluggi_ prevents creation of self-referencing redirects automatically.\n- [#97962](https://forge.typo3.org/issues/97962) – TYPO3 core always replaces underscores with the fallback character during slug generation. _sluggi_ adds a `preserve_underscore` setting for RFC 3986 compliant URLs.\n- [#94003](https://forge.typo3.org/issues/94003) – When copying a page subtree, TYPO3 core changes the copied parent's slug immediately (e.g. appending `-1`) but fails to update child pages' slug prefixes accordingly. _sluggi_ recalculates all slugs in the copied tree with correct parent prefixes.\n- In TYPO3 13.4, `TemporaryPermissionMutationService` grants `tables_modify` for `sys_redirect` but does not grant page-level access. Editors without the site root page in their webmounts cannot create redirect records. _sluggi_ bypasses page-level access checks for redirect creation DataHandler operations.\n\n## Upgrading\n\n### 14.0.0\n\n**Configuration keys renamed**\n\nThe following extension configuration keys were renamed. Your existing values are **not** migrated automatically — update them manually in `config/system/additional.php` or via **Admin Tools \u003e Settings \u003e Extension Configuration**:\n\n| Old key (v12/v13) | New key (v14) |\n|---|---|\n| `exclude_page_types` | `exclude_doktypes` |\n| `allow_lock` | `lock` |\n\n**Configuration keys removed**\n\n| Removed key | Replacement |\n|---|---|\n| `pages_fields` | Configure source fields via TCA `generatorOptions.fields` |\n| `whitelist` | Use standard TYPO3 backend user/group permissions for `pages:slug` |\n| `slash_replacement` | Now always active, no longer configurable |\n\n**Redirect settings moved to site configuration**\n\nExtension-level redirect keys (`redirect_lifetime`, `redirect_code`, `redirect_force_https`, `redirect_respect_query_parameters`, `redirect_keep_query_parameters`) were removed. Use TYPO3's native per-site redirect settings instead. Ready-made presets are shipped in `Configuration/SiteSettings/`.\n\n### 14.2.0\n\n**`exclude_doktypes` default changed from empty to `199,254`** ([#135](https://github.com/wazum/sluggi/issues/135))\n\nPrevious versions shipped with an empty `exclude_doktypes` default, which caused sluggi's copy/move handlers to include Spacer and Sysfolder names in generated slug paths — contrary to TYPO3 core's built-in behavior in `SlugHelper::resolveParentPageRecord()`. The default is now `199,254` (Spacer, Sysfolder) to match core.\n\nSluggi now also overrides core's `resolveParentPageRecord()` so that _all_ slug generation paths (AJAX suggestions, new pages, copy, move, sync) consistently respect the `exclude_doktypes` setting. Without this override, TYPO3 core hardcodes the exclusion of Spacer and Sysfolder regardless of configuration.\n\n**Upgrade wizard:** Run **Admin Tools \u003e Upgrade \u003e Upgrade Wizard** after updating. The wizard _\"Set default excluded page types for sluggi\"_ sets `exclude_doktypes` to `199,254` for existing installations where it was empty.\n\n**[b13/masi](https://github.com/b13/masi) users:** If you use masi to include sysfolders in URL paths, remove `254` from `exclude_doktypes` after the upgrade. Masi uses a TCA `postModifier` (not an XCLASS), so both extensions work together without conflicts — masi overrides the generated slug after sluggi's `SlugHelper`, and both will consistently include the sysfolder when `254` is not in the exclusion list.\n\n## Support and Feature Requests\n\nUse the [issues tracker](https://github.com/wazum/sluggi/issues) on GitHub for support questions and new feature requests or ideas concerning the extension.\n\n## Credits and Sponsors\n\nMade with love for the TYPO3 community by [Wolfgang Klinger](https://wolfgang-klinger.dev/).\n\nMany thanks to [plan2net GmbH](https://www.plan2.net/) for allowing me to work on the extension during my working hours and for great projects where this extension is already being used in real life.\n\nSpecial thanks to [TU München](https://www.tum.de/) and other German universities that sponsored my time at _plan2net GmbH_ to work on this extension (_applies to previous versions_).\n\n## License\n\nGPL-2.0-or-later\n\n\u003cbr\u003e\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"Resources/Public/Icons/Extension.svg\" alt=\"sluggi\" width=\"80\" height=\"80\"\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwazum%2Fsluggi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwazum%2Fsluggi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwazum%2Fsluggi/lists"}