KJP Phase 1 — Scope & Dev Outline

Single source of truth for the currently-active SOW. Start here before touching code.

Note on hours: Original quote was 23.5–36 hrs for the same line items. Signed SOW is 8 hrs. Eric's call (2026-04-23): assume intentional, work to the 8-hr number, flag overages as they surface.


Environment

Item Detail
Host Kinsta (not Flywheel)
SSH ssh kurtjohnsonphotographycom@34.162.230.19 -p 61436
WP path (prod) /www/kurtjohnsonphotographycom_376/public
Local dev DevKinsta (Docker)
Docker WP-CLI docker exec devkinsta_fpm bash -c "cd /www/kinsta/public/kurtjohnsonphotographycom && wp ..."
Theme gmlaunch at /Users/edowns/DevKinsta/public/kurtjohnsonphotographycom/wp-content/themes/gmlaunch/
GA4 property G-RF1XX48Q59
Image storage Flat files at /wp-content/uploads/wpallimport/files/ — NOT WP Media Library. ACF text fields store filenames.
Import sheet https://docs.google.com/spreadsheets/d/1YYkMxk3xBrMHBywyEqWFbvo75qTyyU2G3s2hsb9NKso

Scope — 5 line items from the signed SOW

SOW text: "Gallery Lightbox & Photo Navigation to allow users to enlarge photos on click."

Hover-preview decision (2026-04-29): click-only — signed SOW scope, no hover preview. Re-quotable later.

Client decisions (from KJP-Project-Hub.md): - Click → full PhotoSwipe lightbox with all info + prev/next arrows - Arrows cycle through all images on the current page (49 posts/page on Photography) - Applies to both Photography and Installations archives

Library: PhotoSwipe 5 (MIT, ~5kb, no deps, photography-native)

Files to edit: - inc/loops/loop-photo.php — wrap images, add lightbox data attributes - inc/cpt-loops/loop-photography.php — archive template - inc/cpt-loops/loop-installations.php — installation archive template - functions.php — enqueue PhotoSwipe - header.php — already has the facetwp-loaded event; rebind PhotoSwipe after FacetWP AJAX reloads - New init JS file


2. Installation Slider — Dynamic Sidebar

SOW text: "When clicking through installation photos, the sidebar description should change per slide."

Client decisions (from KJP-Project-Hub.md): - Sidebar changes on each slide: description, type, tags (everything except title and institution) - Title + institution stay fixed (it's still one installation project) - KJP handles all data entry for 486 installations × 10–30 photos each - They plan to rewrite descriptions to better match individual photos

Architecture change: Extend ACF installations_photos_2 repeater with per-photo subfields (description, type, tags), then JS swaps sidebar HTML on Slick's afterChange event.

Files to edit: - single-installations.php — output per-slide data as data-* attributes; sidebar becomes JS-swappable container - js/slick-init.js — hook afterChange to update sidebar - acf-json/group_62741bba884ac.json — add repeater subfields

Gotchas: - Slick class has a typo: .instalation-slider (one L). Don't "fix" it. - Fallback gracefully to installation-level data if a slide has no per-photo metadata (data entry isn't done yet for 486 posts).


3. Newsletter — MailChimp + First/Last Name Fields

SOW text: "Add first and last name fields to the newsletter form. Pass entries through to Mailchimp."

Client decisions (from KJP-Project-Hub.md): - Sitewide (footer form on all pages + homepage CTA module) - Name fields required - MailChimp account exists; Casey has API key - Keep Tori email notification as backup (still want her to see signups) - Q1 maintenance found 98% spam (7,473 of 7,613 entries) — reCAPTCHA v3 is needed

Approach: Gravity Forms MailChimp Add-On (included with their Elite license) + reCAPTCHA v3.

Files to edit: - Gravity Forms admin → Form 2: add First Name + Last Name fields - Gravity Forms admin → MailChimp feed: Email→email, First Name→FNAME, Last Name→LNAME - footer.php — layout adjustment, current form is single-line (email + arrow). Options: stacked vertical, or two-row (names row 1, email+submit row 2), or compact with placeholder labels. No formal design. - inc/page-modules/2_column_email_signup_cta_module.php — homepage module variant - functions.php — if needed for submit button filter

Blocker: MailChimp API key from Casey.


4. Exclude Team from Analytics (GA4)

SOW text: "GA4 internal traffic filters (IP-based for office/studio) + Google Analytics Opt-out browser extension for home."

No code changes — all GA4 admin configuration.

Team: 4 people across 2 homes + 1 studio. - Casey + Jerred (one home) - Kurt + Carolyn (one home) - All four work at a shared studio too

What to do: 1. GA4 Admin → Data Streams → Web → Configure Tag Settings → Define Internal Traffic → add 3 IPs 2. GA4 Admin → Data Settings → Data Filters → activate Internal Traffic filter 3. Email team with link to https://tools.google.com/dlpage/gaoptout (handles non-office browsing) 4. Verify in GA4 real-time reports

Blocker: 3 IP addresses. Easiest: ask each person to Google "what is my IP" from office/studio + both homes.


5. Search Results Limit > 200

SOW text: "Allow for the search results to be greater than 200."

Root cause: FacetWP caps SearchWP queries at 200 in plugins/facetwp/includes/integrations/searchwp/searchwp.php line 187 (hardcoded performance guard).

Client decision (from KJP-Project-Hub.md): Raise to 2,000.

Fix: Use SearchWP's per_page filter to override FacetWP's cap. This fires after FacetWP's override, so it wins. Snippet is in the working doc.

Perf impact: 0.5–2s slower on broad terms ("flower" matches thousands). Narrow terms see zero diff. Pagination unchanged.

Files to edit: functions.php (filter) OR a small mu-plugin. Do NOT edit the FacetWP plugin file directly (overwritten on update).

No blockers. Can ship today.


Admin / Project Management (1 hr in SOW)


Kickoff Blockers (need before work starts)

  1. MailChimp API key — from Casey. Blocks item 3 (wiring).
  2. 3 IP addresses — Casey/Jerred home, Kurt/Carolyn home, studio. Blocks item 4.

Item 5 (search fix) has zero blockers and can ship on day 1 as a quick win.


QA Checklist (✅ Launched 2026-05-09)


What's NOT in Phase 1


File What it is
2026-018_SOW_Phase2-SIGNED.pdf Binding contract (same folder)
KJP-Website-Updates-Working-Doc.md Full dev specs, code snippets, hour breakdowns per item (same folder)
../reference/KJP-Client-Questions.md Original discovery Q&A
../README.md Top-level project hub (timeline, status log, contacts)
../KJP-Project-Hub.md Canonical client-decisions hub (ex-Notion)