## Summary Closes #18. - Add per-page titles, meta descriptions, Open Graph/Twitter tags, and canonical URLs on public `base2.html` pages - Improve semantic structure: skip link, primary nav ARIA, single `<main id="main-content">`, heading hierarchy, descriptive image alts - Publish `/robots.txt`, `/sitemap.xml`, and `/llms.txt` (linked from site head via `rel="alternate"`) - Agentic/a11y fixes: membership checkbox label associations, ZIP `name` attribute, layout stability (image aspect-ratio / min-height), footer year without `document.write` - WebMCP deferred — membership + Stripe checkout remain standard HTML/Stripe flows; no audit flag justified custom MCP surface yet ## Lighthouse / agentic notes Baseline Lighthouse runs still need Chrome Canary export on staging/prod. Structural SEO/a11y items from the ticket are implemented so follow-up audits can capture before/after scores. Expected audit wins vs prior minimal `charset`+`viewport` head: - SEO: unique titles/descriptions, crawl directives, sitemap - Agentic/a11y: landmarks, labels, CLS-oriented image sizing ## Test plan - [x] `uv run python manage.py test schasite` (34 passed) - [ ] Spot-check Home/About/Calendar/Dues/Membership/Board/Links in browser - [ ] Confirm `/robots.txt`, `/sitemap.xml`, `/llms.txt` on deployed host - [ ] Run Lighthouse SEO + Agentic browsing on key pages and note before/after pass ratio on the issue Reviewed-on: #27
This commit was merged in pull request #27.
This commit is contained in:
@@ -10,9 +10,28 @@ section {
|
||||
scroll-margin-top: 70px;
|
||||
}
|
||||
|
||||
/* Skip link visible when focused */
|
||||
.visually-hidden-focusable:focus {
|
||||
z-index: 1080;
|
||||
}
|
||||
|
||||
/* Reserve image space to reduce CLS */
|
||||
.card-img-top {
|
||||
aspect-ratio: 16 / 9;
|
||||
object-fit: cover;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
img.img-fluid {
|
||||
max-width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Hero Section */
|
||||
#home {
|
||||
background-color: rgba(var(--bs-success-rgb), 0.1);
|
||||
min-height: 280px;
|
||||
}
|
||||
|
||||
/* News and Contact Sections */
|
||||
|
||||
@@ -2,16 +2,31 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>About Us | Stonehedge Community Homeowners Association</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.">
|
||||
{% endblock %}
|
||||
{% block og_title %}About Us | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.{% endblock %}
|
||||
{% block twitter_title %}About Us | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Learn about Stonehedge in Wheaton, IL — local schools, community history, shopping and dining nearby, and parks that serve residents.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<section class="py-4 bg-success bg-opacity-10">
|
||||
<div class="container">
|
||||
<h1 class="text-success mb-0">About Stonehedge</h1>
|
||||
<p class="lead mb-0 mt-2">Schools, history, nearby amenities, and parks serving our Wheaton community.</p>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="schools" class="py-5">
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 mb-4 mb-lg-0">
|
||||
<img src="{% static 'images/District_200.png' %}" alt="Local Schools" class="img-fluid rounded shadow">
|
||||
<img src="{% static 'images/District_200.png' %}" alt="Community Unit School District 200 logo" class="img-fluid rounded shadow" width="600" height="400">
|
||||
</div>
|
||||
<div class="col-lg-6">
|
||||
<h2 class="text-success mb-4">Excellent Schools Serving Our Community</h2>
|
||||
@@ -127,7 +142,7 @@
|
||||
<div class="container">
|
||||
<div class="row align-items-center">
|
||||
<div class="col-lg-6 order-lg-2 mb-4 mb-lg-0">
|
||||
<img src="{% static 'images/header.gif' %}" alt="Community History" class="img-fluid rounded shadow">
|
||||
<img src="{% static 'images/header.gif' %}" alt="Historic view of the Stonehedge community" class="img-fluid rounded shadow" width="600" height="400">
|
||||
</div>
|
||||
<div class="col-lg-6 order-lg-1">
|
||||
<h2 class="text-success mb-4">Our Rich History</h2>
|
||||
@@ -161,7 +176,7 @@
|
||||
<div class="row g-4">
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="{% static 'images/danada.jpeg' %}" class="card-img-top" alt="Greenwood Mall">
|
||||
<img src="{% static 'images/danada.jpeg' %}" class="card-img-top" alt="Danada Square shopping area" width="640" height="360">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Danada</h5>
|
||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>1.0 miles from community</p>
|
||||
@@ -174,7 +189,7 @@
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="{% static 'images/downtown_wheaton.jpeg' %}" class="card-img-top" alt="Farmers Market">
|
||||
<img src="{% static 'images/downtown_wheaton.jpeg' %}" class="card-img-top" alt="Downtown Wheaton streetscape" width="640" height="360">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Downtown Wheaton</h5>
|
||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.7 miles from community</p>
|
||||
@@ -188,7 +203,7 @@
|
||||
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="{% static 'images/wheaton_farmers_market.jpeg' %}" class="card-img-top" alt="Farmers Market">
|
||||
<img src="{% static 'images/wheaton_farmers_market.jpeg' %}" class="card-img-top" alt="Wheaton Farmers Market stalls" width="640" height="360">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Wheaton Farmersmarket</h5>
|
||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>2.8 miles from community</p>
|
||||
@@ -201,7 +216,7 @@
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="card h-100 shadow-sm">
|
||||
<img src="{% static 'images/downtown_naperville.jpeg' %}" class="card-img-top" alt="Dining District">
|
||||
<img src="{% static 'images/downtown_naperville.jpeg' %}" class="card-img-top" alt="Downtown Naperville dining district" width="640" height="360">
|
||||
<div class="card-body">
|
||||
<h5 class="card-title">Downtown Naperville</h5>
|
||||
<p class="card-text"><i class="bi bi-geo-alt-fill text-success me-2"></i>6.2 miles from community</p>
|
||||
@@ -227,7 +242,7 @@
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="row g-0 h-100">
|
||||
<div class="col-md-5">
|
||||
<img src="{% static 'images/brighton.jpg' %}" class="img-fluid rounded-start h-100" alt="Community Park" style="object-fit: cover;">
|
||||
<img src="{% static 'images/brighton.jpg' %}" class="img-fluid rounded-start h-100" alt="Brighton Park playground and green space" width="400" height="300" style="object-fit: cover;">
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="card-body">
|
||||
@@ -249,7 +264,7 @@
|
||||
<div class="card shadow-sm h-100">
|
||||
<div class="row g-0 h-100">
|
||||
<div class="col-md-5">
|
||||
<img src="{% static 'images/seven_gables.jpg' %}" class="img-fluid rounded-start h-100" alt="Nature Preserve" style="object-fit: cover;">
|
||||
<img src="{% static 'images/seven_gables.jpg' %}" class="img-fluid rounded-start h-100" alt="Seven Gables Park nature preserve" width="400" height="300" style="object-fit: cover;">
|
||||
</div>
|
||||
<div class="col-md-7">
|
||||
<div class="card-body">
|
||||
|
||||
@@ -5,7 +5,22 @@
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association | Wheaton, IL</title>
|
||||
{% endblock %}
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.">
|
||||
{% endblock %}
|
||||
<link rel="canonical" href="{{ request.scheme }}://{{ request.get_host }}{{ request.path }}">
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Stonehedge Community Homeowners Association">
|
||||
<meta property="og:locale" content="en_US">
|
||||
<meta property="og:url" content="{{ request.scheme }}://{{ request.get_host }}{{ request.path }}">
|
||||
<meta property="og:title" content="{% block og_title %}Stonehedge Community Homeowners Association | Wheaton, IL{% endblock %}">
|
||||
<meta property="og:description" content="{% block og_description %}Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.{% endblock %}">
|
||||
<meta name="twitter:card" content="summary">
|
||||
<meta name="twitter:title" content="{% block twitter_title %}Stonehedge Community Homeowners Association | Wheaton, IL{% endblock %}">
|
||||
<meta name="twitter:description" content="{% block twitter_description %}Stonehedge Community Homeowners Association in Wheaton, Illinois — community news, events, dues, membership, and board information for residents.{% endblock %}">
|
||||
<link rel="alternate" type="text/plain" title="LLM site guidance" href="{% url 'llms_txt' %}">
|
||||
<!-- Bootstrap CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
@@ -16,12 +31,13 @@
|
||||
<script async defer src="https://tianji.aimloperations.com/tracker.js" data-website-id="cm9qziuid9vr7v6dtdbnx8406"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a class="visually-hidden-focusable btn btn-success position-absolute m-2" href="#main-content">Skip to main content</a>
|
||||
|
||||
<!-- Navigation -->
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top">
|
||||
<nav class="navbar navbar-expand-lg navbar-dark bg-success sticky-top" aria-label="Primary">
|
||||
<div class="container">
|
||||
<a class="navbar-brand" href="{% url 'index2' %}">Stonehedge Community Homeowners Association</a>
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav">
|
||||
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="navbar-toggler-icon"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarNav">
|
||||
@@ -52,8 +68,10 @@
|
||||
</div>
|
||||
</div>
|
||||
</nav>
|
||||
<main id="main-content">
|
||||
{% block content %}
|
||||
{% endblock %}
|
||||
</main>
|
||||
|
||||
|
||||
<!-- Footer -->
|
||||
@@ -61,10 +79,10 @@
|
||||
<div class="container">
|
||||
<div class="row">
|
||||
<div class="col-lg-6 mb-4 mb-lg-0">
|
||||
<h5 class="text-uppercase mb-4">Stonehedge Community Homeowners Association</h5>
|
||||
<h2 class="h5 text-uppercase mb-4">Stonehedge Community Homeowners Association</h2>
|
||||
</div>
|
||||
<div class="col-lg-4 offset-lg-2 mb-4 mb-lg-0">
|
||||
<h5 class="text-uppercase mb-4">Quick Links</h5>
|
||||
<h2 class="h5 text-uppercase mb-4">Quick Links</h2>
|
||||
<ul class="list-unstyled">
|
||||
<li class="mb-2"><a href="{% url 'index2' %}" class="text-white-50 text-decoration-none">Home</a></li>
|
||||
<li class="mb-2"><a href="{% url 'about_us2' %}" class="text-white-50 text-decoration-none">About</a></li>
|
||||
@@ -79,8 +97,8 @@
|
||||
<hr class="my-4 text-white-50">
|
||||
<div class="row align-items-center">
|
||||
<div id="footer">
|
||||
<p>© Stonehedge Community Homeowners Association 2010-<script>document.write( new Date().getFullYear() );</script>. All rights reserved </p>
|
||||
<p> Developed by <a href="https://aimloperations.com">AI ML Operations, LLC</a></p>
|
||||
<p>© Stonehedge Community Homeowners Association 2010-{% now "Y" %}. All rights reserved.</p>
|
||||
<p> Developed by <a href="https://aimloperations.com" class="text-white-50">AI ML Operations, LLC</a></p>
|
||||
</div>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Calendar | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
/* Calendar Page Specific Styles */
|
||||
.event-card {
|
||||
@@ -23,6 +23,7 @@
|
||||
height: 180px;
|
||||
width: 100%;
|
||||
object-fit: cover;
|
||||
aspect-ratio: 16 / 9;
|
||||
}
|
||||
|
||||
.nav-tabs .nav-link {
|
||||
@@ -62,20 +63,29 @@
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Calendar | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.{% endblock %}
|
||||
{% block twitter_title %}Calendar | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Stonehedge community calendar — upcoming HOA events, gatherings, and past activities for Wheaton residents.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="py-5">
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<!-- Calendar Navigation -->
|
||||
<div class="row mb-4">
|
||||
<div class="col-12">
|
||||
<h1 class="text-success mb-3">Community Calendar</h1>
|
||||
<ul class="nav nav-tabs" id="calendarTabs" role="tablist">
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link active" id="upcoming-tab" data-bs-toggle="tab" data-bs-target="#upcoming" type="button" role="tab">
|
||||
<button class="nav-link active" id="upcoming-tab" data-bs-toggle="tab" data-bs-target="#upcoming" type="button" role="tab" aria-controls="upcoming" aria-selected="true">
|
||||
Upcoming Events
|
||||
</button>
|
||||
</li>
|
||||
<li class="nav-item" role="presentation">
|
||||
<button class="nav-link" id="past-tab" data-bs-toggle="tab" data-bs-target="#past" type="button" role="tab">
|
||||
<button class="nav-link" id="past-tab" data-bs-toggle="tab" data-bs-target="#past" type="button" role="tab" aria-controls="past" aria-selected="false">
|
||||
Past Events
|
||||
</button>
|
||||
</li>
|
||||
@@ -172,7 +182,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Pay Dues | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
/* Payment Page Specific Styles */
|
||||
.payment-option-card {
|
||||
@@ -50,15 +50,23 @@
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Pay Dues | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.{% endblock %}
|
||||
{% block twitter_title %}Pay Dues | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Pay annual Stonehedge HOA dues securely online via Stripe. Current annual dues are $30.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="py-5">
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<!-- Payment Information Card -->
|
||||
<div class="card shadow-sm mb-5">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h3 class="mb-0">Payment Information</h3>
|
||||
<h1 class="h3 mb-0">Payment Information</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="alert alert-info">
|
||||
@@ -110,7 +118,7 @@
|
||||
<h4 class="text-success">Credit/Debit Card</h4>
|
||||
<p class="card-text">Pay securely with Visa, Mastercard, American Express, or Discover.</p>
|
||||
|
||||
<button class="btn btn-success mt-3" id="submitBtn">Pay Dues</button>
|
||||
<button class="btn btn-success mt-3" id="submitBtn" type="button" aria-label="Pay annual dues with credit or debit card">Pay Dues</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -184,7 +192,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
{% block extra_js %}
|
||||
|
||||
@@ -2,16 +2,18 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Payment Cancelled | Stonehedge Community Homeowners Association</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Your Stonehedge HOA dues payment was cancelled.">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="mid-body">
|
||||
<h1>Your payment cancelled.</h1>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<h1>Your payment cancelled.</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -2,16 +2,18 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Payment Successful | Stonehedge Community Homeowners Association</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Your Stonehedge HOA dues payment was successful.">
|
||||
<meta name="robots" content="noindex, nofollow">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
|
||||
|
||||
<div class="mid-body">
|
||||
<h1>Your payment succeeded.</h1>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<h1>Your payment succeeded.</h1>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Home | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
.hero-section {
|
||||
background: url({% static 'images/header.gif' %});
|
||||
@@ -20,6 +20,14 @@
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Home | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.{% endblock %}
|
||||
{% block twitter_title %}Home | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Welcome to Stonehedge Community Homeowners Association in Wheaton, IL. Pay dues, join as a member, find events, and meet the HOA board.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<!-- Hero Section -->
|
||||
<section id="home" class="py-5 bg-success bg-opacity-10">
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
# Stonehedge Community Homeowners Association (SCHA)
|
||||
|
||||
> Public website for the Stonehedge Community Homeowners Association in Wheaton, Illinois.
|
||||
|
||||
Stonehedge is a residential homeowners association serving Wheaton, IL. This site helps residents learn about the community, pay annual dues, join as members, view events, meet the board, and find useful local links.
|
||||
|
||||
## Primary pages
|
||||
|
||||
- [Home]({{ site_root }}): Community overview and quick links to dues, membership, events, and the board
|
||||
- [About Us]({{ site_root }}about_us): Schools, community history, local shopping/dining, and nearby parks
|
||||
- [Calendar]({{ site_root }}calendar): Upcoming and past community events
|
||||
- [Pay Dues]({{ site_root }}dues): Annual dues payment via Stripe checkout ($30/year)
|
||||
- [Join Today]({{ site_root }}membership_form): New member registration form (address, household contacts, committee interests)
|
||||
- [SCHA Board]({{ site_root }}scha_board): Current volunteer board officers and contacts
|
||||
- [Useful Links]({{ site_root }}useful_links): External resources for residents
|
||||
|
||||
## Machine-readable discovery
|
||||
|
||||
- Sitemap: {{ site_root }}sitemap.xml
|
||||
- Robots: {{ site_root }}robots.txt
|
||||
- This file: {{ site_root }}llms.txt
|
||||
|
||||
## Transactional flows
|
||||
|
||||
- Membership: HTML form POST to /membership_form (CSRF protected; includes reCAPTCHA)
|
||||
- Dues payment: client creates Stripe Checkout session via /create-checkout-session/, then redirects to Stripe
|
||||
|
||||
## Notes for agents
|
||||
|
||||
- Prefer public navigation links in the primary navbar / footer
|
||||
- Do not scrape or interact with /admin/ or member-only DEBUG routes
|
||||
- Keep interactions within visible, labeled controls; payment completes on Stripe's hosted checkout
|
||||
@@ -2,8 +2,8 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<script type="text/css">
|
||||
<title>Join Today | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
/* Membership Form Specific Styles */
|
||||
#membershipForm fieldset {
|
||||
margin-bottom: 2rem;
|
||||
@@ -60,18 +60,26 @@
|
||||
.modal-header .btn-close {
|
||||
filter: invert(1);
|
||||
}
|
||||
</script>
|
||||
</style>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Join Today | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.{% endblock %}
|
||||
{% block twitter_title %}Join Today | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Join Stonehedge Community Homeowners Association. Submit membership details, household contacts, and committee interests.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="py-5">
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h2 class="h4 mb-0">New Member Information</h2>
|
||||
<h1 class="h4 mb-0">New Member Information</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<form id="membershipForm" method="POST" action='{% url "membership_form2" %}' class="needs-validation" novalidate>
|
||||
@@ -112,7 +120,7 @@
|
||||
</div>
|
||||
<div class="col-md-4">
|
||||
<label for="zipCode" class="form-label">ZIP Code*</label>
|
||||
<input type="text" class="form-control" id="zipCode" value="zipCode" value="60189" required>
|
||||
<input type="text" class="form-control" id="zipCode" name="zipCode" value="60189" required>
|
||||
<div class="invalid-feedback">
|
||||
Please provide your ZIP code.
|
||||
</div>
|
||||
@@ -197,77 +205,77 @@
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="block_captain" for="block_captain" name="block_captain">
|
||||
<label class="form-check-label" id="block_captain">
|
||||
<input class="form-check-input" type="checkbox" id="block_captain" name="block_captain">
|
||||
<label class="form-check-label" for="block_captain">
|
||||
BlockCaptain
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="coordinator" for="coordinator" name="coordinator">
|
||||
<label class="form-check-label" id="coordinator">
|
||||
<input class="form-check-input" type="checkbox" id="coordinator" name="coordinator">
|
||||
<label class="form-check-label" for="coordinator">
|
||||
Coordinator
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="egg_hunt" for="egg_hunt" name="egg_hunt">
|
||||
<label class="form-check-label" id="egg_hunt">
|
||||
<input class="form-check-input" type="checkbox" id="egg_hunt" name="egg_hunt">
|
||||
<label class="form-check-label" for="egg_hunt">
|
||||
Easter Egg Hunt
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="spring_garage_sale" for="spring_garage_sale" name="spring_garage_sale">
|
||||
<label class="form-check-label" id="spring_garage_sale">
|
||||
<input class="form-check-input" type="checkbox" id="spring_garage_sale" name="spring_garage_sale">
|
||||
<label class="form-check-label" for="spring_garage_sale">
|
||||
Spring Garage Sale
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="golf_outing" for="golf_outing" name="golf_outing">
|
||||
<label class="form-check-label" id="golf_outing">
|
||||
<input class="form-check-input" type="checkbox" id="golf_outing" name="golf_outing">
|
||||
<label class="form-check-label" for="golf_outing">
|
||||
Golf Outing
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="ice_cream_social" for="ice_cream_social" name="ice_cream_social">
|
||||
<label class="form-check-label" id="ice_cream_social">
|
||||
<input class="form-check-input" type="checkbox" id="ice_cream_social" name="ice_cream_social">
|
||||
<label class="form-check-label" for="ice_cream_social">
|
||||
Ice Creame Social
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="fall_garage_sale" for="fall_garage_sale" name="fall_garage_sale">
|
||||
<label class="form-check-label" id="fall_garage_sale">
|
||||
<input class="form-check-input" type="checkbox" id="fall_garage_sale" name="fall_garage_sale">
|
||||
<label class="form-check-label" for="fall_garage_sale">
|
||||
Fall Garage Sale
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="halloween_party" for="halloween_party" name="halloween_party">
|
||||
<label class="form-check-label" id="halloween_party">
|
||||
<input class="form-check-input" type="checkbox" id="halloween_party" name="halloween_party">
|
||||
<label class="form-check-label" for="halloween_party">
|
||||
Halloween Party
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="santa_visit" for="santa_visit" name="santa_visit">
|
||||
<label class="form-check-label" id="santa_visit">
|
||||
<input class="form-check-input" type="checkbox" id="santa_visit" name="santa_visit">
|
||||
<label class="form-check-label" for="santa_visit">
|
||||
Santa Visits
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="civic_affair" for="civic_affair" name="civic_affair">
|
||||
<label class="form-check-label" id="civic_affair">
|
||||
<input class="form-check-input" type="checkbox" id="civic_affair" name="civic_affair">
|
||||
<label class="form-check-label" for="civic_affair">
|
||||
Civic Affairs Journalist
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="phone_directory" for="phone_directory" name="phone_directory">
|
||||
<label class="form-check-label" id="phone_directory">
|
||||
<input class="form-check-input" type="checkbox" id="phone_directory" name="phone_directory">
|
||||
<label class="form-check-label" for="phone_directory">
|
||||
Annual Phone Director
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="no_preference" for="no_preference" name="no_preference">
|
||||
<label class="form-check-label" id="no_preference">
|
||||
<input class="form-check-input" type="checkbox" id="no_preference" name="no_preference">
|
||||
<label class="form-check-label" for="no_preference">
|
||||
No Preference
|
||||
</label>
|
||||
</div>
|
||||
@@ -352,7 +360,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -2,8 +2,22 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>Newsletters | Stonehedge Community Homeowners Association</title>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Newsletters | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.{% endblock %}
|
||||
{% block twitter_title %}Newsletters | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Stonehedge Community Homeowners Association newsletters and community updates for Wheaton residents.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<h1 class="text-success mb-3">Newsletters</h1>
|
||||
<p class="lead">Community newsletters will appear here as they are published.</p>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@@ -0,0 +1,18 @@
|
||||
User-agent: *
|
||||
Allow: /
|
||||
|
||||
Disallow: /admin/
|
||||
Disallow: /login/
|
||||
Disallow: /signup/
|
||||
Disallow: /dashboard/
|
||||
Disallow: /directory/
|
||||
Disallow: /posts/
|
||||
Disallow: /posts_create/
|
||||
Disallow: /profile/
|
||||
Disallow: /password_reset/
|
||||
Disallow: /set_password/
|
||||
Disallow: /config/
|
||||
Disallow: /create-checkout-session/
|
||||
Disallow: /webhook/
|
||||
|
||||
Sitemap: {{ sitemap_url }}
|
||||
@@ -2,7 +2,7 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<title>SCHA Board | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
/* Board Page Specific Styles */
|
||||
.card-header h4 {
|
||||
@@ -35,15 +35,23 @@
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.">
|
||||
{% endblock %}
|
||||
{% block og_title %}SCHA Board | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.{% endblock %}
|
||||
{% block twitter_title %}SCHA Board | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Meet the volunteer Stonehedge Community Homeowners Association board officers serving Wheaton residents.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="py-5">
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<!-- Board Information -->
|
||||
<div class="row justify-content-center mb-5">
|
||||
<div class="col-lg-10">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-body text-center">
|
||||
<h3 class="text-success mb-3">2025-2026 Stonehedge Community Homeowners Association Board</h3>
|
||||
<h1 class="h3 text-success mb-3">2025-2026 Stonehedge Community Homeowners Association Board</h1>
|
||||
<p>The Stonehedge Community Homeowners Association is governed by a volunteer board of directors elected by the community members. Board members serve two-year terms and are responsible for overseeing the community's operations, finances, and enforcement of covenants.</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -98,5 +106,5 @@
|
||||
|
||||
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
{% for entry in urls %}
|
||||
<url>
|
||||
<loc>{{ entry.loc }}</loc>
|
||||
<changefreq>{{ entry.changefreq }}</changefreq>
|
||||
<priority>{{ entry.priority }}</priority>
|
||||
</url>
|
||||
{% endfor %}
|
||||
</urlset>
|
||||
@@ -2,8 +2,8 @@
|
||||
{% load static %}
|
||||
|
||||
{% block pagetitle %}
|
||||
<title>Stonehedge Community Homeowners Association</title>
|
||||
<script type="text/css">
|
||||
<title>Useful Links | Stonehedge Community Homeowners Association</title>
|
||||
<style type="text/css">
|
||||
/* Links Page Specific Styles */
|
||||
.links-table th {
|
||||
background-color: var(--bs-success);
|
||||
@@ -41,17 +41,25 @@
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block meta_tags %}
|
||||
<meta name="description" content="Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.">
|
||||
{% endblock %}
|
||||
{% block og_title %}Useful Links | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block og_description %}Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.{% endblock %}
|
||||
{% block twitter_title %}Useful Links | Stonehedge Community Homeowners Association{% endblock %}
|
||||
{% block twitter_description %}Helpful links for Stonehedge residents — city services, utilities, schools, and neighborhood resources.{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<main class="py-5">
|
||||
<div class="py-5">
|
||||
<div class="container">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-10">
|
||||
<div class="card shadow-sm">
|
||||
<div class="card-header bg-success text-white">
|
||||
<h3 class="mb-0">Useful Links</h3>
|
||||
<h1 class="h3 mb-0">Useful Links</h1>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="table-responsive">
|
||||
@@ -264,7 +272,7 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -89,6 +89,49 @@ class PublicPageTests(TestCase):
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, "City of Wheaton")
|
||||
|
||||
def test_public_pages_include_seo_metadata(self):
|
||||
pages = [
|
||||
("index2", "Home | Stonehedge"),
|
||||
("about_us2", "About Us | Stonehedge"),
|
||||
("calendar2", "Calendar | Stonehedge"),
|
||||
("dues2", "Pay Dues | Stonehedge"),
|
||||
("membership_form2", "Join Today | Stonehedge"),
|
||||
("scha_board2", "SCHA Board | Stonehedge"),
|
||||
("useful_links2", "Useful Links | Stonehedge"),
|
||||
]
|
||||
|
||||
for name, title_fragment in pages:
|
||||
with self.subTest(page=name):
|
||||
response = self.client.get(reverse(name))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertContains(response, f"<title>{title_fragment}")
|
||||
self.assertContains(response, 'name="description"')
|
||||
self.assertContains(response, 'property="og:title"')
|
||||
self.assertContains(response, 'rel="canonical"')
|
||||
self.assertContains(response, 'id="main-content"')
|
||||
self.assertContains(response, "Skip to main content")
|
||||
|
||||
def test_robots_txt(self):
|
||||
response = self.client.get(reverse("robots_txt"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
||||
self.assertContains(response, "Sitemap:")
|
||||
self.assertContains(response, "Disallow: /admin/")
|
||||
|
||||
def test_sitemap_xml(self):
|
||||
response = self.client.get(reverse("sitemap_xml"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("xml", response["Content-Type"])
|
||||
self.assertContains(response, reverse("index2"))
|
||||
self.assertContains(response, reverse("dues2"))
|
||||
|
||||
def test_llms_txt(self):
|
||||
response = self.client.get(reverse("llms_txt"))
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response["Content-Type"].split(";")[0], "text/plain")
|
||||
self.assertContains(response, "Stonehedge Community Homeowners Association")
|
||||
self.assertContains(response, reverse("membership_form2").lstrip("/"))
|
||||
|
||||
|
||||
@override_settings(
|
||||
RECAPTCHA_PUBLIC_KEY="test-public-key",
|
||||
|
||||
@@ -38,6 +38,9 @@ urlpatterns = authenticated_views + [
|
||||
path("membership_form", views.membership_form2, name="membership_form2"),
|
||||
path("scha_board", views.scha_board2, name="scha_board2"),
|
||||
path("useful_links", views.useful_links2, name="useful_links2"),
|
||||
path("robots.txt", views.robots_txt, name="robots_txt"),
|
||||
path("sitemap.xml", views.sitemap_xml, name="sitemap_xml"),
|
||||
path("llms.txt", views.llms_txt, name="llms_txt"),
|
||||
# stripe specific urls below
|
||||
path("config/", views.stripe_config),
|
||||
path("create-checkout-session/", views.create_checkout_session),
|
||||
|
||||
@@ -18,6 +18,7 @@ from django.http.response import JsonResponse, HttpResponse
|
||||
from django.views.decorators.csrf import csrf_exempt # new
|
||||
from django.contrib.auth import logout, authenticate, login
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from django.urls import reverse
|
||||
import stripe
|
||||
import logging
|
||||
|
||||
@@ -122,6 +123,55 @@ def useful_links(request):
|
||||
return render(request, "schasite/useful_links.html", {"links": useful_links})
|
||||
|
||||
|
||||
PUBLIC_SITEMAP_ROUTES = (
|
||||
("index2", "weekly", "1.0"),
|
||||
("about_us2", "monthly", "0.8"),
|
||||
("calendar2", "weekly", "0.8"),
|
||||
("dues2", "monthly", "0.9"),
|
||||
("membership_form2", "monthly", "0.9"),
|
||||
("scha_board2", "monthly", "0.7"),
|
||||
("useful_links2", "monthly", "0.6"),
|
||||
("newsletters2", "monthly", "0.5"),
|
||||
)
|
||||
|
||||
|
||||
def robots_txt(request):
|
||||
sitemap_url = request.build_absolute_uri(reverse("sitemap_xml"))
|
||||
return render(
|
||||
request,
|
||||
"schasite/robots.txt",
|
||||
{"sitemap_url": sitemap_url},
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
|
||||
def sitemap_xml(request):
|
||||
urls = [
|
||||
{
|
||||
"loc": request.build_absolute_uri(reverse(name)),
|
||||
"changefreq": changefreq,
|
||||
"priority": priority,
|
||||
}
|
||||
for name, changefreq, priority in PUBLIC_SITEMAP_ROUTES
|
||||
]
|
||||
return render(
|
||||
request,
|
||||
"schasite/sitemap.xml",
|
||||
{"urls": urls},
|
||||
content_type="application/xml",
|
||||
)
|
||||
|
||||
|
||||
def llms_txt(request):
|
||||
site_root = request.build_absolute_uri("/")
|
||||
return render(
|
||||
request,
|
||||
"schasite/llms.txt",
|
||||
{"site_root": site_root},
|
||||
content_type="text/plain; charset=utf-8",
|
||||
)
|
||||
|
||||
|
||||
def index2(request):
|
||||
return render(request, "schasite/index2.html", {})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user