When Markdown-rendered HTML content needs further processing, how to use filters in a chain?

Security BLOG 2025-11-08 78 Reads

AnQi CMS with its flexible content management and powerful template functions, helps us build and operate websites efficiently.For operators and developers accustomed to writing content in Markdown, the good support for Markdown in the new Anqi CMS is undoubtedly a blessing.It not only makes content creation more convenient, but also allows content to be presented in an elegant HTML form on the front end.

However, after the Markdown content is rendered into HTML by the system, we may find that these HTML contents still need further refinement, such as generating summaries, removing specific tags to keep it concise, or making other format adjustments.At this time, the chained filter usage feature provided by AnQiCMS is particularly important, as it allows us to flexibly control at various stages of content rendering.

Understand the rendering basics of Markdown content

In AnQiCMS, when you use the Markdown editor to write articles, product descriptions, or single-page content, the system will automatically convert the Markdown syntax to standard HTML structures when displayed on the front-end. This process occurs internally during template rendering, especially when you call such asarchive.Content/page.Contentorcategory.Contentsuch content field when.

It is worth noting that when calling the content field, you canrenderThe parameter is used to explicitly control whether to convert Markdown to HTML. For example, inarchiveDetailTagged,render=trueIt will indicate that the system should render Markdown content as HTML, whilerender=falseThe original Markdown text will be retained.

Generally, to ensure that the rendered HTML content is correctly parsed and displayed by the browser, rather than being escaped as plain text, we need to use immediately after the content variable|safeFilter. This is because AnQiCMS (like many modern template engines) defaults to escaping all output content to prevent potential XSS attacks.So, a typical Markdown content output would be something like this:

{% archiveDetail articleContent with name="Content" render=true %}
{{ articleContent|safe }}

HerearticleContentThe variable is initially passed throughrender=trueThe parameter is then converted to HTML, then|safeThe filter informs the template engine that this part of the HTML is safe, no need to escape it again, and it can be output directly.

Why do we need to use filters in a chained manner?

The content rendered by Markdown is HTML, but it is often 'native' HTML, which may not fully meet our final display needs. Imagine the following common scenarios:

  • Generate summary or preview:We hope to display a brief summary of each article on the article list page, rather than the full content of the article.This summary needs to retain some basic HTML formats (such as paragraphs, links), but it cannot be too long.
  • Content purification and simplification:Sometimes Markdown content includes HTML elements (such as images, video embeds, and specific levels of headings) that we do not want to display in certain scenarios, and we need to remove them.
  • Uniform Formatting:It may be necessary to apply some global text processing to the rendered HTML, such as unified link text processing,relattributes, or convert specific text patterns to links.

At this time, the filter chain of AnQiCMS comes into play.By connecting multiple filters in a pipeline, we can perform multi-step processing on the content, each step based on the result of the previous step.

Core filter and its chained application

Further processing of HTML content rendered from Markdown, the following are some commonly used filters:

  1. |safe:As mentioned before, it is the first key link in the chain, ensuring that HTML content is not escaped. It usually follows the variable rendering HTML content.

  2. |truncatechars_html:数字or|truncatewords_html:数字:

    • These filters are specifically used forTruncate HTML content safely. Compared to ordinary|truncatecharsor|truncatewordsDifferent, they can intelligently handle HTML tags, ensuring that the truncated HTML structure remains complete and valid, and avoiding layout issues caused by unclosed tags due to truncation.
    • truncatechars_htmlTruncate by character count (including the HTML tags themselves, but internally it adjusts intelligently).
    • truncatewords_htmlTruncate by word count.
    • Chaining example:Assuming we want to truncate the first 150 characters of the article (safe truncation in HTML), and display it on the list page.
      
      {% archiveDetail articleContent with name="Content" render=true %}
      <div class="article-summary">
          {{ articleContent|safe|truncatechars_html:150 }}
      </div>
      
  3. |striptagsor|removetags:"标签1,标签2":

    • |striptagsIt will remove all HTML tags from the HTML content, leaving only plain text. This is very useful when you need to extract a plain text summary from formatted content.
    • |removetags:"p,h1,img"It allows you to specify the HTML tags to be removed. For example, if you want the article summary to not display images and first-level headings, but keep other formats.
    • Chaining example:In the truncated summary, we also want to ensure that no image tags are displayed, making the content purer.
      
      {% archiveDetail articleContent with name="Content" render=true %}
      <div class="article-summary">
          {{ articleContent|safe|truncatechars_html:150|removetags:"img" }}
      </div>
      
      The meaning of this chain is: first render Markdown to HTML, then ensure the HTML is safe to output, then truncate the HTML content to 150 characters (while maintaining the HTML structure), and finally remove all<img>.
  4. |replace:"旧文本,新文本":

    • This filter can replace specific text in HTML strings.If you need to replace local text in rendered HTML content or insert specific identifiers.
    • Chaining example:Assuming we want to replace the specific keyword “AnQiCMS” with a linked version in all content (although it is more recommended to handle it at the source of Markdown, but this is for demonstration). “`twig {% archiveDetail articleContent with name=“Content” render=true %}