Courses represent a significant investment for students. They're committing time, money, and energy to learning from you. Your value ladder must honor this commitment by providing clear progression from free exploration to deep mastery.

Course creators often make the mistake of offering only one program. This forces potential students into an all-or-nothing decision. A course ladder provides entry points for beginners and advanced options for graduates, increasing both accessibility and lifetime value.

Mini-Course Core Course Flagship Mastermind

The Course Ladder Structure

A complete course ladder might include:

  • Free mini-course: 5-day email course or short video series
  • Low-ticket workshop: Focused, 60-90 minute training
  • Core course: Comprehensive self-study program
  • Cohort course: Group learning with live elements
  • Mastermind: High-touch ongoing community

Not every creator needs all levels. Choose the rungs that serve your audience and fit your capacity. The key is providing progression for students at different stages.

Rung Price Range
Free mini-course $0
Workshop $27-97

The Free Mini-Course as Lead Magnet

A free mini-course is one of the most effective lead magnets for course creators. Delivered over 5-7 days via email, it provides genuine transformation while demonstrating your teaching style. Students experience your approach before committing to paid programs.

Design your mini-course to deliver a quick win. What's the smallest transformation you can provide in a week? A content creator might offer "5 Days to Better Headlines." A fitness coach might offer "5 Days to Better Mornings." The win creates momentum and trust.

The Workshop: First Paid Step

A focused workshop provides deeper transformation in 60-90 minutes. Price it accessibly to reduce friction for first-time buyers. Deliver clear value that leaves participants wanting more. The workshop serves as both product and promotion for your core course.

Live workshops build connection and allow Q&A. Recorded workshops can sell on autopilot. Consider both formats to serve different preferences. Promote the workshop to mini-course graduates who are ready to go deeper.

The Core Course: Your Flagship

Your core course is your main offer. It delivers complete transformation through comprehensive curriculum. Structure it for self-study with video lessons, worksheets, and resources. Price it based on the value of the transformation it provides.

Core courses can be evergreen (always available) or open on a schedule. Evergreen courses generate passive income but require strong student motivation. Scheduled courses create community and accountability but require more active management.

Core Course Elements:
- Video lessons (10-20 modules)
- Worksheets/workbooks
- Resource library
- Community access
- Lifetime updates
  

Cohort Programs: Live Learning

Cohort-based courses add live elements to self-study. Weekly calls, group accountability, and fixed start dates create structure that many students need. The cohort format commands higher prices and produces stronger results.

Run cohorts 2-4 times per year. Each cohort becomes an event you can promote and fill. Students bond with each other, increasing retention and referrals. Cohort graduates become candidates for your highest offers.

The Mastermind: Peak of the Ladder

At the top, offer a mastermind for your most committed students. This might include ongoing coaching, peer accountability, and advanced content. The mastermind provides maximum support for maximum transformation.

Masterminds work well as ongoing memberships with monthly calls and community. Students stay for years, building deep relationships and achieving sustained results. This rung provides recurring revenue and deep fulfillment.

Moving Students Up the Ladder

Each course should naturally lead to the next. Within your mini-course, mention the workshop. Within the workshop, mention the core course. Within the core course, mention the mastermind. Make progression feel like the obvious next step for those ready.

But never pressure. Some students will only ever take your mini-course, and that's fine. Others will climb every rung. Serve each where they are, and they'll climb when they're ready.

If you're a course creator, map your current offerings against this ladder. Where are the gaps? What could you add to serve students at different levels? Start with one new rung and build from there.

boosting related posts with flexsearch for jekyll blogs

Why FlexSearch for Related Posts

While Lunr.js provides a robust client-side search experience, FlexSearch is another powerful JavaScript full-text search library that is often faster and more configurable. It supports advanced tokenization and scoring methods that can improve the quality and speed of related post recommendations on Jekyll blogs, especially on GitHub Pages where server-side logic is limited.

Advantages of FlexSearch

  • Higher performance and lower memory footprint compared to Lunr
  • Support for async indexing and searching
  • Multiple search modes (e.g., "match", "score", "strict") for fine-tuned control
  • Better support for complex language processing and custom tokenization

Step 1: Generating JSON Data for FlexSearch

The JSON structure is similar to Lunr’s, but you can include additional fields or customize as needed:


---
layout: null
permalink: /flexsearch-posts.json
---

[
  {% for post in site.posts %}
  {
    "id": "{{ post.url }}",
    "title": {{ post.title | jsonify }},
    "tags": {{ post.tags | join: ' ' | jsonify }},
    "content": {{ post.content | strip_html | jsonify }}
  }{% unless forloop.last %},{% endunless %}
  {% endfor %}
]

Step 2: Adding FlexSearch Script

Add FlexSearch to your post layout via CDN:


<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/flexsearch.bundle.js"></script>

Step 3: Creating the FlexSearch Related Posts Function

We build a client-side script that:

  • Fetches the JSON data
  • Indexes the posts asynchronously
  • Searches based on the current post title
  • Displays top relevant related posts excluding the current post

<script>
document.addEventListener("DOMContentLoaded", function () {
  const currentURL = window.location.pathname;
  const relatedContainer = document.getElementById("related-posts");

  fetch("/flexsearch-posts.json")
    .then(res => res.json())
    .then(posts => {
      const index = new FlexSearch.Document({
        document: {
          id: "id",
          index: ["title", "tags", "content"],
          store: ["title", "id"]
        },
        tokenize: "forward",
        cache: true,
        async: true,
        resolution: 9,
      });

      posts.forEach(post => index.add(post));

      const currentPost = posts.find(p => p.id === currentURL);

      if (!currentPost) return;

      index.searchAsync(currentPost.title, {limit: 5}).then(results => {
        const relatedPosts = [];

        results.forEach(result => {
          result.result.forEach(id => {
            if (id !== currentURL && !relatedPosts.find(p => p.id === id)) {
              const post = posts.find(p => p.id === id);
              if (post) relatedPosts.push(post);
            }
          });
        });

        if (relatedPosts.length > 0 && relatedContainer) {
          relatedContainer.innerHTML = `
            <h3>Related Posts Powered by FlexSearch</h3>
            <ul>
              ${relatedPosts.map(p => `<li><a href="${p.id}">${p.title}</a></li>`).join("")}
            </ul>
          `;
        }
      });
    });
});
</script>

Step 4: Adding the Container

Place this in your post layout template where you want the related posts list:

<div id="related-posts"></div>

Real-World Example and Performance

On a mid-sized Jekyll blog with 200+ posts, FlexSearch indexing completed under 200ms in the browser, with searches returning results instantly. Compared to Lunr, it handled larger indexes more efficiently and allowed custom tokenization for multi-language posts.

Improving Relevance with Weighted Fields

You can prioritize some fields, e.g., tags over content, using weights in FlexSearch:


const index = new FlexSearch.Document({
  document: {
    id: "id",
    index: [
      { field: "title", tokenize: "forward", weight: 5 },
      { field: "tags", tokenize: "forward", weight: 10 },
      { field: "content", tokenize: "forward", weight: 1 }
    ],
    store: ["title", "id"]
  },
  async: true,
});

Conclusion

FlexSearch offers a performant and flexible way to implement full-text related post search on static Jekyll sites hosted on GitHub Pages. Its async capabilities make it suitable for larger sites while keeping the UI responsive.

This method complements or can even replace tag-based related posts for better user engagement and SEO. In the next article, we’ll compare FlexSearch and Lunr side by side and explore hybrid models for multi-language content indexing on Jekyll.