Building a “Lightweight Knowledge Index” for My Blog (Part 9): From Knowledge Maps to First-Visit Welcome Cards
Article Abstract
To address the issue where first-time visitors to a personal blog lack an overall perception of its content, the author designed a “First-Visit Prompt Card” to provide navigational guidance. Based on the blog's existing knowledge map system, this solution automatically pops up a lightweight prompt card containing core topic introductions and an entry point to the knowledge map upon a user's first visit. It supports manual closing or automatic dismissal after 15 seconds, and records the visit status via browser local storage to re-trigger after 180 days. In terms of implementation, PHP is used to construct the structure, JavaScript controls the display logic and status recording, and CSS handles the visual design, avoiding the introduction of complex plugins and server-side dependencies. As the final link in the knowledge index system, this feature resolves the crucial gap of “how users discover content boundaries,” forming a complete closed loop for the blog from content organization and semantic correlation to user cognition, while maintaining lightweight, self-controllable technical characteristics.
Qwen3-14B · 2026-10-23

1 A Problem That Could Never Be Closed-Loop

Over the past few months, after gradually adding article-level knowledge indexing features to the blog (content structure hints, related articles, article series cards, AI summaries, right-side menu, etc.), combined with the global-level “Blog Knowledge Map” that has been maintained all along, my blog has finally taken a big step toward the goal of becoming a “personal mini knowledge base.” At least for visitors, no matter which article they enter the blog from, it is no longer easy to get lost.

Still, I always felt that the entire system was missing one final, critical piece. The problem seemed to be right there, yet it was hard to put into precise words at the time. So over the next week or two, I began experimenting with various approaches around this vague issue.

At first, I thought what was missing was search capability. As the number of articles grew, traditional categories and tags struggled more and more to meet content discovery needs, so I started exploring semantic search, hoping to use embeddings and vector retrieval technology to let visitors find content of interest via natural language.

But as I thought and experimented further, I gradually realized that the problem might not lie there. For enterprise documentation sites, official product pages, or SaaS platforms, users usually understand what knowledge system they are in. For example, visitors to Cloudflare's official documentation typically know they are looking for Cloudflare-related content and can thus ask relatively specific questions.

Personal blogs are different: most visitors land directly on a specific article via search engines, seeing only a solution to one particular problem. They might arrive at my blog because of Cloudflare Tunnel, WordPress, AI, home data centers, music cognition, or even cognitive thinking essays, yet they may not know what other topics are covered here.

This means search solves the problem of “knowing what you are looking for,” whereas readers visiting a personal blog for the first time often do not yet know what is worth looking for here. If they don't even know the scope of the blog's content, it's naturally hard to formulate effective search queries. Therefore, what visitors really lack is not a search tool, but an awareness of the blog's overall content boundaries.

In fact, my blog does not lack corresponding navigation systems. Previously, I had pinned the “Blog Knowledge Map” on the homepage and maintained entry points like the Cloudflare Learning Map, AI Learning Map, and Music & Sound Cognition Special Topic Map. As long as visitors enter these map pages, they can intuitively understand the blog's main research directions and the articles under each topic.

The real problem is that most visitors do not start browsing from the homepage; they are more likely to land directly on a specific article via search engines, and the existence of a knowledge map does not mean first-time readers will discover it. Therefore, what I needed to solve was not adding yet another navigation system, but how to guide visitors into the existing one.

Once I realized this, the problem finally became clear: how can I let first-time visitors to the blog know what content is actually here in the shortest possible time?

Centered on this goal, I explored various options such as FAQs, live2d mascots, and bubble menus, hoping to add a tour entry point to the blog. But as testing went deeper, I found that although these options differed in form, they shared a common trait: they all tended to make the tour feature permanently present on the page.

However, for the vast majority of visitors, the only moment they truly need a guide might be during their very first visit to the blog. Once I understood this, the solution became straightforward: I didn't need a persistent floating assistant on the page, nor a complex Q&A system, but rather a “first-visit welcome card” that appears only on the first visit and automatically disappears once the introduction is complete.


PS: In fact, I had previously researched off-the-shelf WordPress popup plugins like Popup Maker and Popup Builder. While they can achieve similar effects, most are geared toward marketing scenarios and come loaded with many features I don't actually need. For a tour feature with such clear requirements and simple logic, rather than introducing a complex general-purpose plugin, it's better to implement it myself using PHP, CSS, and a small amount of JavaScript. This allows customization based on the blog's actual needs and aligns with my long-standing philosophy of pursuing lightweight builds and reducing plugin dependencies.


2 Implementation of the First-Visit Welcome Card

1 Implementation Concept

Having decided on a custom implementation, the first thing to consider was how this welcome card should work. I set a design principle for myself:Keep it as simple as possible.

Because the goal of this feature is neither to add a new interaction system nor to build a complex user onboarding flow, but simply to help first-time readers quickly build an overall awareness of the blog's content. Therefore, it shouldn't take up too much page space, shouldn't require extra actions from visitors, and above all shouldn't disrupt normal reading for an extended period.

Based on this principle, I ultimately decided on the following logic:

     访客进入博客
         ↓
  判断是否已经看过提示卡
          ↓
   否            是
   ↓             ↓
显示提示卡     直接浏览
   ↓
点击按钮
或等待15秒
   ↓
关闭提示卡
   ↓
记录访问状态
   ↓
XX天内不再显示
   ↓
XX天后重新显示

The entire process looks fairly simple, but several design details within it were actually refined through repeated deliberation.

First, the display timing

I didn't restrict the welcome card to showing only on the homepage; instead, I allowed it to appear on the homepage, article pages, and other pages on a first visit. The reason is simple: most visitors do not enter the blog through the homepage. For a personal blog, the more common visit path is often:

搜索引擎(或者反向链接)
        ↓
    某篇具体文章
        ↓
       阅读
        ↓
       离开

If the welcome card only appeared on the homepage, the vast majority of visitors arriving via search engines would never see it, and the tour feature would naturally lose its purpose. Therefore, no matter where a visitor enters the blog, as long as it is their first visit, they should have the chance to see this welcome card.

Second, the auto-close mechanism

During the initial design phase, I considered requiring visitors to actively click a button to dismiss the welcome card, but quickly found that this approach created a subtle sense of coercion. For visitors, whether clicking “View Blog Knowledge Map” or clicking “Start Browsing,” it essentially became a mandatory multiple-choice question, which clearly runs counter to a good reading experience.

So I later changed it to an auto-close mode: visitors can either proactively click a button to take action, or do nothing and wait for the countdown to end for it to close automatically. This makes the welcome card feel more like a tour guide stepping forward to introduce themselves, rather than a guard standing at the door waiting for confirmation.

Regarding the countdown duration, I initially tried 10 seconds. But after actual testing, I found that for a welcome card containing multiple lines of introductory content, 10 seconds was noticeably too short—visitors often hadn't finished reading before the welcome card disappeared on its own. So it was ultimately adjusted to 15 seconds. This duration ensures most visitors have enough time to read without lingering so long that it impairs the normal browsing experience.

Finally, the visit state recording mechanism

If the welcome card popped up on every single visit to the blog, no matter how well-designed the content, it would quickly become an annoyance. Therefore, the welcome card does not display permanently, but rather uses a visit state recording mechanism to control its display frequency.

The state record here is essentially just a front-end display flag, requiring no server-side evaluation. For a purely front-end interaction scenario like a welcome card,localStorage is much better suited as a small local state storage method in the browser. Therefore, compared to cookies that need to be sent to the server with HTTP requests, I ultimately chose to use localStorage to store the visit timestamp.

Considering that the blog's content continues to expand over time, its structure and thematic focus half a year later might already differ from today. Thus, instead of hiding it permanently, I set it to reappear after 180 days. This avoids repeatedly disturbing returning visitors while re-introducing the blog's latest development directions to them over a longer time horizon.

In actual operation, each time a visitor enters the blog, JavaScript attempts to read the visit timestamp saved in the browser's localStorage and checks whether the display criteria are met based on the current time, thereby deciding whether to show the welcome card again.


Additionally, when designing the first-visit prompt, there is another easily overlooked issue: how to proactively introduce the blog's overall information without disrupting the visitor's normal browsing experience?

For personal blogs, visitors usually arrive with a specific purpose, especially users landing directly on an article via search engines—they want to find a quick solution to their current problem. Therefore, the welcome card must proactively showcase the blog's overall information without turning into a reading-blocking modal popup. To this end, the welcome card should not require visitors to take mandatory actions, but should allow them to actively dismiss it or wait for it to fade away automatically; the display frequency must be controlled to avoid repeated annoyance; and the prompt content should center on information visitors genuinely need, rather than turning into marketing recommendations or forced onboarding.

Based on these principles, the final approach employs a first-visit display, automatic closing, and a mechanism that reappears every 180 days, making the welcome card feel more like a proactive introduction rather than an interactive barrier preventing users from continuing to browse.

Once these details were settled, the remaining work became much simpler: using PHP to output the prompt card structure, CSS for styling and animations, and a small amount of JavaScript to implement the first-visit detection, auto-close, and state-recording logic.

2 Code Implementation

2.1 Feature Implementation: PHP & JavaScript

Once the overall logic was determined, the actual implementation was not complex; the entire welcome card feature mainly consists of two parts:

  • PHP is responsible for outputting the welcome card structure;
  • JavaScript is responsible for visit status detection, auto-closing, and recording visits.

The complete implementation code is provided directly below:

function twd_welcome_card() {
?>
<div id="welcome-card">
    <div class="welcome-card-content">
        <h2>👋 Welcome to “Wudi's Personal Blog”</h2>
        <p class="welcome-card-desc">Here, long-term exploration is mainly carried out around the following directions:</p>
        <div class="welcome-card-topics">
            <div class="topic-item">🧱 Personal Digital Infrastructure and Blog System Construction</div>
            <div class="topic-item">☁️ Cloudflare and Network Architecture Practice</div>
            <div class="topic-item">🧠 AI and Knowledge System Exploration</div>
            <div class="topic-item">🛡️ Network Security and Access Optimization</div>
            <div class="topic-item">🎵 Music and Sound Cognition</div>
            <div class="topic-item">👁️ Cognitive Perspectives and Worldviews</div>
        </div>
        <div class="welcome-card-footer">
            <p>📚 It is recommended to read the "Blog Knowledge Map" first to quickly understand the overall content structure and reading path of the blog.</p>
            <div class="welcome-card-buttons">
                <a href="/en/roadmap/" class="welcome-btn-primary welcome-close">View Blog Knowledge Map</a>
                <button type="button" class="welcome-btn-secondary welcome-close">Continue Exploring</button>
            </div>
            <div class="welcome-auto-close">
                First-time visit guide prompt, will close automatically
                <div class="welcome-progress">
                    <div class="welcome-progress-bar"></div>
                </div>
            </div>
        </div>
    </div>
</div>

<script>
document.addEventListener('DOMContentLoaded', function(){
    const card = document.getElementById('welcome-card');
    if(!card) return;

    const key = 'twd_welcome_seen';
    const expireTime = 180 * 24 * 60 * 60 * 1000;
    const seenTime = localStorage.getItem(key);

    if(seenTime && (Date.now() - Number(seenTime)) < expireTime) return;

    card.style.display = 'flex';
    card.style.opacity = '1';

    function closeWelcome(){
        card.style.opacity = '0';
        setTimeout(function(){
            card.style.display = 'none';
        }, 300);
        localStorage.setItem(key, Date.now());
    }

    document.querySelectorAll('.welcome-close').forEach(function(btn){
        btn.addEventListener('click', closeWelcome);
    });

    setTimeout(closeWelcome, 15000);
});
</script>
&lt;?php;


From an implementation perspective, the entire feature actually revolves around four core logics.

The Structure of the Visit Prompt Card Itself

The PHP part is primarily responsible for outputting the HTML structure of the welcome card, including the welcome heading, an introduction to the blog's core focus areas, the knowledge map entry button, and automatic closing prompt information.

Since this part of the content is essentially just a page display structure and does not involve complex business logic, it can be directly output by PHP.

JavaScript Display Logic

Next comes the JavaScript logic.

After the page finishes loading, the script first attempts to read the timestamp stored in the browser's localStorage .

If no record exists, it indicates that this is a first visit; if a record exists, it further determines whether the time elapsed since the last recorded time has exceeded the configured 180-day cycle, thereby deciding whether to display the welcome card again.

When it is determined that display is needed, JavaScript will reveal the prompt card and restore its corresponding opacity state.

Closing the Visit Prompt Card

Once the visit prompt card is displayed, visitors can either actively click the button to close it or wait for the 15-second countdown to finish for it to close automatically.

Although the trigger methods differ, both ultimately call the same closing function, ensuring that the behavioral logic of the entire closing process remains consistent.

Status Recording

While closing the welcome card, the system writes the current timestamp into localStorage。

During subsequent visits to the blog, the script reads this time information to determine whether more than 180 days have passed since the last closure, thereby deciding whether the prompt card needs to be shown again.


The entire implementation process does not introduce any additional plugins, nor does it rely on databases or server-side storage. All states are stored locally in the browser, making the overall implementation extremely lightweight and placing virtually no extra burden on WordPress itself. For scenarios with a single function and clear logic like this, a custom implementation is often more concise and efficient than a generic modal popup plugin.

2.2 Styling Implementation: CSS

After the functionality is implemented, the remaining work is the visual presentation of the welcome card. Since this feature is essentially positioned as a one-time visit guide, I did not pursue complex animations or overly intense visual effects in the style design, but rather tried to keep it consistent with the blog's existing style.

The entire design follows several principles:

  • Minimize interference with reading the body text;
  • Maintain a concise and clear information display;
  • Highlight the core entry point of the “Blog Knowledge Map”;
  • Allow visitors to finish reading in a short time.

Therefore, a centered floating overlay card format was ultimately adopted, using a semi-transparent background to achieve a page focusing effect. The complete CSS is as follows:

/* =========================
   Welcome Card
========================= */

#welcome-card {
    position: fixed;
    inset: 0;
    z-index: 999999;
    display: none;
    opacity: 1;
    transition: opacity .3s ease;
    align-items: center;
    justify-content: center;
    background: rgba(0,0,0,.35);
}

.welcome-card-content {
    width: min(90%, 620px);
    background: #fff;
    border-radius: 16px;
    padding: 32px;
    box-shadow: 0 10px 30px rgba(0,0,0,.15);
    text-align: center;
}

.welcome-card-content h2 {
    margin-top: 0;
    margin-bottom: 20px;
}

.welcome-card-desc {
    color: #666;
    line-height: 1.8;
    margin-bottom: 24px;
}

.welcome-card-topics {
    text-align: left;
    margin: 24px 0;
}

.topic-item {
    margin: 12px 0;
    font-size: 15px;
}

.welcome-card-footer p {
    color: #888;
    line-height: 1.6;
    margin-bottom: 20px;
}

.welcome-card-buttons {
    display: flex;
    justify-content: center;
    gap: 12px;
}

.welcome-btn-primary,
.welcome-btn-secondary {
    padding: 10px 20px;
    border-radius: 8px;
    cursor: pointer;
    text-decoration: none;
    font-size: 14px;
}

.welcome-btn-primary {
    background: #4f46e5;
    color: #fff;
}

.welcome-btn-secondary {
    background: #eee;
    border: none;
}

.welcome-progress {
    width: 100%;
    height: 3px;
    background: rgba(0,0,0,.08);
    margin-top: 12px;
    overflow: hidden;
    border-radius: 3px;
}

.welcome-progress-bar {
    width: 100%;
    height: 100%;
    background: rgba(0,0,0,.25);
    animation: welcome-countdown 15s linear forwards;
}

@keyframes welcome-countdown {
    from {
        width: 100%;
    }
    to {
        width: 0%;
    }
}

From an implementation perspective, this part of the styling mainly accomplishes several tasks.

First, through the fixed-positioned centered overlay and the semi-transparent background mask, the welcome card is placed above the visitor's current reading environment. This design not only highlights the importance of the first-visit guide, but also avoids making visitors feel as if they have entered an entirely separate page, thereby reducing the disjointed feeling brought by page transitions.

Second, by hierarchically laying out the heading, content introduction, list of blog topic directions, and action buttons, visitors can understand the blog's main content directions in a relatively short time and discover the core navigation entry point of the “Blog Knowledge Map.”

In terms of button design, I adopted a primary-secondary separation approach. “View Blog Knowledge Map” acts as the primary guiding entrance and uses a more prominent visual style; “Continue Exploring” remains relatively understated, allowing visitors to choose their next action based on their own needs rather than being forced into a specific page.

In addition, an auto-close progress bar is added to the bottom of the welcome card to indicate that the current guide card will not stay permanently, but will automatically disappear after a period of time. Compared to directly displaying a numeric countdown, this approach softens time pressure while enabling visitors to clearly perceive that the prompt card has an automatic closing mechanism.

The entire style implementation likewise does not rely on any third-party components, accomplishing the layout, visual effects, and countdown animation purely through CSS. For most WordPress themes, it can be reused simply by making minor adjustments according to their own color schemes.

2.3 Showcase of Actual Results

After the above implementation, the first-visit guide feature is fully functional.

When a visitor enters the blog for the first time, if entering from the homepage, the system will automatically pop up the welcome card, providing a brief introduction to the blog's primary content directions and offering the entrance to the blog knowledge map.

Homepage effect screenshot:

image.png

Visitors arriving at an article page from search engines can also see the welcome card. This is also a scenario heavily considered during the design of the entire solution, because the vast majority of personal blog visitors do not actually start browsing from the homepage.

Article page effect screenshot:

image.png

The welcome card supports two closing methods: actively clicking the button to close and waiting for the 15-second auto-close. After closing, the system records the current time locally in the browser and will not display it again for the next 180 days.

At this point, a lightweight tour guide system specifically tailored for personal blog first-visit scenarios has been built.

3 The Final Gap in the Lightweight Knowledge Index

Looking back at the entire “Building a Lightweight Knowledge Index for a Blog” series, one can see that this series is not simply about adding a few standalone features to the blog, but about gradually refining the entire process of blog content from organization to presentation.

Initially, although articles in the blog formed certain connections through categories, tags, and manually maintained structures, the content relationships perceptible to visitors were still relatively limited. With the addition of features such as related posts and series post cards, articles began to form a richer content network based on relationships like topics and order. Later, introducing AI summaries and Embedding-based semantic computation expanded content organization from traditional taxonomy and manual linking into a semantic layer that machines can understand and compute; the right-hand menu further transformed these relationships into navigation entry points that visitors can directly use.

But having content organized does not necessarily mean visitors can understand this system. Therefore, the first-visit prompt card added at the end does not duplicate existing features, but rather supplements a new entrance on top of the existing knowledge system: previous features solve “how to continue exploring after entering the blog,” while the prompt card solves “how to quickly understand what is here when entering the blog for the first time.”

Of course, this feature also has a prerequisite: the blog itself must already possess a certain level of content organization capability. Without clear content directions, curated navigation entries, and an inter-article connection system, the prompt card could only serve as a simple introduction without truly helping visitors comprehend the content structure.

From this perspective, the entire lightweight knowledge index system has formed a relatively complete chain: starting from articles, establishing content connections through structured relationships and semantic computation, presenting these connections to visitors via various display methods, and finally lowering the barrier to understanding the entire knowledge system with the help of the first-visit guide. This also means that the blog's evolutionary direction is no longer just about adding more articles, but about gradually building a small-scale knowledge system centered around content organization, semantic understanding, and user discovery.

The entire process continues to adhere to an important principle: keep it as lightweight as possible—it does not introduce complex backend systems or rely on third-party platforms, but gradually enhances capabilities on top of WordPress's native structure through minimal code and offline computation. For a personal blog, this approach is not meant to replace large-scale knowledge management systems, but rather to grant long-accumulated content higher discoverability and utility value at limited cost.

At this point, the “Building a Lightweight Knowledge Index for a Blog” series has completed its final chapter: from content organization to semantic enhancement, and onward to the user cognitive entrance, the entire system has formed a relatively complete closed loop.

📚 Series Articles: Building a “Lightweight Knowledge Index” for a Blog (9 / 9)

View Related Categories · 3 Matches
📌 Content Structure Prompt:
This content is part of the following knowledge map, where you can view the complete content path: WordPress Learning Roadmap。
📎 Related Articles
Share this article
The blog content is original, please indicate the source when reposting! The RSS address of the blog is:https://blog.tangwudi.com/feed, welcome to subscribe; if needed, you can join theTelegram Groupto discuss questions together.
No Comments

Send Comment Edit Comment


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗ
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
Kaomoji
Emoji
Little Dinosaur
Flower!
Previous
       

👋 Welcome to “Wudi's Personal Blog”

Here, long-term exploration is mainly carried out around the following directions:

🧱 Personal Digital Infrastructure and Blog System Construction
☁️ Cloudflare and Network Architecture Practice
🧠 AI and Knowledge System Exploration
🛡️ Network Security and Access Optimization
🎵 Music and Sound Cognition
👁️ Cognitive Perspectives and Worldviews