Heart with magnifying glass — representing careful analysis of the kahoot360.com website

Technical Analysis

Headless Approach with Astro

Just like kahoot360.com, this site uses Astro as a static site generator with WordPress as a headless CMS. At build time, Astro fetches content from the WordPress REST API and renders it to static HTML. A single data-access layer in src/lib/wordpress.ts handles all fetching, so components never know or care where the data comes from.

To structure the content, I registered three custom post types: card for the homepage cards, section for the sections on this page, and list_item for the bullet points within each section. The list_item type is hierarchical — each item’s post_parent links it to its section, so the template knows which bullets belong where. All three support menu_order, so editors can drag-and-drop to reorder content without touching code.

For structured fields beyond title and content — like a card’s pill label, image URL, and alt text — I used Advanced Custom Fields (ACF). Each content type has its own field group, and every field has show_in_rest enabled so it appears in the REST API response under the acf key.

// src/lib/wordpress.ts
const USE_MOCK = false;
const WP_BASE_URL = "https://your-wp-site.com/wp-json/wp/v2";

export async function getCards(locale: string) {
  if (USE_MOCK) {
    return getMockData("cards", locale);
  }
  // Custom post type endpoint — orderby=menu_order
  // lets editors drag-and-drop to reorder.
  const res = await fetch(
    `/card?orderby=menu_order&order=asc&lang=&_embed`
  );
  return (await res.json()) ?? [];
}
  • Build-time fetching: Astro calls the WordPress REST API during the build process

  • Mock data layer: local JSON files shaped exactly like real API responses

  • Single swap point: one constant in wordpress.ts switches from mock to live

BEM Conventions

kahoot360.com uses structured BEM class names like page-header and page-header--microsite. I followed the same approach throughout this site — every component uses Block Element Modifier naming. The navbar is navbar with navbar__logo, navbar__links, and navbar__link. The card is card with card__content, card__title, card__pill, and card__illustration. No utility classes, no framework — just semantic, component-oriented CSS that describes what something is, not how it looks.

<!-- Card component -->
<div class="card">
  <div class="card__content">
    <div class="card__illustration">...</div>
    <div class="card__pill">...</div>
    <h3 class="card__title">...</h3>
    <p class="card__text">...</p>
  </div>
</div>
  • navbar / navbar__logo / navbar__links / navbar__link

  • card / card__content / card__title / card__pill / card__illustration

  • hero / hero__title / hero__subtitle / hero__content / hero__cta

  • footer / footer__text

Component Reusability

On kahoot360.com, the --microsite modifier shows how one base component adapts to different contexts. I took the same approach with Card.astro — it accepts props for title, text, pill, image, and variant, so the same component renders differently depending on what you pass in. The Hero component works the same way: it optionally shows an illustration, a pill, or content depending on the props. One component, many contexts, less duplicated code — exactly what the job description asks for.

<!-- Same Card component, different content -->
<Card
  pill="CSS"
  title="BEM Conventions"
  text="Structured BEM class names..."
  image="/illustrations/Controller.png"
  imageAlt="Controller"
/>

<Card
  pill="Architecture"
  title="Headless Approach"
  text="Astro fetches from WordPress..."
  image="/illustrations/Classroom.png"
  imageAlt="Classroom"
/>
  • Card.astro — accepts title, text, pill, image, imageAlt, and variant props

  • Hero.astro — optionally renders illustration, pill, and content

  • Button.astro — variant prop switches between primary and secondary styles