Skip to content

Commit ff29f29

Browse files
committed
feat: implement custom slug generation with fallback and length limitation
1 parent fd366f6 commit ff29f29

File tree

2 files changed

+78
-1
lines changed

2 files changed

+78
-1
lines changed

docs/configuration.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -503,6 +503,13 @@ Control how InspireCMS handles frontend requests:
503503
* Override with a custom class to implement specialized preview behavior
504504
*/
505505
'preview_provider' => \SolutionForest\InspireCms\Content\DefaultPreviewProvider::class,
506+
507+
/**
508+
* Controls how URL slugs are generated for content
509+
*
510+
* Override to implement custom slug generation rules
511+
*/
512+
'slug_generator' => \SolutionForest\InspireCms\Content\DefaultSlugGenerator::class,
506513
],
507514
```
508515

src/Content/DefaultSlugGenerator.php

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,76 @@ class DefaultSlugGenerator implements SlugGeneratorInterface
88
{
99
public function generate($text)
1010
{
11-
return Str::slug($text);
11+
// return Str::slug($text);
12+
13+
$maxLength = 50;
14+
15+
// Method 1: Try ICU transliterator (best option)
16+
if (function_exists('transliterator_transliterate')) {
17+
$slug = self::useTransliterator($text);
18+
if ($slug && strlen($slug) > 0) {
19+
return self::limitLength($slug, $maxLength);
20+
}
21+
}
22+
23+
// Method 2: Try iconv transliteration
24+
$slug = self::useIconv($text);
25+
if ($slug && strlen($slug) > 0) {
26+
return self::limitLength($slug, $maxLength);
27+
}
28+
29+
// Method 3: Fallback to meaningful slug
30+
return self::fallbackSlug($text);
31+
}
32+
33+
private static function useTransliterator($text) {
34+
try {
35+
$transliterated = transliterator_transliterate(
36+
'Han-Latin; Latin-ASCII; Lower()',
37+
$text
38+
);
39+
return self::cleanSlug($transliterated);
40+
} catch (Exception $e) {
41+
return false;
42+
}
43+
}
44+
45+
private static function useIconv($text) {
46+
$transliterated = iconv('UTF-8', 'ASCII//TRANSLIT//IGNORE', $text);
47+
if ($transliterated === false) {
48+
return false;
49+
}
50+
return self::cleanSlug($transliterated);
51+
}
52+
53+
private static function cleanSlug($text) {
54+
$slug = strtolower($text);
55+
$slug = preg_replace('/[^a-z0-9\s-]/', '', $slug);
56+
$slug = preg_replace('/[\s-]+/', '-', $slug);
57+
$slug = trim($slug, '-');
58+
return $slug;
59+
}
60+
61+
private static function fallbackSlug($text) {
62+
// Create a meaningful fallback
63+
$hash = substr(md5($text), 0, 8);
64+
$timestamp = date('Ymd');
65+
return "article-{$timestamp}-{$hash}";
66+
}
67+
68+
private static function limitLength($slug, $maxLength) {
69+
if (strlen($slug) <= $maxLength) {
70+
return $slug;
71+
}
72+
73+
// Cut at word boundary
74+
$slug = substr($slug, 0, $maxLength);
75+
$lastDash = strrpos($slug, '-');
76+
77+
if ($lastDash !== false && $lastDash > $maxLength * 0.7) {
78+
$slug = substr($slug, 0, $lastDash);
79+
}
80+
81+
return rtrim($slug, '-');
1282
}
1383
}

0 commit comments

Comments
 (0)