首页 / 资讯中心 / 文章详情

Orchard Core Taxonomies 模块深度指南:从 Taxonomy 分类体系、Shape 渲染到查询与配置实战

Orchard Core Taxonomies 模块深度指南:从 Taxonomy 分类体系、Shape 渲染到查询与配置实战 ★ FEATURED ARTICLE
CMS后端Web框架【免费下载链接】OrchardCoreOrchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.项目地址https://gitcode.com/gh_mirrors/or/OrchardCore点击查看免费下载本指南以 Orchard Core 仓库中 Taxonomies 模块官方文档 为主体结合模块源码src/OrchardCore.Modules/OrchardCore.Taxonomies与src/OrchardCore/OrchardCore.Taxonomies.Core展开。通过本文你将掌握Taxonomy分类法与 Term术语的核心数据模型、Term/TermItem/TermContentItem等 Shape 的渲染机制与 Alternate 模板体系、Razor/Liquid 两种模板下的调用与自定义方式、TaxonomyField字段的显示模型、Orchard Helper 与 Liquid 过滤器taxonomy_terms、inherited_terms的查询用法、TaxonomyIndex索引表结构以及管理端列表过滤与 Recipe 配置方法。模块概览用分类法组织任意类型的内容OrchardCore.Taxonomies模块提供了一个名为Taxonomy的内容类型用于定义任何类型的受管词表vocabulary即分类/类别。它的核心设计是Taxonomy是一个内容项内部承载一组按层级组织的Terms术语。任意内容项可以通过挂载Taxonomy Field字段与一个或多个 Term 建立关联。从源码看这一设计由三个核心模型支撑TaxonomyPart —— 自动附加到所有 Taxonomy 内容项上包含TermContentType术语的内容类型名和TermsListContentItem即层级术语树。TermPart —— 自动附加到所有 Term 内容项上记录所属分类法的TaxonomyContentItemId。TaxonomyField —— 可挂到任意内容部件上的字段仅含两个属性TaxonomyContentItemId关联的分类法内容项 ID与TermContentItemIds选中的术语内容项 ID 数组。模块的注册入口在 Startup.cs它注册了TaxonomyPart、TaxonomyField、TermPart及相关 Handler、Display Driver、Shape 表提供程序TermShapes、Liquid 过滤器、TaxonomyIndexProvider索引提供程序并内置 GraphQL 支持需要启用OrchardCore.Apis.GraphQL特性时生效。Shape 渲染体系Taxonomy 模块的前端渲染完全建立在 Orchard Core 的 Shape 体系之上共涉及 5 类 ShapeTaxonomyPart、TermPart、Term、TermItem、TermContentItem以及字段 ShapeTaxonomyField。它们的 Alternate 生成逻辑集中在 TermShapes.cs 与 TermItemAlternatesFactory.cs 中。TaxonomyPart ShapeTaxonomy 的展示依赖AutoroutePart设置中的Container routing功能实现路由启用后 Taxonomy 的展示即由TaxonomyPartShape 渲染其内部使用TermShape 展示 Term 的层级结构。对应视图为 TaxonomyPart.cshtml。TermPart Shape当某个 Term 启用AutoroutePart的Container routing后Term 的展示由TermPartShape 渲染。它会列出所有通过TaxonomyField归入该 Term 层级的内容项。注意TermPart由内容显示驱动器渲染而非部件显示驱动器因此在 TermShapes.cs 中通过OnDisplaying为其补加了基于内容类型与显示类型的 Alternate。Term ShapeTermShape 由TaxonomyPart展示时用来渲染 Taxonomy 的术语层级列表。它本身是可复用的 Shape类似MenuShape既可以从内容模板中调用渲染整个 Taxonomy 及其术语层级也可以只渲染Term层级的某一部分。典型场景是在内容模板中调用它渲染一个侧边栏分类列表Liquid{% shape term, alias: alias:Categories %}Razorshape typeTerm aliasalias:Categories /也可以指定TermContentItemId只渲染部分术语层级Liquid{% shape term, TaxonomyContentItemId: taxonomyContentItemId TermContentItemId: termContentItemId %}Razorshape typeTerm TaxonomyContentItemIdtaxonomyContentItemId TermContentItemIdtermContentItemId /TermShape 上可用的属性如下属性说明Model.TaxonomyContentItemId若已定义为要渲染的分类法内容项标识符Model.Items该分类法的术语项 Shape 列表元素类型为TermItemModel.Differentiator若已定义为分类法的格式化名称例如CategoriesModel.TermContentItemId若已定义为开始渲染层级的术语内容项标识符从源码实现看TermShape 的数据装配发生在OnProcessing阶段TermShapes.cs它支持通过Alias别名或TaxonomyContentItemId定位分类法加载 Taxonomy 内容项后递归查找指定的TermContentItemId若提供随后把每个术语通过shapeFactory.CreateAsync(TermItem, ...)创建为TermItemShape 并追加到Items。注意注释特别强调不要使用Items.Add()否则集合不会被正确排序。同时FormatName会把foo-ba r之类的显示文本转换为FooBaR形式的 PascalCase用作Differentiator与 CSS 类名。Term Alternate 模板定义模板示例文件命名Term__[Differentiator]Term__CategoriesTerm-Categories.cshtmlTerm__[ContentType]Term__CategoryTerm-Category.cshtmlTerm 模板示例Liquidul classlist-group list-group-flush {{ Model.Classes | join: }} {% for item in Model.Items %} {% shape_add_classes item list-group-item border-0 pb-0 %} {{ item | shape_render }} {% endfor %} /ulRazormodel dynamic if ((bool)Model.HasItems) { TagBuilder tag Tag(Model, ul); foreach (var item in Model.Items) { tag.InnerHtml.AppendHtml(await DisplayAsync(item)); } tag } else { p classalert alert-warningT[The list is empty]/p }TermItem ShapeTermItemShape 用于渲染单个术语项是层级渲染中的节点。属性说明Model.Term拥有该术语项的TermShapeModel.TaxonomyContentItem对应的TaxonomyContentItemModel.TermContentItem该术语项对应的TermContentItemModel.Level术语项的层级顶层为0Model.Items子术语项 Shape 列表元素类型为TermItemModel.Terms层级中较低层级术语的内容项列表Model.Differentiator若已定义为分类法的格式化名称例如Categories注意当通过TermContentItemId渲染部分术语层级时Level始终基于 Taxonomy 根节点计算即在 TermShapes.cs 中从根节点开始递归定位术语后返回的层级数而非以所选术语为 0 层。TermItem Alternate 模板定义模板示例文件命名TermItem__level__[level]TermItem__level__2TermItem-level-2.cshtmlTermItem__[ContentType]TermItem__CategoryTermItem-Category.cshtmlTermItem__[ContentType]__level__[level]TermItem__Category__level__2TermItem-Category-level-2.cshtmlTermItem__[Differentiator]TermItem__CategoriesTermItem-Categories.cshtmlTermItem__[Differentiator]__level__[level]TermItem__Categories__level__2TermItem-Categories-level-2.cshtmlTermItem__[Differentiator]__[ContentType]TermItem__Categories__CategoryTermItem-Categories-Category.cshtmlTermItem__[Differentiator]__[ContentType]__level__[level]TermItem__Categories__ContentType__level__2TermItem-Categories-Category-level-2.cshtml这些 Alternate 模式由 TermItemAlternatesFactory.cs 基于(ContentType, Differentiator, Level)组合预先计算并缓存同一组合只需计算一次提升重复渲染性能。TermItem 模板示例Liquidli classlist-group-item border-0 pb-0 {% shape_clear_alternates Model %} {% shape_type Model TermContentItem %} {{ Model | shape_render }} {% if Model.HasItems %} ul classlist-group list-group-flush {% for item in Model.Items %} {% shape_add_classes item list-group-item border-0 pb-0 %} {{ item | shape_render }} {% endfor %} /ul {% endif %} /liRazormodel dynamic { // Morphing the shape to keep Model untouched Model.Metadata.Alternates.Clear(); Model.Metadata.Type TermContentItem; } li await DisplayAsync(Model) if ((bool)Model.HasItems) { ul foreach (var item in Model.Items) { await DisplayAsync(item) } /ul } /liTermContentItem ShapeTermContentItemShape 用于渲染术语内容项本身。它是由TermItemShape变形morphing而来——即保留原TermItem的全部属性仅把 Shape 类型改为TermContentItem因此TermItem上可用的属性在这里依然可用。属性说明Model.Term拥有该术语项的TermShapeModel.TaxonomyContentItem对应的TaxonomyContentItemModel.TermContentItem该术语项对应的TermContentItemModel.Level术语项的层级顶层为0Model.Items子术语项 Shape 列表元素类型为TermItemModel.Terms层级中较低层级术语的内容项列表Model.Differentiator若已定义为术语的格式化名称例如TravelTermContentItem Alternate 模板定义模板示例文件命名TermContentItem__level__[level]TermContentItem__level__2TermContentItem-level-2.cshtmlTermContentItem__[ContentType]TermContentItem__CategoryTermContentItem-Category.cshtmlTermContentItem__[ContentType]__level__[level]TermContentItem__Category__level__2TermContentItem-Category-level-2.cshtmlTermContentItem__[Differentiator]TermContentItem__CategoriesTermContentItem-Categories.cshtmlTermContentItem__[Differentiator]__level__[level]TermContentItem__Categories__level__2TermContentItem-Categories-level-2.cshtmlTermContentItem__[Differentiator]__[ContentType]TermContentItem__Categories__CategoryTermContentItem-Categories-Category.cshtmlTermContentItem__[Differentiator]__[ContentType]__level__[level]TermContentItem__Categories__Category__level__2TermContentItem-Categories-Category-level-2.cshtmlTermContentItem 模板示例Liquid{{ Model.TermContentItem | shape_build_display: Summary | shape_render }}Razormodel dynamic await Orchard.DisplayAsync(Model.TermContentItem as ContentItem, Summary)TaxonomyField Shape当TaxonomyField被附加到某个内容部件时会渲染该 Shape其 Shape 基类为DisplayTaxonomyFieldViewModel。字段数据类TaxonomyField上的属性属性类型说明TaxonomyContentItemIdstring与该字段关联的分类法的内容项 IDTermContentItemIdsstring[]该字段选中的术语内容项 ID 列表DisplayTaxonomyFieldViewModel用于字段展示时的 ViewModel 类见 DisplayTaxonomyFieldViewModel.cs可用属性属性类型说明FieldTaxonomyFieldTaxonomyField实例PartContentPart该字段所附属的内容部件PartFieldDefinitionContentPartFieldDefinition部件字段定义Orchard HelpersRazor 模板中的分类法查询模块在 TaxonomyOrchardHelperExtensions.cs 中提供了三个扩展方法供 Razor 视图直接调用。GetTaxonomyTermAsync根据术语内容项 ID 与分类法返回对应的术语内容项未找到时返回null。内部先加载 Taxonomy再通过FindTerm递归遍历TaxonomyPart.TermsJSON 树查找匹配ContentItemId的术语。foreach(var termId in Model.TermContentItemIds) { await Orchard.GetTaxonomyTermAsync(Model.TaxonomyContentItemId, termId); }GetInheritedTermsAsync返回包含父级在内的术语列表从当前术语到根节点的完整链路。内部通过FindTermHierarchy递归回溯父链并依次加入列表。foreach(var termId in Model.TermContentItemIds) { div foreach(var parent in await Orchard.GetInheritedTermsAsync(Model.TaxonomyContentItemId, termId)) { parent } /div }QueryCategorizedContentItemsAsync提供按特定术语查询被分类内容项的能力。它接收一个FuncIQueryContentItem, TaxonomyIndex, IQueryContentItem查询委托基于TaxonomyIndex索引执行查询并用IContentManager.LoadAsync加载结果。示例排除当前内容项的相关内容下面示例查询与当前内容项按术语类别相关联、但排除当前内容项本身的内容项using YesSql.Services { var termContentItemIds Model.TermContentItemIds; var contentItems await Orchard.QueryCategorizedContentItemsAsync( query query.Where(index index.TermContentItemId.IsIn(termContentItemIds) index.ContentItemId ! Model.Part.ContentItem.ContentItemId)); foreach(var contentItem in contentItems) { ... } }Liquid 过滤器模块在 Startup.cs 中注册了两个 Liquid 过滤器taxonomy_terms与inherited_terms。taxonomy_termstaxonomy_terms过滤器用于加载指定的术语内容项。其实现TaxonomyTermsFilter.cs支持三种输入形式TaxonomyField对象、包含TermContentItemIds/TaxonomyContentItemId的 JSON 对象以及术语 ID 数组此时第一个参数必须为分类法内容项 ID。示例列出BlogPost内容类型上Colors字段关联的所有术语并渲染{% assign colors Model.ContentItem.Content.BlogPost.Colors | taxonomy_terms %} {% for c in colors %} {{ c }} {% endfor %}taxonomy_terms同样接受术语内容项 ID 作为输入只要第一个参数是分类法内容项 ID 即可。示例显示所有颜色及其层级{% assign taxonomyId Model.ContentItem.Content.BlogPost.Colors.TaxonomyContentItemId %} {% for colorId in Model.ContentItem.Content.BlogPost.Colors.TermContentItemIds %} div {% assign parentColors colorId | inherited_terms: taxonomyId %} {% for c in parentColors %} {{ c }} {% endfor %} /div {% endfor %}inherited_termsinherited_terms过滤器加载给定术语的所有父级术语。输入必须是术语内容项或内容项 ID第一个参数必须是分类法内容项或内容项 ID。其实现InheritedTermsFilter.cs同样复用FindTermHierarchy递归收集父链。Taxonomy Index索引表结构TaxonomyIndexSQL 表记录了所有与 Taxonomy 字段关联的内容项每一条记录对应字段中选中的一个术语。其 C# 定义位于 TaxonomyIndex.cs基于 YesSql 的MapIndex实现。列类型说明TaxonomyContentItemIdstring分类法的内容项 IDContentItemIdstring被分类内容的内容项 IDContentTypestring被分类内容的内容类型ContentPartstring包含该字段的内容部件ContentFieldstring内容部件中字段的名称TermContentItemIdstring被分类的术语的内容项 ID例如若某字段选中了两个术语则会产生两条记录除TermContentItemId外的列值完全相同。该索引由 TaxonomyIndexProvider.cs 负责写入它按内容类型遍历所有类型为TaxonomyField的字段定义跳过软删除项Published与Latest均为 false及不包含 Taxonomy 字段的内容类型并缓存到_ignoredTypes以提升性能为每个选中术语生成一条索引记录。索引模型额外包含Published与Latest两个布尔列用于区分草稿/发布状态。Tags 模式编辑时的标签化Tags是分类法的一种编辑与显示模式选项允许在编辑内容项时以标签形式进行打标。启用 Tags 模式后除了保存TermContentItemId还会一并保存术语的显示文本display text属性。你可以直接用如下访问器读取TagNames属性Liquid{% for tagName in Model.ContentItem.Content.BlogPost.Tags.TagNames %} span classbadge text-bg-secondary i classfa-solid fa-tag fa-xs fa-rotate-90 align-middle aria-hiddentrue/i span classalign-middle {{ tagName }} /span /span {% endfor %}Razorforeach (var tagName in Model.ContentItem.Content.BlogPost.Tags.TagNames) { span classtaxonomy-tag-termtagName/span }注意如果更新了术语的显示文本属性已使用该标签的内容项需要重新发布republish才能反映此变更。从源码看Tags 模式由独立的显示驱动器与编辑器驱动支撑TaxonomyFieldTagsDisplayDriver仅用于 DisplayType 为Tags的场景见 Startup.cs和TaxonomyFieldTagsEditorSettingsDriver相关 TypeScript 编辑器逻辑位于 taxonomy-field-tags.ts。Taxonomies 管理端内容列表过滤器模块提供一个特性FeatureOrchardCore.Taxonomies.ContentsAdminList注册于 Startup.cs启用后会在后台内容列表中提供分类法过滤器。它通过TaxonomyContentsAdminListFilter实现IContentsAdminListFilter、TaxonomyContentsAdminListDisplayDriver与AdminMenu导航提供程序实现并允许通过部署步骤导出 Taxonomy Filters settings 设置。前台列出 Taxonomy 内容项在后台内容列表之外若要在前端按分类法术语筛选内容项或操作查询可以使用IContentsTaxonomyListFilter接口位于 IContentsTaxonomyListFilter.cs文档中写作IContentTaxonomyListFilter请以源码为准。其默认实现为 DefaultContentsTaxonomyListQueryService.cs注册为IContentsTaxonomyListQueryService。Recipe 配置预置管理端分类法过滤器Taxonomy 后台列表设置可以通过Settingsrecipe 步骤进行配置。配置文件中的TaxonomyContentsAdminListSettings模型定义见 TaxonomyContentsAdminListSettings.cs示例{ steps: [ { name: settings, TaxonomyContentsAdminListSettings: { TaxonomyContentItemIds: [ 4k2v5q8m1nh3y9x6p0w7r2t4jz ] } } ] }属性类型说明TaxonomyContentItemIdsArray of String用作后台内容列表过滤器的分类法内容项 ID小结与实践建议渲染层级术语树优先复用TermShape支持通过Alias或TaxonomyContentItemId定位并按需通过 Alternate 模板Term__Categories、TermItem__Categories__level__2等定制样式所有 Alternate 命名与生成逻辑可在 TermShapes.cs 与 TermItemAlternatesFactory.cs 中核对。查询分类内容Razor 中使用QueryCategorizedContentItemsAsyncLiquid 中使用taxonomy_terms/inherited_terms底层统一走TaxonomyIndex注意该索引为每个选中术语各生成一条记录。配置后台过滤启用OrchardCore.Taxonomies.ContentsAdminList特性后可通过Settingsrecipe 步骤预置TaxonomyContentItemIds。Tags 模式适合快速打标场景但术语显示文本变更后需重新发布内容项。如需在前后端查看模块实际视图可参考 Views 目录下的Term.cshtml、TermItem.cshtml、TermContentItem.cshtml、TaxonomyPart.cshtml、TermPart.cshtml及TaxonomyField.cshtml等默认模板官方文档中还收录了多段分类法相关的视频教程可在 模块 README 末尾查看。赞分享CMS后端Web框架【免费下载链接】OrchardCoreOrchard Core is an open-source modular and multi-tenant application framework built with ASP.NET Core, and a content management system (CMS) built on top of that framework.项目地址https://gitcode.com/gh_mirrors/or/OrchardCore点击查看免费下载相关推荐Zola 分类法Taxonomies模板开发指南从配置、术语渲染到分页与 Feed 的完整实战Zola 分类法Taxonomies模板开发指南从配置、术语渲染到分页与 Feed 的完整实战 Zola 内置的 Taxonomies分类法机制允许你静态站点CLI开发工具Zola 分类系统Taxonomies完全指南从配置文件、内容标注到模板渲染Zola 分类系统Taxonomies完全指南从配置文件、内容标注到模板渲染 Zola 内置了功能完整的分类系统Taxonomies让你可以按照任意静态站点CLI开发工具Orchard Core 配置体系深度解析IShellConfiguration 与多租户配置实战Orchard Core 配置体系深度解析IShellConfiguration 与多租户配置实战 Orchard Core 在 ASP.NET Core 标CMS后端Web框架上一篇如何用自动化脚本每天节省25分钟淘宝淘金币任务终极解决方案下一篇淘宝淘金币自动化脚本终极指南每天节省25分钟轻松赚取淘金币创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
阅读完成 · 觉得有帮助?
咨询建站