Class Sealed
public sealed class PostProcessPhase : IBuildPhase

Namespace: Moka.Docs.Engine.Phases

Generates sitemap.xml and robots.txt in the output directory.

Inheritance

Inherits from: IBuildPhase

Constructors

NameDescription
PostProcessPhase(PostProcessPhase> logger) Generates sitemap.xml and robots.txt in the output directory.

PostProcessPhase(PostProcessPhase> logger)

PostProcessPhase.PostProcessPhase(ILogger<PostProcessPhase> logger)

Generates sitemap.xml and robots.txt in the output directory.

Properties

NameDescription
Name
Order

Methods

Type Relationships
classDiagram
                    style PostProcessPhase fill:#f9f,stroke:#333,stroke-width:2px
                    PostProcessPhase --|> IBuildPhase : inherits
                
View Source
/// <summary>
///     Generates sitemap.xml and robots.txt in the output directory.
/// </summary>
public sealed class PostProcessPhase(ILogger<PostProcessPhase> logger) : IBuildPhase
{
    /// <inheritdoc/>
    public string Name => "PostProcess";
    /// <inheritdoc/>
    public int Order => 1200;

    /// <inheritdoc/>
    public Task ExecuteAsync(BuildContext context, CancellationToken ct = default)
    {
        IFileSystem fs = context.FileSystem;
        string outputDir = context.OutputDirectory;
        if (context.Config.Build.Sitemap)
        {
            WriteSitemap(context, fs, outputDir);
        }

        if (context.Config.Build.Robots)
        {
            WriteRobotsTxt(context, fs, outputDir);
        }

        return Task.CompletedTask;
    }

    private void WriteSitemap(BuildContext context, IFileSystem fs, string outputDir)
    {
        string baseUrl = context.Config.Site.Url.TrimEnd('/');
        if (string.IsNullOrEmpty(baseUrl))
        {
            logger.LogDebug("No site URL configured, skipping sitemap generation");
            return;
        }

        var sb = new StringBuilder();
        sb.AppendLine("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
        sb.AppendLine("<urlset xmlns=\"http://www.sitemaps.org/schemas/sitemap/0.9\">");
        foreach (DocPage page in context.Pages)
        {
            if (page.FrontMatter.Visibility != PageVisibility.Public)
            {
                continue;
            }

            string url = baseUrl + page.Route;
            string lastmod = page.LastModified?.ToString("yyyy-MM-dd") ?? "";
            sb.AppendLine("  <url>");
            sb.AppendLine($"    <loc>{url}</loc>");
            if (!string.IsNullOrEmpty(lastmod))
            {
                sb.AppendLine($"    <lastmod>{lastmod}</lastmod>");
            }

            sb.AppendLine("  </url>");
        }

        sb.AppendLine("</urlset>");
        string path = fs.Path.Combine(outputDir, "sitemap.xml");
        fs.File.WriteAllText(path, sb.ToString());
        logger.LogInformation("Generated sitemap.xml with {Count} URLs", context.Pages.Count(p => p.FrontMatter.Visibility == PageVisibility.Public));
    }

    private void WriteRobotsTxt(BuildContext context, IFileSystem fs, string outputDir)
    {
        string baseUrl = context.Config.Site.Url.TrimEnd('/');
        var sb = new StringBuilder();
        sb.AppendLine("User-agent: *");
        sb.AppendLine("Allow: /");
        if (!string.IsNullOrEmpty(baseUrl))
        {
            sb.AppendLine($"Sitemap: {baseUrl}/sitemap.xml");
        }

        string path = fs.Path.Combine(outputDir, "robots.txt");
        fs.File.WriteAllText(path, sb.ToString());
        logger.LogInformation("Generated robots.txt");
    }
}
Was this page helpful?