Skip to content

Instagram Reel Highlight — Implementation Spec

Status: Pre-formation operational spec. The Communications Committee will own the curation step once seated. The Administrator + Full-stack Dev own the implementation on each surface.

Decision context: ADR-0009 — Instagram reel highlight: link-out cards in the new theme + showcase, no embed, no API. This document is the how; the ADR is the why.

Scope (revised 2026-05-09): The new guildcommerce-theme and the guildcommerce.pplx.app showcase only. The current YOOtheme production site on ganjierguild.com is being replaced by the new theme; do not invest in the YOOtheme integration. The MkDocs document library is out of scope.

What we're building

A small "Featured reel" card that appears on each in-scope public Guild surface. The card is a Guild-controlled thumbnail + caption + button that links out to Instagram. No Instagram embed script. No Meta API tokens. No auto-pulling.

The same content appears on:

  • guildcommerce-theme — the new WordPress theme being staged (replaces YOOtheme on ganjierguild.com when staging goes live)
  • guildcommerce.pplx.app — React/Vite showcase

Identical content, identical visual, two implementations.

The card

┌─────────────────────────────────────────────┐
│                                             │
│   [thumbnail image, brand-cropped]          │
│                                             │
│  Featured reel                              │
│  TODO: 1–2 line caption written by the      │
│  Communications Committee                    │
│                                             │
│  [ Watch on Instagram → ]                   │
│  More on Instagram                          │
│                                             │
└─────────────────────────────────────────────┘
Element Source Notes
Eyebrow text Static: "Featured reel" Same on every surface. Same as other Guild card eyebrows.
Thumbnail image Guild's own asset (uploaded; not hot-linked from Instagram) See Asset specs
Caption Guild-written, 1–2 lines, ≤140 characters Not the Instagram caption — written for off-platform context
Primary CTA "Watch on Instagram →" Brand Honey button per brand/README.md
Primary CTA link The specific reel's permalink (e.g. https://www.instagram.com/reel/<id>/) Open in new tab; target="_blank" rel="noopener"
Secondary link "More on Instagram" Links to the Guild's Instagram channel home (https://www.instagram.com/<handle>/)

The card inherits the Guild brand cascade — Covik Sans for the eyebrow + caption, Abadi MT Pro for the secondary link, Honey for the CTA, Mocha for text. Fallback fonts apply on surfaces that don't yet have Typekit authorized.

Asset specs

Thumbnail image

  • Aspect ratio: 4:5 (Instagram reel-native)
  • Pixel dimensions (web-served): 800 × 1000
  • Pixel dimensions (source/master): 1600 × 2000 (so we have a 2× version for retina)
  • Format: WebP primary, JPG fallback
  • File size target: ≤120 KB (WebP), ≤180 KB (JPG fallback)
  • Color space: sRGB
  • Treatment: Crop tight to the reel's hero frame; do not upscale Instagram's compressed export. Re-export from the source video where possible.
  • Naming convention: featured-reel-YYYY-MM-DD.webp (date is the curation date, not the reel's original post date)
  • Where to store:
  • New theme: guildcommerce-theme/assets/featured-reel.webp (theme-bundled asset, deployed with the theme; on the live WP install it can be overridden with an upload to the WP media library if the operator prefers — see theme implementation notes)
  • Showcase: site/client/public/featured-reel.webp in the guildcommerce repo

Caption text

  • Length: 1–2 lines, ≤140 characters total
  • Voice: matches the Guild brand voice (clear, declarative, no marketing puffery)
  • What it should answer: "Why should someone off-Instagram click this?" — not what the reel is about as content, but what they get for clicking
  • What it should NOT do: copy the Instagram caption verbatim; use platform jargon ("link in bio"); or contain any hashtags

Per-surface implementation

Surface 1: guildcommerce-theme (new WordPress theme — staging into ganjierguild.com)

Component type: Theme template part + a small block (or shortcode, depending on how the theme exposes building blocks). The card is implemented in the theme so it ships with staging and is available on any page the operator drops it on.

Placement target on go-live: Homepage, in the lower third — below the primary value-prop blocks, above the footer. Not in the hero (the hero stays focused on conversion to Guild membership signup).

Build steps:

  1. Add the bundled fallback thumbnail at guildcommerce-theme/assets/featured-reel.webp (the placeholder ships with the theme so the card never renders broken on first activation).

  2. Add the template part at guildcommerce-theme/template-parts/featured-reel.php. Pseudocode:

<?php
/**
 * Featured Reel — link-out card. See ADR-0009.
 * No Instagram embed, no Meta API.
 */
$reel_url    = get_theme_mod( 'gc_featured_reel_url', '' );
$caption     = get_theme_mod( 'gc_featured_reel_caption', '' );
$thumbnail   = get_theme_mod( 'gc_featured_reel_thumb', get_template_directory_uri() . '/assets/featured-reel.webp' );
$channel_url = get_theme_mod( 'gc_featured_reel_channel', 'https://www.instagram.com/' . get_theme_mod( 'gc_instagram_handle', '' ) );

// Render nothing if not configured — prevents an empty card on staging before first curation.
if ( empty( $reel_url ) || empty( $caption ) ) {
    return;
}
?>
<section class="gc-featured-reel" aria-labelledby="gc-featured-reel-eyebrow">
  <a href="<?php echo esc_url( $reel_url ); ?>" target="_blank" rel="noopener noreferrer" aria-label="Watch on Instagram">
    <img src="<?php echo esc_url( $thumbnail ); ?>"
         alt=""
         width="800" height="1000"
         loading="lazy" decoding="async"
         class="gc-featured-reel__img" />
  </a>
  <p id="gc-featured-reel-eyebrow" class="gc-eyebrow">Featured reel</p>
  <p class="gc-featured-reel__caption"><?php echo esc_html( $caption ); ?></p>
  <a class="gc-btn gc-btn--primary" href="<?php echo esc_url( $reel_url ); ?>" target="_blank" rel="noopener noreferrer">
    Watch on Instagram →
  </a>
  <a class="gc-link gc-link--secondary" href="<?php echo esc_url( $channel_url ); ?>" target="_blank" rel="noopener noreferrer">
    More on Instagram
  </a>
</section>
  1. Register Customizer settings in guildcommerce-theme/inc/customizer.php (or wherever the theme already registers add_setting calls): four settings under a "Featured Reel" panel — gc_featured_reel_url, gc_featured_reel_caption, gc_featured_reel_thumb (image control, defaults to the bundled asset), gc_instagram_handle. Standard sanitize_callback per setting (esc_url_raw, sanitize_text_field).

  2. Expose the card as either a block (preferred — appears in the block inserter under "GuildCommerce") or a shortcode [gc_featured_reel]. Either route calls get_template_part( 'template-parts/featured-reel' ).

  3. Styles — append to the theme's primary stylesheet (or wherever brand tokens live):

.gc-featured-reel {
  max-width: 28rem;
  margin: 4rem auto;
  text-align: center;
  font-family: var(--gc-font-sans, "Covik Sans", system-ui, sans-serif);
}
.gc-featured-reel__img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 0.75rem;
  display: block;
}
.gc-featured-reel .gc-eyebrow {
  font-family: var(--gc-font-display, "Abadi MT Pro", serif);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.75rem;
  color: var(--gc-mocha-80, #5a4a3a);
  margin: 1.25rem 0 0.5rem;
}
.gc-featured-reel__caption {
  color: var(--gc-mocha-90, #3e2f22);
  margin: 0 0 1.25rem;
}
.gc-featured-reel .gc-btn--primary {
  display: inline-block;
  background: var(--gc-honey, #d9a441);
  color: var(--gc-mocha-90, #3e2f22);
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
  font-weight: 600;
  text-decoration: none;
}
.gc-featured-reel .gc-link--secondary {
  display: block;
  margin-top: 0.75rem;
  color: var(--gc-mocha-80, #5a4a3a);
  font-size: 0.875rem;
}
  1. Staging verification (before go-live):
  2. Activate guildcommerce-theme on staging.
  3. In the Customizer, set the four Featured Reel settings (URL, caption, optional custom thumb, IG handle).
  4. Insert the Featured Reel block on the staging homepage (or add the shortcode).
  5. Confirm: card renders; thumbnail at 4:5; both links open in a new tab; no instagram.com script in the network tab; no console errors; page weight added by the card <200 KB.
  6. With the four settings cleared, the card renders nothing (verifies the "do not show empty card" guard).

  7. Go-live: when the new theme replaces YOOtheme on ganjierguild.com, the Customizer settings carry across (theme_mod). Cloudflare cache purge for the homepage URL after first curation.

Acceptance:

  • Theme activates with no PHP warnings or notices
  • Card renders only when configured (URL + caption present)
  • No Instagram embed script anywhere in the rendered page
  • Customizer panel "Featured Reel" exposes all four settings with clear labels
  • Same component re-usable on other pages via the block/shortcode

Surface 2: guildcommerce.pplx.app (React/Vite showcase)

Component type: React component, added to the existing showcase template

Placement: As a card inside the existing "Why this exists" or final-CTA region — the showcase is already a tall narrative scroll, so the reel card slots in as a single-column section near the bottom.

Build steps:

  1. Drop featured-reel.webp into site/client/public/.
  2. Add a FeaturedReel component to site/client/src/components/FeaturedReel.tsx:
export function FeaturedReel({
  thumbnailSrc = "/featured-reel.webp",
  caption,
  reelUrl,
  channelUrl = "https://www.instagram.com/<handle>",
}: {
  thumbnailSrc?: string;
  caption: string;
  reelUrl: string;
  channelUrl?: string;
}) {
  // Don't render an empty card if not configured.
  if (!caption || !reelUrl) return null;

  return (
    <section className="gc-featured-reel" aria-labelledby="gc-featured-reel-eyebrow">
      <a href={reelUrl} target="_blank" rel="noopener noreferrer" aria-label="Watch on Instagram">
        <img
          src={thumbnailSrc}
          alt=""
          width={800}
          height={1000}
          loading="lazy"
          decoding="async"
        />
      </a>
      <p id="gc-featured-reel-eyebrow" className="gc-eyebrow">Featured reel</p>
      <p className="gc-caption">{caption}</p>
      <a className="gc-btn-primary" href={reelUrl} target="_blank" rel="noopener noreferrer">
        Watch on Instagram →
      </a>
      <a className="gc-link-secondary" href={channelUrl} target="_blank" rel="noopener noreferrer">
        More on Instagram
      </a>
    </section>
  );
}
  1. Render it from the showcase's main page component, passing in the current caption and reelUrl:
<FeaturedReel
  caption="TODO: current caption"
  reelUrl="https://www.instagram.com/reel/TODO/"
/>
  1. Add styles to src/index.css under a new section:
.gc-featured-reel {
  max-width: 28rem;
  margin: 4rem auto;
  text-align: center;
  font-family: var(--font-sans);
}
.gc-featured-reel img {
  width: 100%;
  aspect-ratio: 4 / 5;
  object-fit: cover;
  border-radius: 0.75rem;
}
.gc-featured-reel .gc-eyebrow {
  font-family: var(--font-display);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  font-size: 0.75rem;
  color: var(--gc-mocha-80);
  margin: 1.25rem 0 0.5rem;
}
.gc-featured-reel .gc-caption {
  color: var(--gc-mocha-90);
  margin: 0 0 1.25rem;
}
.gc-featured-reel .gc-btn-primary {
  display: inline-block;
  background: var(--gc-honey);
  color: var(--gc-mocha-90);
  padding: 0.75rem 1.5rem;
  border-radius: 0.5rem;
  font-weight: 600;
  text-decoration: none;
}
.gc-featured-reel .gc-link-secondary {
  display: block;
  margin-top: 0.75rem;
  color: var(--gc-mocha-80);
  font-size: 0.875rem;
}
  1. Build, deploy via the existing showcase deploy flow.

Acceptance: Component renders on the showcase, browser console clean, no instagram.com script in the network tab, page weight added <200 KB.

What this spec does NOT cover

  • Current production ganjierguild.com (YOOtheme). Out of scope. The new theme replaces it; investing in the YOOtheme integration is wasted work.
  • MkDocs document library at ginalyncox.github.io/ganjier-guild-launch-blueprint/. Out of scope. If the document library ever needs a featured reel, ADR-0009 is amended rather than re-decided.
  • Instagram brand-mark usage (the wordmark, the icon). Avoid Meta's brand assets in the card; the buttons are text-only with an arrow. If Meta brand-mark usage is later needed, route it through counsel + the Form L — Communications & Brand Authorization Matrix.
  • Disclosure language, conduct, sponsorship, or any legal copy. Counsel territory.
  • Privacy / cookie banners. The card adds zero third-party tracking, so the existing privacy posture on each surface is unchanged. If a future iteration adds tracking, the privacy notices on every surface are revisited.
  • Auto-update. This is intentional; see ADR-0009 for the trade-off.

Curation cadence

The Communications Committee owns the curation step. Pre-formation, the Administrator runs it.

Cadence Activity Owner
Every 2 weeks (target) Pick the next featured reel; export the thumbnail; write the caption; replace assets on each surface; deploy/publish Communications Committee + Administrator
Monthly Confirm both surfaces show the same reel; confirm the channel link is correct; verify links open in new tabs Administrator
Quarterly Review what's been featured this quarter; pull simple performance signal where available (Instagram-side reach for the featured reels vs reels that weren't featured); decide if cadence should change Communications Committee

The 2-week target is aspirational, not a service level. A reel can sit on the card for longer if there's no replacement queued; the worst case is "the same good reel for a month," not a broken page.

Curation checklist (per refresh)

  • Reel selected from Instagram (record the URL)
  • Caption written (≤140 chars, brand-voice)
  • Thumbnail exported at 1600×2000 master, downscaled to 800×1000
  • Master + WebP saved to the brand assets folder (brand/assets/instagram/)
  • Surface 1 — new theme on the live site: thumbnail uploaded to WP media (or replace the bundled asset on next theme deploy); Customizer settings updated (URL, caption, optional thumb, handle); Cloudflare cache purged for the homepage
  • Surface 2 — showcase: thumbnail committed to site/client/public/; caption + URL committed to the page component; deployed
  • Quick visual check on each surface (desktop + mobile)

Roles

Role Responsibility
Administrator Pre-formation curation; updates Customizer settings on the live WP install; coordinates with Full-stack Dev on showcase deploys
Communications Committee (post-seating) Owns selection criteria, caption voice, and quarterly review
Full-stack Dev Theme template part, Customizer settings, and showcase component implementation
Designer / brand owner Thumbnail export when the reel hero frame needs treatment beyond a straight crop

Cross-references