@@ -6,12 +6,14 @@ public class WebsiteDiscoveryProvider(
66 IProgressiveCache cache ,
77 IWebsiteChannelContext website ,
88 IContentQueryExecutor executor ,
9- IWebsiteDiscoveryOptions options ) : IWebsiteDiscoveryProvider
9+ IWebsiteDiscoveryOptions options ,
10+ IHttpContextAccessor httpContextAccessor ) : IWebsiteDiscoveryProvider
1011{
1112 private readonly IProgressiveCache cache = cache ;
1213 private readonly IWebsiteChannelContext website = website ;
1314 private readonly IContentQueryExecutor executor = executor ;
1415 private readonly IWebsiteDiscoveryOptions options = ValidateOptions ( options ) ;
16+ private readonly IHttpContextAccessor httpContextAccessor = httpContextAccessor ;
1517
1618 private static IWebsiteDiscoveryOptions ValidateOptions ( IWebsiteDiscoveryOptions options )
1719 {
@@ -50,23 +52,51 @@ public async Task<ActionResult> GenerateSitemap()
5052 var sitemapItems = await GetSitemapPages ( ) ;
5153 return new SitemapProvider ( ) . CreateSitemap ( new SitemapModel ( sitemapItems ) ) ;
5254 }
53- public async Task < List < SitemapNode > > GetSitemapPages ( ) =>
55+
56+ public async Task < ActionResult > GenerateLlmsTxt ( )
57+ {
58+ var pages = await GetSitemapPagesWithDetails ( ) ;
59+ var sb = new StringBuilder ( ) ;
60+ var currentRequest = httpContextAccessor . HttpContext ? . Request ;
61+
62+ sb . AppendLine ( $ "# { website . WebsiteChannelName } ") ;
63+ sb . AppendLine ( ) ;
64+ sb . AppendLine ( "## Pages" ) ;
65+ sb . AppendLine ( ) ;
66+
67+ foreach ( var page in pages )
68+ {
69+ string title = ! string . IsNullOrWhiteSpace ( page . Title ) ? page . Title : page . SystemFields . WebPageItemName ;
70+ string relativeUrl = page . SystemFields . WebPageUrlPath ;
71+ string url = currentRequest != null ? relativeUrl . AbsoluteURL ( currentRequest ) : relativeUrl ;
72+
73+ if ( ! string . IsNullOrWhiteSpace ( page . Description ) )
74+ {
75+ sb . AppendLine ( $ "- [{ title . CleanHtml ( ) . EscapeMarkdown ( ) . Replace ( "’s" , "" ) } ]({ url . ToLower ( ) } ): { page . Description . CleanHtml ( ) . EscapeMarkdown ( ) . Replace ( "’s" , "" ) } ") ;
76+ }
77+ else
78+ {
79+ sb . AppendLine ( $ "- [{ title . CleanHtml ( ) . EscapeMarkdown ( ) . Replace ( "’s" , "" ) } ]({ url . ToLower ( ) } )") ;
80+ }
81+ }
82+
83+ return new ContentResult
84+ {
85+ Content = sb . ToString ( ) ,
86+ ContentType = "text/plain; charset=utf-8"
87+ } ;
88+ }
89+
90+ private async Task < List < SitemapPage > > GetSitemapPagesWithDetails ( ) =>
5491 await cache . LoadAsync ( cs =>
5592 {
5693 cs . CacheDependency = CacheHelper . GetCacheDependency ( BuildCacheDependencyKeys ( ) ) ;
5794
58- return GetSitemapNodesInternal ( ) ;
59- } , new CacheSettings ( 3 , [ nameof ( GetSitemapPages ) ] ) { } ) ;
95+ return GetSitemapPagesInternal ( ) ;
96+ } , new CacheSettings ( 60 , [ nameof ( GetSitemapPagesWithDetails ) ] ) { } ) ;
6097
61- private string [ ] BuildCacheDependencyKeys ( ) =>
62- options . ContentTypeDependencies
63- . Select ( t => $ "webpageitem|bychannel|{ website . WebsiteChannelName } |bycontenttype|{ t } ")
64- . ToArray ( ) ;
65-
66- private async Task < List < SitemapNode > > GetSitemapNodesInternal ( )
98+ private async Task < List < SitemapPage > > GetSitemapPagesInternal ( )
6799 {
68- var nodes = new List < SitemapNode > ( ) ;
69-
70100 var b = new ContentItemQueryBuilder ( )
71101 . ForContentTypes ( c => c
72102 . OfReusableSchema ( options . ReusableSchemaName )
@@ -104,13 +134,29 @@ private async Task<List<SitemapNode>> GetSitemapNodesInternal()
104134 } , isInSitemap , title , description ) ;
105135 } ) ;
106136
107- foreach ( var page in pages )
137+ return pages . Where ( p => p . IsInSitemap ) . ToList ( ) ;
138+ }
139+
140+ public async Task < List < SitemapNode > > GetSitemapPages ( ) =>
141+ await cache . LoadAsync ( cs =>
108142 {
109- if ( ! page . IsInSitemap )
110- {
111- continue ;
112- }
143+ cs . CacheDependency = CacheHelper . GetCacheDependency ( BuildCacheDependencyKeys ( ) ) ;
144+
145+ return GetSitemapNodesInternal ( ) ;
146+ } , new CacheSettings ( 60 , [ nameof ( GetSitemapPages ) ] ) { } ) ;
147+
148+ private string [ ] BuildCacheDependencyKeys ( ) =>
149+ options . ContentTypeDependencies
150+ . Select ( t => $ "webpageitem|bychannel|{ website . WebsiteChannelName } |bycontenttype|{ nameof ( WebsiteDiscoveryProvider ) } |{ t } ")
151+ . ToArray ( ) ;
113152
153+ private async Task < List < SitemapNode > > GetSitemapNodesInternal ( )
154+ {
155+ var pages = await GetSitemapPagesInternal ( ) ;
156+ var nodes = new List < SitemapNode > ( ) ;
157+
158+ foreach ( var page in pages )
159+ {
114160 var node = new SitemapNode ( page . SystemFields . WebPageUrlPath )
115161 {
116162 LastModificationDate = DateTime . Now ,
0 commit comments