How to define a reusable custom function or code snippet (such as loop rendering article list items) in the Anqi CMS template?

Behind the powerful functions of AnQi CMS, the flexible use of templates is the key to improving efficiency and ensuring consistency of the website.As an experienced website operations expert, I know that in daily work, we always hope to achieve twice the result with half the effort.Today, let's delve deeply into a topic that can greatly enhance the efficiency of template development and maintenance: how to define and use reusable custom functions or code snippets in Anqi CMS templates, especially for common scenarios like rendering article list items in a loop.

Why do we need reusable code snippets?

In the digital age, content is king, and the forms of content presentation are diverse.An enterprise website may need to display the latest news articles on the homepage, recommend popular products in the sidebar, show related article lists on specific category pages, and even embed different content modules in other corners of the website.If we rewrite the code every time we encounter similar display requirements, it will be a huge waste of time and effort.

It is more important that repetitive code brings a series of maintenance problems: slight changes in style or structure require modifications in multiple places; inconsistent code logic may lead to uneven user experience; low development efficiency also slows down the website iteration speed.By defining reusable code snippets, we can easily achieve consistency, maintainability, improved development efficiency, and smoother updates and iterations.This is the practice of the “DRY” (Don’t Repeat Yourself) principle that we often say in template development in English.

The Anqi CMS uses a syntax similar to Django template engine, which provides a very friendly way to achieve code reuse, mainly reflected ininclude/extendsandmacrothese three tags.

Core reuse mechanism:includeWithextends

The most direct way to reuse code in ASecurity CMS is to useincludeLabel.It allows us to extract a snippet of HTML code (such as the header, footer, sidebar, or navigation menu) into an independent file and then simply reference it where needed.So, no matter how many pages need these common elements, we only need to maintain the code in one place, greatly simplifying the update work.

{# 引入网站头部 #}
{% include "partial/header.html" %}

{# 页面主体内容 #}
<main>
    <!-- 这里是页面的具体内容 -->
</main>

{# 引入网站底部 #}
{% include "partial/footer.html" %}

If thispartial/header.htmlrequires some dynamic data, such as the title of the current page, we can pass throughwithParameter passing:

{% include "partial/header.html" with page_title="关于我们" %}

whileextendsLabels provide a more macroscopic code reuse strategy, allowing us to define a "master" or "skeleton" template that other page templates can inherit. The skeleton template will define someblockArea, subtemplates can overwrite these areas to fill their own content. It's like creating a master slide in PowerPoint, where the theme and layout are fixed, and the content can be customized as needed.

a typicalbase.htmlThe skeleton may include a header, navigation, sidebar, footer, and a main content area namedcontent:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>{% block title %}默认标题 - {% system with name="SiteName" %}{% endblock %}</title>
    {# 其他公共CSS和JS文件 #}
</head>
<body>
    {% include "partial/header.html" %}
    <div class="container">
        {% block content %}
            <!-- 默认内容或为空 -->
        {% endblock %}
    </div>
    {% include "partial/footer.html" %}
</body>
</html>

Then, a specific page, such as an article list pagearticle/list.htmlcan inherit thisbase.htmlFill in your content:

{% extends 'base.html' %}

{% block title %}文章列表 - {% system with name="SiteName" %}{% endblock %}

{% block content %}
    <div class="article-list">
        <h1>最新文章</h1>
        <!-- 这里将是文章列表的具体渲染逻辑 -->
    </div>
{% endblock %}

PassextendsWe ensure that the overall structure and common elements of all pages are consistent, while only focusing on the unique content part of each page.

Define reusable code functions:macroThe art of tags

AlthoughincludeandextendsIt provides powerful reuse capabilities at the structural level, but when we face more granular, parameterized dynamic content rendering needs,macroLabels are particularly important.macroIt can be understood as a 'function' in the template, which accepts parameters and renders a specific HTML fragment based on these parameters.This is tailor-made for scenarios like rendering list items in loops.

Imagine that we need to display article lists at different locations on the website (such as the "Latest Articles" block on the homepage, the article lists on category pages, and the search results page).Each article's display format may include the title, summary, publish time, thumbnail, etc., and these formats may vary slightly between different blocks or may need to hide specific elements in certain cases.If we write complex HTML structures in each list loop, it will be very long and difficult to maintain.

This is,macrocan show off. We can define a macro, specifically responsible for rendering a single article list item:

Firstly, we can define this macro in a separate template file (for examplemacros/article_items.html):

{# macros/article_items.html #}
{% macro render_article_item(article, show_thumbnail=true, custom_class='') %}
<li class="article-item {{ custom_class }}">
    {% if show_thumbnail and article.Thumb %}
    <a href="{{ article.Link }}" class="article-thumb">
        <img src="{{ article.Thumb }}" alt="{{ article.Title }}">
    </a>
    {% endif %}
    <div class="article-content">
        <h3 class="article-title"><a href="{{ article.Link }}">{{ article.Title }}</a></h3>
        <p class="article-description">{{ article.Description|truncatechars:100 }}</p>
        <div class="article-meta">
            <span>发布日期:{{ stampToDate(article.CreatedTime, "2006-01-02") }}</span>
            <span>浏览量:{{ article.Views }}</span>
        </div>
    </div>
</li>
{% endmacro %}

In this macro,render_article_itemaccepts three parameters:

  • article: The article object to be rendered, usuallyarchiveListIn the loopitem.
  • show_thumbnail: A boolean value, default istrue, used to control whether to display the article thumbnail.
  • custom_classAn English string, default is empty, allowing us to add custom CSS classes to list items.

Define the macro after which we can then import it at any location where we need to render the article list, andarchiveListcall it in the loop.

For example, in the "Latest Articles" block on the homepage:

{# index.html 或其他需要用到宏的模板 #}
{% import "macros/article_items.html" as article_macros %}

<div class="latest-articles">
    <h2>最新文章</h2>
    <ul>
    {% archiveList archives with type="list" moduleId="1" limit="5" %}
        {% for item in archives %}
            {{ article_macros.render_article_item(item, show_thumbnail=true, custom_class='latest-item') }}
        {% empty %}
            <li>暂无最新文章。</li>
        {% endfor %}
    {% endarchiveList %}
    </ul>
</div>

While in the sidebar's 'Hot Recommendations', we may not want to display thumbnails and use a different style:

<div class="hot-recommendations">
    <h3>热门推荐</h3>
    <ul>
    {% archiveList hot_articles with type="list" moduleId="1" flag="c" order="views desc" limit="3" %}
        {% for item in hot_articles %}
            {{ article_macros.render_article_item(item, show_thumbnail=false, custom_class='hot-item') }}
        {% empty %}
            <li>暂无热门推荐。</li>
        {% endfor %}
    {% endarchiveList %}
    </ul>
</div>

You can see that by:macroWe successfully encapsulated the complex list item rendering logic and can flexibly control its display behavior through parameters.This not only makes the template code more tidy, but also makes it easy to modify or expand the display style of the article list.

Flexible variables and data transmission:withandset

In utilizinginclude/extends