A content and tools website that helps people find 24-hour pharmacies across the United States and save money on prescriptions. Built on WordPress with custom React widgets, a programmatic city page pipeline, and a multi-stream affiliate monetization model.
This repo contains all custom code. WordPress core, GeneratePress Pro, and third-party plugins are managed on the server and are not tracked here.
An exact-match domain site targeting "24 hour pharmacy near me" and related high-intent local health queries. Users are often in genuine emergencies - out of medication at midnight, traveling, looking for urgent care alternatives. The site serves that need directly and monetizes through prescription savings tools, insurance lead gen, and telehealth referrals.
This is not an online pharmacy. It does not dispense medications, handle prescriptions, or store any health data.
├── wordpress/
│ ├── theme/ GeneratePress child theme
│ │ ├── style.css
│ │ ├── functions.php
│ │ ├── front-page.php
│ │ ├── single-city.php
│ │ ├── archive-state.php
│ │ ├── header.php
│ │ └── footer.php
│ └── plugin/ Custom plugin: 24hr-pharmacy-tools
│ ├── 24hr-pharmacy-tools.php
│ ├── post-types.php
│ ├── taxonomies.php
│ ├── meta-boxes.php
│ ├── schema.php
│ ├── shortcodes.php
│ ├── settings.php
│ ├── rewrite-rules.php
│ └── rest-api.php
├── widgets/ React widgets (Vite, IIFE output)
│ ├── pharmacy-finder/ [pharmacy_finder] shortcode
│ ├── discount-card/ [discount_card] shortcode
│ ├── price-checker/ [price_checker] shortcode
│ └── open-now-checker/ [open_now_checker] shortcode
├── data/
│ ├── cities.json Target cities with coordinates and population
│ ├── scripts/ Python data pipeline
│ └── pharmacies/ Raw Google Places API response cache
├── CLAUDE.md Instructions for Claude Code
├── .env.example Environment variable reference (no real values)
└── README.md
| Layer | Choice |
|---|---|
| CMS | WordPress 6.x |
| Theme | GeneratePress Pro + child theme |
| Hosting | Hostinger Business |
| CDN / Security | Cloudflare (free tier) |
| Caching | LiteSpeed Cache |
| React widgets | React 18, Vite (library mode, IIFE output) |
| Widget styling | CSS custom properties from GeneratePress (no Tailwind) |
| Data pipeline | Python 3.11 |
| Maps / Places | Google Maps Platform |
| Analytics | Google Analytics 4 + Search Console |
| MailerLite |
Each widget is a standalone React app compiled by Vite in library mode to a single IIFE bundle. Bundles are placed inside the custom plugin and loaded via WordPress shortcodes.
Key rules:
wp_localize_script() from wp_optionsBuild a widget:
cd widgets/discount-card
npm install
npm run build
# Output: dist/discount-card.iife.js
# Copy to: wordpress/plugin/assets/js/
The Python pipeline in data/scripts/ generates city pages programmatically:
data/cities.json (city name, state, lat/lng, population)Raw API responses are cached to data/pharmacies/raw/ to avoid redundant API calls.
Rate limit: max 10 Google Places API requests per second.
Never commit real values. Use .env.example as a reference.
All sensitive values are stored in one of two places:
.env for running data pipeline scriptsThe plugin Settings page stores: Google Maps API key, all affiliate BIN/PCN/Group codes, network publisher IDs. These are passed to React via wp_localize_script().
See .env.example for the full list of required variables.
There is no CI/CD pipeline yet. Deploy manually:
Child theme:
Zip wordpress/theme/
Upload via WP Admin > Appearance > Themes > Add New > Upload
Custom plugin:
Zip wordpress/plugin/
Upload via WP Admin > Plugins > Add New > Upload Plugin
Widget bundles:
Build via Vite (see above)
Copy .iife.js file into plugin/assets/js/
Redeploy plugin zip
Data scripts:
Run locally
Scripts push content to WordPress via REST API
Requires WP_APP_USER and WP_APP_PASSWORD in .env
To automate: add a GitHub Actions workflow that SFTPs changed theme/plugin files to Hostinger on push to main.
Hardening is documented in security-and-ops.md. Key items:
DISALLOW_FILE_EDIT and FORCE_SSL_ADMIN set in wp-config.php24hourpharmacy.com/* in Google Cloud Console/wp-login.php and /xmlrpc.phpThis is a YMYL (Your Money or Your Life) site. Google applies elevated quality standards to health content.
LocalBusiness, FAQPage, BreadcrumbList.HowTo, MedicalWebPage.See CLAUDE.md for the full content generation instructions used by Claude Code.
/ Homepage
/city/{state}/{city-slug}/ City page
/state/{state-slug}/ State directory
/pharmacy/{slug}/ Individual pharmacy
/savings/discount-card/ Discount card hub
/savings/home-testing/ At-home health testing
/insurance/ Insurance comparison
/telehealth/ Telehealth hub
/telehealth/glp1/ GLP-1 telehealth comparison
/seniors/medical-alerts/ Medical alert systems
/mental-health-resources/ Mental health platforms
/blog/{post-slug}/ Blog
/tools/pharmacy-finder/ Standalone finder tool
/advertise/ Direct advertising for independent pharmacies
/about/ About + author bio
/affiliate-disclosure/ FTC disclosure (required)
/privacy-policy/ Privacy policy (required)
/disclaimer/ Medical disclaimer (required)
| Metric | Target |
|---|---|
| LCP | < 2.5s |
| CLS | < 0.1 |
| INP | < 200ms |
| TTFB | < 600ms |
| Mobile Lighthouse | > 90 |
Ad network approval (Raptive/Mediavine) requires strong Core Web Vitals. Test with PageSpeed Insights before applying.