Hướng dẫn tạo màn hình khởi đầu (Started Screen) cho Init Live Search

Màn hình khởi đầu sẽ giúp người dùng khám phá nội dung hấp dẫn ngay khi mở hộp tìm kiếm của Init Live Search. Bài viết này hướng dẫn bạn cách tận dụng các REST API sẵn có như /categories, /tags, /recent để hiển thị chuyên mục, thẻ, bài viết mới và cho phép kích hoạt slash command tương ứng.

Hướng dẫn tạo màn hình khởi đầu (Started Screen) cho Init Live Search

Ý tưởng tổng thể

Thông thường khi mở Init Live Search, người dùng sẽ thấy một hộp tìm kiếm trống hoặc được đẩy thẳng vào slash command mặc định như /recent. Nhưng nếu bạn muốn tạo một ấn tượng đầu tiên thật “đỉnh” — một màn hình khởi động mang tính gợi mở, hấp dẫn — thì đây là lúc để tuỳ biến.

Chúng ta sẽ tận dụng hook ils:modal-opened để chờ đúng khoảnh khắc người dùng mở modal, rồi thực hiện fetch dữ liệu qua các REST API như danh mục, thẻ, bài mới. Kết quả là một màn hình chào mừng năng động, hiện đại, giúp dẫn dắt người dùng đi sâu hơn vào nội dung trang.

Các REST API được sử dụng

Init Live Search đã tích hợp sẵn nhiều endpoint hữu ích mà bạn có thể gọi trực tiếp, không cần viết thêm backend:

  • GET /initlise/v1/taxonomies?taxonomy=category – danh sách chuyên mục
  • GET /initlise/v1/taxonomies?taxonomy=post_tag – các thẻ phổ biến
  • GET /initlise/v1/recent – các bài viết mới nhất

Toàn bộ danh sách endpoint đã được tổng hợp tại danh sách Endpoint REST API trong Init Live Search.

Mã JavaScript mẫu

window.addEventListener('ils:modal-opened', async function () {
    const input = document.querySelector('#init-live-search-input');
    if (!input || input.value.trim()) return;

    const container = document.querySelector('.ils-results');
    container.innerHTML = '<p class="ils-loading">Đang tải gợi ý...</p>';

    const [categories, tags, recent] = await Promise.all([
        fetch('/wp-json/initlise/v1/taxonomies?taxonomy=category').then(r => r.json()),
        fetch('/wp-json/initlise/v1/taxonomies?taxonomy=post_tag').then(r => r.json()),
        fetch('/wp-json/initlise/v1/recent').then(r => r.json()),
    ]);

    container.innerHTML = `
        <div class="ils-welcome">
            <h3>Chủ đề phổ biến</h3>
            <ul>${categories.slice(0, 6).map(c => `<li><a href="${c.url}" target="_blank">${c.name}</a></li>`).join('')}</ul>

            <h3>Thẻ nổi bật</h3>
            <ul>${tags.slice(0, 6).map(t => `<li><a href="${t.url}" target="_blank">#${t.name}</a></li>`).join('')}</ul>

            <h3>Bài viết mới</h3>
            <ul>${recent.slice(0, 5).map(p => `<li><a href="${p.url}" target="_blank">${p.title}</a></li>`).join('')}</ul>
        </div>
    `;
});

CSS nhẹ nhàng

.ils-welcome { padding: 1rem; line-height: 1.6; }
.ils-welcome h3 { margin-top: 1.5rem; }
.ils-welcome ul { list-style: none; padding-left: 0; display: flex; flex-wrap: wrap; gap: 0.5rem; }
.ils-welcome li { background: #f2f2f2; padding: 0.4rem 0.6rem; border-radius: 4px; }

Ví dụ nâng cao: giao diện chào mừng hoàn chỉnh với UIkit

Để giao diện trông mượt và hiện đại hơn, bạn có thể tận dụng sẵn UIkit (nếu trang đã dùng), kết hợp với localStorage để cache kết quả — tránh việc gọi lại REST API mỗi lần mở modal.

Dưới đây là ví dụ đã được tối ưu:

  • Dùng uk-buttonuk-border-pill để hiển thị chuyên mục, thẻ nổi bật một cách sinh động.
  • Hiển thị danh sách bài viết mới bằng uk-list + uk-list-divider.
  • Tự động lưu cache vào localStorage với prefix ils-cache-*, đảm bảo bạn có thể dọn dẹp dễ dàng sau này bằng lệnh /clear.
window.addEventListener('ils:modal-opened', async function () {
    const input = document.querySelector('#init-live-search-input');
    if (!input || input.value.trim()) return;

    const container = document.querySelector('.ils-results');
    container.innerHTML = '<div class="uk-text-center uk-padding"><div uk-spinner></div></div>';

    function getCache(key) {
        const raw = localStorage.getItem('ils-cache-' + key);
        try { return raw ? JSON.parse(raw) : null; } catch { return null; }
    }

    async function fetchAndCache(key, url) {
        const res = await fetch(url).then(r => r.json());
        localStorage.setItem('ils-cache-' + key, JSON.stringify(res));
        return res;
    }

    const [categories, tags, recent] = await Promise.all([
        getCache('categories') ?? fetchAndCache('categories', '/wp-json/initlise/v1/taxonomies?taxonomy=category'),
        getCache('tags') ?? fetchAndCache('tags', '/wp-json/initlise/v1/taxonomies?taxonomy=post_tag'),
        getCache('recent') ?? fetchAndCache('recent', '/wp-json/initlise/v1/recent'),
    ]);

    container.innerHTML = `
        <div class="uk-padding-small uk-container">
            <h4 class="uk-heading-line uk-h5 uk-text-bold uk-text-muted uk-text-uppercase">
                <span><span uk-icon="icon: folder"></span> Chủ đề phổ biến</span>
            </h4>
            <div class="uk-flex uk-flex-wrap uk-margin-bottom uk-grid-small" uk-grid>
                ${categories.slice(0, 6).map(c => `
                    <div>
                        <a href="${c.url}" target="_blank" class="uk-button uk-button-default uk-button-small uk-border-pill">${c.name}</a>
                    </div>
                `).join('')}
            </div>

            <h4 class="uk-heading-line uk-h5 uk-text-bold uk-text-muted uk-text-uppercase">
                <span><span uk-icon="icon: tag"></span> Thẻ nổi bật</span>
            </h4>
            <div class="uk-flex uk-flex-wrap uk-margin-bottom uk-grid-small" uk-grid>
                ${tags.slice(0, 6).map(t => `
                    <div>
                        <a href="${t.url}" target="_blank" class="uk-button uk-button-text uk-border-pill">#${t.name}</a>
                    </div>
                `).join('')}
            </div>

            <h4 class="uk-heading-line uk-h5 uk-text-bold uk-text-muted uk-text-uppercase">
                <span><span uk-icon="icon: file-text"></span> Bài viết mới</span>
            </h4>
            <ul class="uk-list uk-list-divider">
                ${recent.slice(0, 10).map(p => `
                    <li>
                        <a href="${p.url}" target="_blank" class="uk-link-heading">${p.title}</a>
                    </li>
                `).join('')}
            </ul>
        </div>
    `;
});

Gợi ý: Bạn hoàn toàn có thể mở rộng thêm phần này bằng cách thêm nút “Xem thêm”, hoặc gắn thẳng link slash command như /popular, /category wordpress… Nếu bạn dùng giao diện không phải UIkit, chỉ cần thay class tương ứng — logic hoàn toàn không đổi.

Tại sao chỉ fetch khi modal được mở?

Việc fetch dữ liệu được thực hiện ngay khi người dùng mở modal, chứ không từ đầu trang, mang lại nhiều lợi ích rõ rệt:

  • Tiết kiệm tài nguyên: không phải tải ồ ạt các endpoint khi người dùng chưa cần.
  • Chính xác về ngữ cảnh: chỉ khi người dùng mở tìm kiếm là lúc họ thực sự có nhu cầu.
  • Hiệu suất tối ưu: giữ site nhẹ và nhanh, tránh gây tải cho server.

Đây chính là triết lý “Lazy Load on Intent” — chỉ phản hồi khi hành vi thực sự xảy ra, không đoán mò, không thừa thãi.

Mở rộng thêm

Bạn có thể dễ dàng nâng cấp màn hình chào mừng bằng cách bổ sung thêm các REST API khác:

  • Gợi ý sản phẩm từ WooCommerce: GET /initlise/v1/product
  • Bài viết theo ngày đăng: GET /initlise/v1/date
  • Nội dung ngẫu nhiên hoặc phổ biến: GET /initlise/v1/random, /popular nếu có định nghĩa

Tất cả đều có thể gắn link để người dùng click, hoặc tự động điền slash command tương ứng vào input — cực kỳ linh hoạt, tuỳ UI/UX bạn thiết kế.

Bình luận


1 bình luận
  • Admin

    05/06/2025 lúc 13:46

    đoạn code nâng cao, cũng chính là JS mở rộng dùng cho chính blog này, bạn có thể thử mở tìm kiếm để xem demo trực tiếp nhé 👍

Init Toolbox

Nhấn Ctrl + \ trên máy tính, hoặc vuốt sang trái ở bất kỳ đâu trên mobile.

Đăng nhập





Đang tải...