Laravel 10层级分类URL实现求助(附现有代码)
Laravel 10 实现层级分类URL(仿WordPress分类结构)
一、模型与表关联配置
先对应你的terms和term_taxonomy表建好模型,确保层级关联逻辑正确:
Term模型(app/Models/Term.php)
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\HasOne; use Illuminate\Database\Eloquent\Relations\HasManyThrough; class Term extends Model { protected $table = 'terms'; protected $primaryKey = 'term_id'; public $timestamps = false; // 匹配WP默认表结构,按需调整 // 关联分类法表 public function taxonomy(): HasOne { return $this->hasOne(TermTaxonomy::class, 'term_id', 'term_id'); } // 获取父分类 public function parentTerm() { return $this->hasOneThrough( self::class, TermTaxonomy::class, 'term_id', 'term_id', 'term_id', 'parent' ); } // 递归获取所有子分类 public function childrenTerms(): HasManyThrough { return $this->hasManyThrough( self::class, TermTaxonomy::class, 'parent', 'term_id', 'term_id', 'term_id' )->with('childrenTerms'); } }
TermTaxonomy模型(app/Models/TermTaxonomy.php)
<?php namespace App\Models; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; class TermTaxonomy extends Model { protected $table = 'term_taxonomy'; protected $primaryKey = 'term_taxonomy_id'; public $timestamps = false; public function term(): BelongsTo { return $this->belongsTo(Term::class, 'term_id', 'term_id'); } }
二、生成层级Slug路径
在Term模型中添加属性方法,自动拼接从根分类到当前分类的完整slug路径:
// 在Term模型中新增 public function getFullSlugAttribute() { $slugs = []; $current = $this; // 向上遍历父分类,收集所有slug while ($current) { array_unshift($slugs, $current->slug); $current = $current->parentTerm; } return implode('/', $slugs); }
三、配置支持层级的路由
在routes/web.php中设置匹配多级路径的路由:
// 匹配任意层级的分类URL,如 /top-travel/sea 或 /top-travel/sea/beach Route::get('{categoryPath}', [CategoryController::class, 'show']) ->where('categoryPath', '^[a-z0-9-]+(/[a-z0-9-]+)*$') // 正则限制路径格式 ->name('category.show');
四、控制器逻辑修正(CategoryController.php)
修改控制器方法,根据层级路径定位正确的分类:
<?php namespace App\Http\Controllers; use App\Models\Term; use Illuminate\Http\Response; class CategoryController extends Controller { public function show(string $categoryPath) { $slugSegments = explode('/', $categoryPath); $lastSlug = end($slugSegments); // 定位最后一个slug对应的分类(可添加taxonomy筛选,如只处理category类型) $category = Term::where('slug', $lastSlug) ->whereHas('taxonomy', function ($query) { $query->where('taxonomy', 'category'); }) ->first(); if (!$category) { abort(Response::HTTP_NOT_FOUND); } // 验证路径合法性,避免不同层级slug重复导致错误 if ($category->full_slug !== $categoryPath) { abort(Response::HTTP_NOT_FOUND); } // 这里可添加分类内容查询逻辑,如关联文章 // $posts = $category->taxonomy->posts; return view('category.show', compact('category')); } // 生成分类URL的工具方法 public function categoryUrl(Term $category) { return route('category.show', ['categoryPath' => $category->full_slug]); } }
五、优化方案
- 缓存层级路径:避免重复查询数据库,提升性能
// 修改Term模型的full_slug属性方法 public function getFullSlugAttribute() { return cache()->remember("term-full-slug-{$this->term_id}", 3600, function () { $slugs = []; $current = $this; while ($current) { array_unshift($slugs, $current->slug); $current = $current->parentTerm; } return implode('/', $slugs); }); }
注意:修改分类slug或父级时,要清除对应缓存。
- 全局辅助函数:方便视图中直接生成分类URL
在app/helpers.php中添加:
function category_url(\App\Models\Term $category) { return route('category.show', ['categoryPath' => $category->full_slug]); }
然后在composer.json的autoload中添加:
"autoload": { "files": [ "app/helpers.php" ] }
执行composer dump-autoload生效,视图中可直接调用{{ category_url($category) }}。
- Slug唯一性校验:创建分类时,确保同一父分类下slug唯一,避免路径冲突。
内容的提问来源于stack exchange,提问作者MarkBui
相关产品推荐
相关产品推荐

