backup
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
"""
|
||||
Lahr Carpet Cleaning — Location page generator.
|
||||
Creates /locations/<slug>/index.html for each city.
|
||||
Run: python3 tools/gen-locations.py
|
||||
"""
|
||||
import os
|
||||
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
|
||||
LOC_DIR = os.path.join(BASE_DIR, "locations")
|
||||
|
||||
CITIES = [
|
||||
{"name": "Waterloo", "slug": "waterloo-ny", "county": "Seneca County", "note": "Our home base. Fastest response times in the area."},
|
||||
{"name": "Geneva", "slug": "geneva-ny", "county": "Ontario County", "note": "Full residential and commercial services throughout Geneva."},
|
||||
{"name": "Seneca Falls", "slug": "seneca-falls-ny", "county": "Seneca County", "note": "Serving homes, vacation rentals, and businesses in Seneca Falls."},
|
||||
{"name": "Canandaigua", "slug": "canandaigua-ny", "county": "Ontario County", "note": "Lakefront homes, rentals, and businesses along Canandaigua Lake."},
|
||||
{"name": "Penn Yan", "slug": "penn-yan-ny", "county": "Yates County", "note": "Homes, wineries, and short-term rentals in the Penn Yan area."},
|
||||
{"name": "Newark", "slug": "newark-ny", "county": "Wayne County", "note": "Carpet and upholstery cleaning for homes and businesses in Newark."},
|
||||
{"name": "Clifton Springs", "slug": "clifton-springs-ny", "county": "Ontario County", "note": "Residential and commercial cleaning throughout Clifton Springs."},
|
||||
{"name": "Lodi", "slug": "lodi-ny", "county": "Seneca County", "note": "Serving homes and vacation properties in Lodi and surrounding areas."},
|
||||
{"name": "Himrod", "slug": "himrod-ny", "county": "Yates County", "note": "Carpet and floor cleaning for homes and rentals in the Himrod area."},
|
||||
{"name": "Phelps", "slug": "phelps-ny", "county": "Ontario County", "note": "Residential carpet and upholstery cleaning throughout Phelps."},
|
||||
{"name": "Shortsville", "slug": "shortsville-ny", "county": "Ontario County", "note": "Home and business cleaning services in Shortsville, NY."},
|
||||
{"name": "Victor", "slug": "victor-ny", "county": "Ontario County", "note": "Residential and commercial carpet cleaning throughout Victor."},
|
||||
{"name": "Naples", "slug": "naples-ny", "county": "Ontario County", "note": "Serving homes, wineries, and vacation rentals in the Naples area."},
|
||||
{"name": "Gorham", "slug": "gorham-ny", "county": "Ontario County", "note": "Carpet and floor cleaning for homes and properties in Gorham."},
|
||||
{"name": "Manchester", "slug": "manchester-ny", "county": "Ontario County", "note": "Residential and commercial cleaning services in Manchester, NY."},
|
||||
{"name": "Ovid", "slug": "ovid-ny", "county": "Seneca County", "note": "Serving homes and rental properties throughout Ovid."},
|
||||
{"name": "Clyde", "slug": "clyde-ny", "county": "Wayne County", "note": "Carpet, upholstery, and floor cleaning for homes and businesses in Clyde."},
|
||||
{"name": "Farmington", "slug": "farmington-ny", "county": "Ontario County", "note": "Residential and commercial carpet cleaning throughout Farmington."},
|
||||
{"name": "East Bloomfield", "slug": "east-bloomfield-ny", "county": "Ontario County", "note": "Serving homes and properties in East Bloomfield and surrounding areas."},
|
||||
{"name": "Rushville", "slug": "rushville-ny", "county": "Yates County", "note": "Carpet and upholstery cleaning for homes and rentals in Rushville."},
|
||||
{"name": "Finger Lakes", "slug": "finger-lakes-ny", "county": "Region", "note": "Serving vacation rentals, wineries, and homes across the Finger Lakes region."},
|
||||
]
|
||||
|
||||
SERVICES = [
|
||||
{"name": "Carpet Cleaning", "slug": "/services/carpet-cleaning/", "img": "/assets/images/services/carpet-cleaning.jpg", "sub": "In-Home Service", "desc": "Hot water extraction removes deep-seated dirt, allergens, and stains from carpet fibers throughout your home."},
|
||||
{"name": "Stairs Cleaning", "slug": "/services/stairs/", "img": "/assets/images/services/stairs-cleaning.jpg", "sub": "Step by Step", "desc": "Stairs collect more dirt per square inch than any flat surface. We clean every tread, riser, and landing."},
|
||||
{"name": "Upholstery Cleaning","slug": "/services/upholstery/", "img": "/assets/images/services/upholstery-cleaning.jpg","sub": "Furniture Refresh", "desc": "Safe, effective cleaning for sofas, chairs, and mattresses. We work with all fabric types and leave no residue."},
|
||||
{"name": "Floor Cleaning", "slug": "/services/floors/", "img": "/assets/images/services/floor-cleaning.jpg", "sub": "Hard Surface Care", "desc": "Wood floor cleaning and tile and grout restoration that brings hard surfaces back to their original condition."},
|
||||
{"name": "Area Rug Cleaning", "slug": "/services/area-rugs/", "img": "/assets/images/services/area-rug-cleaning.jpg", "sub": "Delicate Care", "desc": "Gentle, specialized cleaning for oriental, Persian, and delicate rugs that restores color and removes embedded dirt."},
|
||||
{"name": "Add-On Services", "slug": "/services/add-ons/", "img": "/assets/images/services/add-ons.jpg", "sub": "Extra Care", "desc": "Furniture moving, pet hair removal, odor treatment, and heavily soiled area care available alongside any service."},
|
||||
]
|
||||
|
||||
HERO_IMAGES = [
|
||||
"/assets/images/hero/hero-living-room.jpg",
|
||||
"/assets/images/hero/hero-clean-result.jpg",
|
||||
"/assets/images/hero/hero-technician.jpg",
|
||||
"/assets/images/hero/hero-before-after.jpg",
|
||||
"/assets/images/hero/hero-stairs.jpg",
|
||||
]
|
||||
|
||||
|
||||
def service_card(svc, city_name):
|
||||
accent_word, rest = svc["name"].split(" ", 1) if " " in svc["name"] else (svc["name"], "")
|
||||
h3 = f'<span class="text-accent">{accent_word}</span> {rest}'.strip()
|
||||
return f""" <div class="service-card">
|
||||
<div class="service-image"><img src="{svc['img']}" alt="{svc['name']} in {city_name}, NY"></div>
|
||||
<h3 class="heading-3">{h3}</h3>
|
||||
<div class="text-block-4">{svc['sub']}</div>
|
||||
<p class="paragraph-2">{svc['desc']}</p>
|
||||
<a href="{svc['slug']}" class="btn btn-primary">Learn More</a>
|
||||
</div>"""
|
||||
|
||||
|
||||
def page_html(city, idx):
|
||||
hero_img = HERO_IMAGES[idx % len(HERO_IMAGES)]
|
||||
cards = "\n".join(service_card(s, city["name"]) for s in SERVICES)
|
||||
name = city["name"]
|
||||
county = city["county"]
|
||||
note = city["note"]
|
||||
slug = city["slug"]
|
||||
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Carpet Cleaning in {name}, NY | Lahr Carpet Cleaning</title>
|
||||
<meta name="description" content="Professional carpet, upholstery, and floor cleaning in {name}, NY. Lahr Carpet Cleaning serves {county} and the Finger Lakes region. Call 315-719-1218.">
|
||||
<link rel="stylesheet" href="/assets/css/styles.css?v=5">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="header" id="header">
|
||||
<div class="container"><div id="site-nav"></div></div>
|
||||
</header>
|
||||
|
||||
<section class="page-hero" style="background-image: url('{hero_img}');">
|
||||
<div class="container">
|
||||
<div class="page-hero-content">
|
||||
<span class="hero-eyebrow">{county} — Finger Lakes</span>
|
||||
<h1 class="hero-title">{name},<br><span class="text-accent">NY</span></h1>
|
||||
<p>{note}</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/contact/" class="btn btn-primary btn-large">Book Now</a>
|
||||
<a href="tel:315-719-1218" class="btn btn-ghost btn-large"><i class="fas fa-phone"></i> 315-719-1218</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="services-overview">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="section-label">{name}, NY</span>
|
||||
<h2 class="section-title">Services in {name}</h2>
|
||||
<p class="section-subtitle">We serve {name} and the surrounding {county} communities. Call to confirm availability for your address.</p>
|
||||
</div>
|
||||
<div class="services-grid">
|
||||
{cards}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-banner">
|
||||
<div class="cta-content">
|
||||
<h2 class="heading-4"><strong>Serving </strong><span class="text-accent"><strong>{name}</strong></span></h2>
|
||||
<p class="paragraph-4">Call 315-719-1218 or submit the form for a free estimate in {name}, NY.</p>
|
||||
<a href="/contact/" class="btn btn-primary">Get a Free Estimate</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="/assets/js/components.js"></script>
|
||||
<script src="/assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
def locations_index():
|
||||
city_cards = []
|
||||
for i, city in enumerate(CITIES):
|
||||
img = HERO_IMAGES[i % len(HERO_IMAGES)]
|
||||
name = city["name"]
|
||||
county = city["county"]
|
||||
note = city["note"]
|
||||
slug = city["slug"]
|
||||
if " " in name:
|
||||
accent_word, rest = name.split(" ", 1)
|
||||
h3 = f'<span class="text-accent">{accent_word}</span> {rest}, NY'
|
||||
else:
|
||||
h3 = f'<span class="text-accent">{name}</span>, NY'
|
||||
city_cards.append(f""" <div class="service-card">
|
||||
<div class="service-image"><img src="{img}" alt="{name} NY"></div>
|
||||
<h3 class="heading-3">{h3}</h3>
|
||||
<div class="text-block-4">{county}</div>
|
||||
<p class="paragraph-2">{note}</p>
|
||||
<a href="/locations/{slug}/" class="btn btn-primary">View Services</a>
|
||||
</div>""")
|
||||
|
||||
cards_html = "\n".join(city_cards)
|
||||
return f"""<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Service Areas | Lahr Carpet Cleaning | Finger Lakes, NY</title>
|
||||
<meta name="description" content="Lahr Carpet Cleaning serves Waterloo, Geneva, Seneca Falls, Canandaigua, Penn Yan, and 16 more cities across the Finger Lakes region. Call 315-719-1218.">
|
||||
<link rel="stylesheet" href="/assets/css/styles.css?v=5">
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css">
|
||||
</head>
|
||||
<body>
|
||||
<header class="header" id="header">
|
||||
<div class="container"><div id="site-nav"></div></div>
|
||||
</header>
|
||||
|
||||
<section class="page-hero" style="background-image: url('/assets/images/hero/hero-technician.jpg');">
|
||||
<div class="container">
|
||||
<div class="page-hero-content">
|
||||
<span class="hero-eyebrow">Finger Lakes Region</span>
|
||||
<h1 class="hero-title">Service<br><span class="text-accent">Areas</span></h1>
|
||||
<p>We clean carpets, upholstery, rugs, and hard floors across 21 cities in Upstate New York. Select your city below.</p>
|
||||
<div class="hero-actions">
|
||||
<a href="/contact/" class="btn btn-primary btn-large">Book Now</a>
|
||||
<a href="tel:315-719-1218" class="btn btn-ghost btn-large"><i class="fas fa-phone"></i> 315-719-1218</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="services-overview">
|
||||
<div class="container">
|
||||
<div class="section-header">
|
||||
<span class="section-label">Where We Work</span>
|
||||
<h2 class="section-title">Cities We Serve</h2>
|
||||
<p class="section-subtitle">Based in Waterloo, NY. We travel throughout Seneca, Ontario, Yates, Wayne, and Cayuga counties.</p>
|
||||
</div>
|
||||
<div class="services-grid">
|
||||
{cards_html}
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="cta-banner">
|
||||
<div class="cta-content">
|
||||
<h2 class="heading-4"><strong>Not sure if we cover your area?</strong></h2>
|
||||
<p class="paragraph-4">Call 315-719-1218 or submit the form and we will confirm availability for your address.</p>
|
||||
<a href="/contact/" class="btn btn-primary">Get a Free Estimate</a>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<div id="site-footer"></div>
|
||||
<script src="/assets/js/components.js"></script>
|
||||
<script src="/assets/js/main.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
"""
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# Write locations index
|
||||
with open(os.path.join(LOC_DIR, "index.html"), "w") as f:
|
||||
f.write(locations_index())
|
||||
print("Wrote locations/index.html")
|
||||
|
||||
# Write each city page
|
||||
for i, city in enumerate(CITIES):
|
||||
city_dir = os.path.join(LOC_DIR, city["slug"])
|
||||
os.makedirs(city_dir, exist_ok=True)
|
||||
out_path = os.path.join(city_dir, "index.html")
|
||||
with open(out_path, "w") as f:
|
||||
f.write(page_html(city, i))
|
||||
print(f"Wrote locations/{city['slug']}/index.html")
|
||||
|
||||
print(f"\nDone. {len(CITIES)} city pages + index generated.")
|
||||
Reference in New Issue
Block a user