Template:UI/upcoming events featured/card

From Miniscope
Jump to: navigation, search

Card-rendering sub-template for Template:UI/upcoming_events_featured and Template:UI/workshops_library. Renders one workshop card — image, status badge, eyebrow date, title, tagline, and CTA buttons.

Normally invoked indirectly via a parent template's format=template auto-query, which passes the matched workshop's full title in as Page. Can also be called directly for one-off main-page features that need to override the auto-pick (e.g. promoting a specific workshop ahead of its application-close timing):

All other fields are derived from the page's SMW data via per-call #show against {{{Page}}}:

  • Eyebrow?Has start date#ISO, rendered via
 Template:UI/datetime (format=month_year) → "July 2026". CSS
 uppercases the visual rendering. Date-only format means no TZ
 shift and no <time> wrapper — the eyebrow is a
 workshop-month kicker, not a precise meeting time, so visitor-
 local conversion would be misleading (a workshop "in July" is in
 July regardless of where the visitor is). Suppressed when Has
 start date is empty (the empty {{{iso}}} arm in
 UI/datetime returns nothing, which keeps the eyebrow from
 collapsing to today's month).
  • TitlePage, wrapped in a wikilink
 to the workshop page.
  • Tagline?Has description on the page.
 Suppressed when empty.
  • Image?Has card image, falling back to
 ?Has banner. 4:3 aspect locked by CSS; uploads of a
 different ratio center-crop. When both properties are empty the
 image slot is suppressed and the card renders text-only.

Status badge

A small badge in the card's top-right corner reflects where in its lifecycle the workshop sits. The state machine is a cascade over four dates (Has start date, Has end date, Has application open date, Has application close date) against today:

 past         — Has end date is in the past (workshop is over).
                Falls back to "Has start date in the past" when
                Has end date isn't set.
 in_progress  — Has start date ≤ today ≤ Has end date.
 apps_open    — workshop is upcoming AND application window is
                currently open (open ≤ today ≤ close).
 apps_closed  — workshop is upcoming AND application close date
                is in the past (close < today < start).
 upcoming     — workshop is upcoming AND no application info is
                set, OR applications haven't opened yet
                (today < open).
 none         — Has start date isn't set; no badge rendered.

The cascade runs twice — once to emit the badge text, once to drive the CTA logic — because the Variables extension isn't enabled on the target wikis and wikitext has no other way to cache the result of an

  1. ifexpr chain. The repeated #show calls within a parser pass are

served from SMW's per-property cache, so the cost is roughly one SMW lookup per (workshop × property), not per (workshop × property × cascade-branch).

CTA buttons

The cascade also gates which CTAs render. Each only appears when its data is set AND the workshop is in the right state for it:

  • Primary "Apply now"?Has registration url, but
 only when status = apps_open. On a past or
 applications-closed workshop, the apply CTA would be misleading
 even if a registration URL is still on the page.
  • Secondary "View recording"?Has recording url,
 only when status = past. Surfaces the archival
 artifact on past-workshop cards in the workshops library.
  • Secondary "Learn more" → the workshop page itself
 ({{{Page}}}). Always renders when Page is non-empty —
 the universal fallback CTA so every card has at least one action.

Why not project these via the outer #ask in Template:UI/upcoming_events_featured: keeping them as #show calls here means the direct-invocation path (passing Page explicitly) works without changing the call site. The cost is a handful of extra #show per render; even in a workshops library with 30 workshops the parser budget is comfortable.

Named args

  • Page — bare full title of the workshop (required from
 #ask via mainlabel=Page; required from direct callers).
 When empty the template renders nothing — the empty-state placeholder
 lives on the dispatcher side so it shows up only when the auto-query
 returned zero matches, not when this sub-template happens to receive
 an empty Page (which would only happen via a malformed call).