Skip to main content

Knowledge > Products > Pro Website > Sections

Pro Website Template Sections

Section Rendering Philosophy

Every section in UnifiedTemplate is conditional on data availability. If a church has not populated staff, the Staff section does not render -- there is no empty placeholder or "Coming Soon" stub. This means a brand-new Pro Website with no admin edits still looks complete: it shows the hero video, service times (from the church's PewSearch directory listing), map/contact, and footer. As the church adds content via the admin dashboard, sections progressively appear.

The template renders sections in a fixed order (listed below). There is no drag-and-drop section reordering. The order was designed based on visitor psychology: what matters most (who is this church, when do they meet) comes first; secondary content (events, sermons, giving) comes later.

Section Reference

Section 1: StickyNav

What it does: Renders a fixed-position navigation bar at the top of the page with anchor links to visible sections and the church logo.

Data source: Computed from which sections are visible (each section registers an anchor ID). Logo from premium_churches.logo_url.

Rendering logic:

IF logo_url exists:
Show logo image (max-height 48px, auto-width)
ELSE:
Show church name as text

Navigation links = array of {label, anchorId} for each visible section
Links use denomination-specific labels (e.g., "Mass Times" vs "Service Times")
Scroll behavior: smooth scroll to anchor on click
Sticky: position fixed at top, z-index above content, semi-transparent background
Mobile: collapses to hamburger menu

When it renders: Always. Every Pro Website page has navigation.

Visual adaptation: Background color and link hover color match the denomination family. Logo is rendered as-uploaded (no color transformation).


Section 2: Demo Badge

What it does: Shows a small "DEMO" indicator badge overlaying the page for test/demo churches.

Data source: Church UUID from premium_churches.church_id.

Rendering logic:

IF church_id starts with '00000000-0000-4000-a000-':
Show floating badge: "DEMO" in red/white
Position: top-right corner, below nav
ELSE:
Do not render

When it renders: Only for demo church UUIDs (those starting with the reserved demo prefix). This ensures demo pages are clearly distinguishable from real church pages during testing and sales demos.


Section 3: VideoHero

What it does: Full-width video background with church name overlay, tagline, and denomination-styled call-to-action.

Data source:

  • Video: premium_churches.hero_video_key (single) or premium_churches.hero_slideshow_keys (array)
  • Church name: churches.name
  • Tagline: churches.description (first sentence or custom tagline if set)

Rendering logic:

IF hero_slideshow_keys is non-empty array:
Render slideshow: cycle through videos with crossfade
Each video: <video autoplay muted loop playsinline>
Poster image shown on mobile / while loading
ELSE:
video_key = hero_video_key OR 'church-entrance' (default)
Lookup video entry from video-library.ts
Render single <video autoplay muted loop playsinline>

Overlay:
Semi-transparent gradient (family-specific color)
Church name: large heading (family heading font)
Tagline: subtitle text below name
CTA button: "Plan Your Visit" or family-specific label, scrolls to What to Expect or Service Times

When it renders: Always. The hero section is the visual anchor of every Pro Website page. Even without a custom video selected, the default church-entrance video provides a professional first impression.

Visual adaptation:

  • Liturgical: dark overlay with gold accent border, Playfair Display heading
  • Protestant: blue gradient overlay, clean sans-serif heading
  • Community: warm gradient overlay, modern rounded heading

Section 4: About

What it does: Displays the church's description/about text with denomination-appropriate styling.

Data source: churches.description (from the PewSearch directory listing, editable by church admin).

Rendering logic:

IF description exists and is non-empty:
Render description text in a styled card/section
Apply family-specific background and text styling
Max-width container for readability
ELSE:
Do not render

When it renders: When the church has a description. Most claimed churches have one from their directory listing.


Section 5: Beliefs & Values

What it does: Renders belief statement cards in a grid layout.

Data source: premium_churches.beliefs (JSONB array).

Rendering logic:

IF beliefs array exists and has items:
FOR each belief in beliefs:
Render card with:
- belief.title (bold heading)
- belief.description (body text)
Layout: responsive grid (2 columns desktop, 1 column mobile)
Family-specific card styling (border color, background)
ELSE:
Do not render

When it renders: Only when the church has added beliefs via the admin Content tab. This is opt-in content -- many churches may choose not to display belief statements on their website.


Section 6: VideoTransition (First)

What it does: A decorative video break between the upper content sections and the middle sections. Creates visual breathing room.

Data source: premium_churches.transition_video_key (default: transition-1).

Rendering logic:

video_key = transition_video_key OR 'transition-1'
Lookup video entry from video-library.ts
Render: <video autoplay muted loop playsinline>
Height: constrained (approximately 200-300px)
Width: full-width
No overlay text

When it renders: Always (when at least one section exists above and below it). Provides visual rhythm to the page.


Section 7: Service Times

What it does: Displays the church's service/meeting times in a structured, day-ordered grid.

Data source: premium_churches.custom_hours (JSONB, structured by day) OR fallback to churches.service_times from the directory listing.

Rendering logic:

IF custom_hours exists (Pro Website admin-edited):
Use custom_hours data
ELSE IF churches.service_times exists (directory fallback):
Use directory service times
ELSE:
Do not render

Day ordering: Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday
For each day with entries:
Show day name
For each service on that day:
Show label (e.g., "Morning Worship", "Evening Service", "Mass")
Show time (formatted)

Section heading uses family label:
liturgical/catholic: "Mass & Confession Times"
liturgical/orthodox: "Divine Liturgy Times"
protestant: "Service Times"
community: "Gathering Times"

When it renders: When any hours data exists. Most churches have service times from their directory listing, so this section renders for nearly all Pro Website pages.


Section 8: What to Expect

What it does: A first-visit information guide with 10 structured fields, designed to reduce visitor anxiety about attending a new church.

Data source: premium_churches.what_to_expect (JSONB object with 10 fields).

Fields:

FieldPurposeExample Content
dress_codeWhat to wear"Come as you are! Most people wear casual or business casual."
parkingWhere to park"Free parking in our main lot off Oak Street. Greeters will direct you."
childrenKids programs"We have nursery (0-2), preschool (3-5), and elementary (K-5) programs during all services."
first_visitWhat happens"Arrive 10 minutes early. A greeter will meet you at the door and help you find a seat."
music_styleWorship style"Contemporary worship with a full band, plus one traditional hymn each Sunday."
service_lengthHow long"Services typically last about 75 minutes."
accessibilityAccessibility info"Wheelchair accessible. Hearing assistance devices available at the welcome desk."
communionCommunion practice"We celebrate communion on the first Sunday of each month. All believers are welcome."
coffeeCoffee/refreshments"Free coffee and donuts in the lobby before and after every service!"
guest_checkinGuest registration"Fill out a connection card in your seat or check in at the welcome desk."

Rendering logic:

IF what_to_expect exists and has at least one non-empty field:
Render section with heading (family label: "What to Expect" / "Visiting Our Parish" / "Your First Visit")
FOR each field in what_to_expect:
IF field value is non-empty:
Render card with icon + field label + field value
Layout: responsive grid (2 columns desktop, 1 column mobile)
Each card has a contextual icon (parking icon for parking, kids icon for children, etc.)
ELSE:
Do not render

When it renders: Only when the church has populated at least one What to Expect field via the admin.


Section 9: Staff

What it does: Displays a staff directory with photos, names, titles, and bios in a responsive grid.

Data source: premium_churches.custom_staff (JSONB array).

Staff entry structure:

{
"name": "Pastor John Smith",
"title": "Senior Pastor",
"bio": "Pastor John has served our church for 15 years...",
"photo_url": "https://supabase.co/storage/v1/.../photo.jpg",
"order": 1
}

Rendering logic:

IF custom_staff exists and has items:
Sort by order field (ascending)
Render section heading (family label: "Staff" / "Parish Staff" / "Clergy & Staff" / "Our Team")
FOR each staff member:
Render card with:
- Photo (if photo_url exists, else default avatar placeholder)
- Name (bold)
- Title (subtitle)
- Bio (body text, truncated with expand on click if long)
Layout: 2x4 responsive grid (up to 4 columns on wide screens, 2 on tablet, 1 on mobile)
ELSE:
Do not render

When it renders: Only when the church has added staff via the admin. Staff photos are uploaded via POST /api/upload/staff-photo and stored in Supabase Storage.


Section 10: VideoTransition (Second)

What it does: Second decorative video break, identical in behavior to Section 6.

Data source: Same transition_video_key as Section 6.

When it renders: When sections exist above and below it that benefit from visual separation. Uses the same transition video as Section 6.


Section 11: Ministries

What it does: Displays ministry/program cards with names and descriptions.

Data source: premium_churches.custom_ministries (JSONB array).

Ministry entry structure:

{
"name": "Youth Group",
"description": "For students in grades 6-12. Meets Wednesday evenings at 6:30 PM.",
"order": 1
}

Rendering logic:

IF custom_ministries exists and has items:
Sort by order field (ascending)
Render section heading (family label: "Ministries" / "Parish Ministries" / "Get Involved")
FOR each ministry:
Render card with:
- Ministry name (heading)
- Description (body text)
Layout: responsive grid (3 columns desktop, 2 tablet, 1 mobile)
Card styling: family-specific border and accent colors
ELSE:
Do not render

When it renders: Only when the church has added ministries via the admin.


What it does: Embeds a YouTube or Vimeo video player for the church's featured sermon, plus a grid of additional sermons if available.

Data source:

  • Primary: premium_churches.featured_video_url OR first entry in premium_churches.sermons array
  • Additional: remaining entries in premium_churches.sermons

Rendering logic:

primary_video = featured_video_url OR sermons[0].video_url

IF primary_video exists:
Render section heading (family label: "Sermons" / "Homilies" / "Messages")
Render embedded video player (responsive iframe):
- YouTube: extract video ID, render youtube-nocookie embed
- Vimeo: extract video ID, render Vimeo player embed
IF sermons array has more than 1 entry:
Render grid of additional sermon cards:
- Sermon title
- Speaker name
- Date
- Thumbnail (auto-generated from video URL)
- Click to play (replaces primary player or opens in new tab)
ELSE:
Do not render

When it renders: When the church has set a featured_video_url or has at least one sermon in the sermons array.


Section 13: Events

What it does: Displays a list of upcoming events with date, time, and description.

Data source: premium_churches.events (JSONB array).

Event entry structure:

{
"title": "Easter Sunday Service",
"date": "2026-04-05",
"time": "9:00 AM",
"description": "Join us for a special Easter celebration with worship, message, and egg hunt for kids.",
"location": "Main Sanctuary"
}

Rendering logic:

IF events array exists and has items:
Filter to future events (date >= today)
Sort by date ascending (soonest first)
Render section heading (family label: "Upcoming Events" / "Parish Events" / "What's Happening")
FOR each event:
Render event card with:
- Date (formatted: "April 5, 2026")
- Time
- Title (heading)
- Description
- Location (if provided)
Layout: vertical list or 2-column grid depending on count
ELSE:
Do not render

When it renders: Only when the church has added events and at least one is in the future.

Known gap: No recurring event support. Each occurrence must be entered individually. This is a known admin UX limitation for future improvement.


Section 14: Giving

What it does: Displays a call-to-action button linking to the church's online giving platform.

Data source: premium_churches.giving_url (text, external URL).

Rendering logic:

IF giving_url exists and is non-empty:
Render section with:
- Heading (family label: "Give Online" / "Support Our Parish" / "Give")
- Brief text encouraging generosity
- Large CTA button linking to giving_url (opens in new tab)
- Button styled with family accent color
ELSE:
Do not render

When it renders: Only when the church has set a giving URL in the admin.


Section 15: Map & Contact Info

What it does: Renders a Leaflet map showing the church's location alongside contact information (phone, email, website, social links).

Data source:

  • Location: churches.latitude, churches.longitude, churches.address
  • Phone: churches.phone
  • Website: churches.website
  • Social: premium_churches.custom_social_media (JSONB)
  • Email: premium_churches.contact_email

Rendering logic:

IF latitude and longitude exist:
Render Leaflet map with marker at church location
Map: interactive, zoomable, with OpenStreetMap tiles
Marker popup: church name and address
ELSE:
Show address text only (no map)

Contact info (beside or below map):
- Address (always shown if available)
- Phone (with tel: link for mobile click-to-call)
- Email (with mailto: link)
- Website (external link, opens in new tab)
- Social media icons (Facebook, Instagram, Twitter/X, YouTube, TikTok)
Only icons with URLs are shown

When it renders: Almost always. Most churches have at least an address and phone number from their PewSearch listing. The map renders when coordinates are available.


Section 16: Contact Form

What it does: A form visitors can fill out to contact the church. Submissions are stored in the contact_submissions table and an email notification is sent to the church's contact_email.

Data source: premium_churches.contact_email (submission recipient).

Form fields:

  • Name (required)
  • Email (required)
  • Phone (optional)
  • Message (required, textarea)

Rendering logic:

IF contact_email exists:
Render contact form with heading (family label: "Contact Us" / "Contact the Parish" / "Reach Out")
On submit:
- Validate required fields
- POST to /api/contact (or inline server action)
- INSERT into contact_submissions (church_id, name, email, phone, message, created_at)
- Send email notification to contact_email
- Show success message: "Thank you! We'll be in touch soon."
Spam protection: honeypot field + rate limiting
ELSE:
Do not render (no recipient for submissions)

When it renders: When the church has set a contact email. Submissions are also visible in the admin dashboard metrics.

Database table: contact_submissions

ColumnTypePurpose
idUUIDPrimary key
church_idUUIDFK to churches
nametextSubmitter name
emailtextSubmitter email
phonetextSubmitter phone (optional)
messagetextMessage body
created_attimestamptzSubmission timestamp

Section 17: ChurchWiseAI Chatbot Widget

What it does: Embeds the ChurchWiseAI chatbot widget as a floating button in the bottom-right corner of the page.

Data source: premium_churches.chatbot_enabled (boolean), premium_churches.chatbot_agent_id (UUID).

Rendering logic:

IF chatbot_enabled === true AND chatbot_agent_id is valid UUID:
Inject config into window:
window.__CWAI_CONFIG = {
churchId: chatbot_agent_id,
color: style.chatbotAccent, // family-specific color
position: "bottom-right"
}
Dynamically load script: https://churchwiseai.com/embed/churchwiseai-widget.js
ELSE:
Do not render

When it renders: Only when both chatbot_enabled is true AND chatbot_agent_id is a valid UUID. This prevents rendering a broken widget.

See Chatbot Integration for full details on the widget, accent colors, and tier restrictions.


What it does: Page footer with social links, contact info, and branding.

Data source: Social links from premium_churches.custom_social_media, contact info from churches.

Rendering logic:

Render footer with:
- Church name
- Address
- Phone (click-to-call)
- Social media icon links (only those with URLs)
- "Powered by PewSearch" attribution (not removable on any Pro Website tier — branding removal is not currently offered for PewSearch products, unlike the CWA chatbot Suite tier which removes the "Powered by ChurchWiseAI" badge)
- Copyright year (dynamic)

Footer styling: dark background (family-specific shade), light text
Full-width, responsive layout

When it renders: Always. Every page has a footer.

Section Visibility Summary

SectionAlways RendersData Required
StickyNavYes--
Demo BadgeConditionalDemo UUID prefix
VideoHeroYes-- (uses default video)
AboutConditionalchurches.description
Beliefs & ValuesConditionalpremium_churches.beliefs
VideoTransition (1st)Yes--
Service TimesConditionalcustom_hours or churches.service_times
What to ExpectConditionalpremium_churches.what_to_expect (any field)
StaffConditionalpremium_churches.custom_staff
VideoTransition (2nd)Yes--
MinistriesConditionalpremium_churches.custom_ministries
Featured SermonConditionalfeatured_video_url or sermons[0]
EventsConditionalpremium_churches.events (future events)
GivingConditionalpremium_churches.giving_url
Map & Contact InfoConditionalchurches.latitude/longitude or address
Contact FormConditionalpremium_churches.contact_email
Chatbot WidgetConditionalchatbot_enabled + valid chatbot_agent_id
FooterYes--

Always-visible sections (5): StickyNav, VideoHero, VideoTransition (x2), Footer. These ensure every Pro Website page looks complete even with zero admin edits.

Conditional sections (14): Progressively appear as the church adds content.

See Also