# 3.3 — Signature across the directory

- Rebuilt Signature as a cohesive editorial design system: homepage, discovery, category index, service and location routes, profile, submission, and 404.
- Added browser-local saved places, share/copy link, mobile navigation, active profile tabs, compact mobile identity and fixed mobile contact actions.
- Added Dining, Travel, Real Estate and Technology presets, for sixteen presets total.
- Preserved site logo, primary navigation, stored content, category descriptions, FAQ visibility preferences and existing claim/callback actions.
- Added server-rendered filters and pagination, intentional missing-data states and a review-first submission form with nonce validation, rate limiting and post/redirect/get.
- Bundled Inter locally, added keyboard/reduced-motion support, and kept core search/contact/reviews usable without JavaScript.
- Fixed Signature styling on legacy directory posts and retained the legacy city search parameter.

# Business360 3.2

## Signature: the Business360 design system (listing page)
A fourth layout pack, selectable under Settings > Templates. It ships the listing page first; every other page
type (city, service, search, homepage) is served by Health until Signature versions exist.

- Identity card instead of a stock banner: photo or initial, specialty, open-now badge with closing time,
  claimed badge, name, rating, review count, city and address. The name appears once.
- Sticky section tabs: Overview, Reviews, Hours, Location, FAQ, Similar.
- 8/4 grid with a sticky action card: rating, today's hours with an open or closed dot, Call (formatted number),
  Get directions, Visit website, and either Request a callback (claimed listings) or a claim link.
- At-a-glance tiles: comparison with the city average, days open, and sampled reviews rated 4 or 5 stars.
- Feedback snapshot: a bar per topic showing how many sampled reviews mention it, coloured by whether those
  reviews were positive, mixed or negative. Only topics mentioned in at least two reviews appear, the same
  rule the article follows. Every number comes from the evidence engine.
- Reviews from Google: three shown, long ones clamped with Read more, the rest behind Show all.
- Accordion FAQs built from the listing's own data, a map with the directions header, and uniform Similar cards
  (fixed image ratio, two-line names, rating, distance, open or closed, View profile).
- Mobile: the action card moves to the top, the identity card stacks, tabs scroll sideways.
- All styling is scoped under .gw360-sig, so the theme is untouched. The accent colour comes from the design
  preset, so one layout serves every niche.

## Supporting changes
- Templates fall back through the pack's declared fallback and then Health, so a pack can ship page by page.
- A pack with no Tailwind build of its own loads its fallback's build for the pages it borrows.
- Applying a design preset while Signature is active changes fonts and palette but keeps the Signature layout.
- On Signature pages the floating callback bar is hidden, because those actions live in the action card.

# Business360 3.1.5

- Paragraphs that admit a theme was barely discussed and then infer it anyway are removed at save time, for
  example "comments on wait times were less frequent, overall impressions suggest patients find it manageable".
  A paragraph is only removed when it combines both signals, so evidence-backed sentences that happen to use
  "suggest" ("reviews suggest the front desk is friendly: eight of ten mention it") are kept.
- A heading or bold label left with nothing under it, such as "Recurring Concerns:" after its empty list was
  removed, is removed too. A label that still introduces a list is kept.

# Business360 3.1.4

- Every listing's Location & Maps section now has a "Get directions" link on the right of the heading, in all
  three packs. It opens Google Maps directions to the listing's exact pin when coordinates are stored, and to
  the address otherwise. On hover it underlines and the arrow nudges right; on narrow screens it wraps under
  the heading. It uses the site's accent colour.

# Business360 3.1.3

- Find page: pressing Clear filters after using Near me crashed the search script. The reset left the stored
  location undefined rather than empty, and the next request tried to format it. The reset now clears the
  location properly, returns the sort to Best match and the button to "Near me", and the request only sends
  coordinates when they are real numbers.
- Sensitive lead mode is fail-safe: a site is treated as health, legal, finance or wellness if either its AI
  niche or its applied design preset says so, so a health site with the AI niche left on "general" still never
  shows a free-text box.

# Business360 3.1.2

- Claims no longer store callback fields. The claim form hid "Best time" and "Reason" but still sent their
  default values, so a claim could appear in Leads as "Claim - New patient appointment". The server now clears
  them for claims (and clears the role field for callbacks).
- Only administrators can mark a listing as claimed. Setting the "Claimed by" email switches on lead forwarding,
  so editors can no longer see or change it.

# Business360 3.1.1

Lead and claim hardening. Nothing else changed.

## Callbacks only where the business will receive them
- 3.1 told visitors their request would go to the business, but for an unclaimed listing only the site admin
  received it. Unclaimed listings now show only "Own this business? Claim this listing". Claimed listings show
  "Request a callback", worded as going to the business, which is now true.
- The server refuses callback requests for unclaimed listings too, not just the button.

## Accurate claim wording
- "Before giving you control of this listing" is gone: claiming does not grant access to anything yet. The form
  now says the business will be verified before the listing is marked as claimed, and that callbacks will then
  go straight to the owner.

## Fixed choices are enforced
- "Best time" is allowlisted server-side like "Reason", so a crafted request cannot store free text in it.
  Tested with "Afternoon, I have diabetes and chest pain", which is stored as empty.

## Leads are administrators only
- Leads hold names, phone numbers and emails. Editors and authors can no longer see them.

## Distances in the site's units
- Kilometres by default, miles on US and UK English sites, chosen from the site's language setting (not the
  visitor's location). The radius filter
  uses the same unit. Override with the gw360_distance_unit filter.

# Business360 3.1

## Homepage search: [business360_hero_search]
- City and service dropdowns built from the site's own data, each with live listing counts, sending the
  visitor to the Find page with the filters applied.
- A "Near me" button that uses the browser's location and opens the Find page sorted nearest first.
- A line of real totals under the form ("18 listings across 3 cities"), never an invented statistic.
- Attributes: title, subtitle, find_url, location_label, service_label.

## Distance search on the Find page
- "Near me" button and a "Nearest first" sort option.
- Each result shows its distance in miles once a location is known.
- An optional radius filter (the API takes radius in miles).
- Without a location, "Nearest first" quietly falls back to best match.

## Callback requests and listing claims
- Every listing gets a "Request a callback" button and an "Own this business?" button.
- On health, legal, finance and wellness sites the form never asks for symptoms, history or case details:
  only name, phone or email, best time, and a reason from a fixed list. A free-text field sent in a crafted
  request is discarded before storage. Other niches get an optional details box.
- Leads are stored privately (Listings > Leads), emailed to the site admin, and forwarded to the business only
  once it has claimed its listing.
- Claims arrive through the same form. An admin confirms ownership, then enters the owner's email in the new
  "Claimed by" box on the listing; from then on that listing's callbacks go to the owner too.
- Protection: nonce, hidden honeypot, a minimum fill time, and five submissions per IP per hour. Bots are told
  their request succeeded and nothing is stored.

# Business360 3.0.3

- The Modern pack's review form is now labelled "Write a Review for This Site", matching Classic and Health,
  so all three packs keep imported Google reviews separate from reviews submitted to the site.
- Phone formatting only applies to numbers that are provably North American: those starting +1 or 1, or a bare
  10-digit number on a listing whose country is the United States or Canada. Everything else, including
  10-digit numbers from other countries, is shown exactly as stored.

# Business360 3.0.2

## No reasoning across themes
The model could previously argue from one attribute to another: friendly staff implying a clean office,
easy booking implying short waits. Each theme is now judged only on reviews that discuss that theme, a theme
with no supporting reviews is left out entirely rather than inferred or noted as missing, and hedging words
(likely, probably, suggests that, it can be assumed) are not allowed where the evidence does not exist.

## Honest presentation
- The FAQ no longer claims "Parking and public transport may vary by time of day". There is no parking data,
  so there is no sentence.
- The imported reviews section is labelled "Reviews from Google", and the submission form is labelled as a
  review for this site, so the two sources are not presented as one.

## Phone numbers
US and Canadian numbers display as (512) 382-9500 instead of +15123829500. The tel: link still uses the raw
number, and international numbers are left exactly as they are.

# Business360 3.0.1

## Headings finally appear on the page
The headings were being generated correctly and then thrown away. The block converter split article HTML on
blank lines, but the model returns "<h2>..</h2><p>..</p>" as one unbroken string, so a heading and its
paragraphs landed in the same section, the heading pattern never matched, and the h2 was swallowed by the
paragraph branch. Block-level elements are now separated before splitting, so headings, lists and paragraphs
each become their own block.

## Paragraphs about what the reviews do not say
The prompt forbids mentioning absent data and the cleanup removed short lines, but whole paragraphs such as
"The reviews did not explicitly mention wait times" or "While there are no specific comments about
cleanliness" survived. Those are now removed at save time. Genuine sentences that merely contain similar
words are kept.

# Business360 2.13.7

Final cleanup before rollout. No features, no refactors.

## A real bug in the Classic pack
- Four Classic templates (geo-city, geo-state, geo-country, service-geo) generated their own typography and
  built the font family with str_replace(':', ','), so "Inter:300,400,500" became a font-family of
  "Inter,300,400,500", which no browser resolves. Classic city and state pages have been falling back to a
  generic sans-serif. Those blocks are removed and typography now comes from the one owner.

## Consistent ownership
- Search and 404 pages are rendered by the plugin, so they are now included in the directory-page check and
  get the configured fonts and typography like every other plugin page.

## Known leftover
- Two unused helper methods remain in the REST class. They have no callers and no effect. Removing them
  cleanly needs a careful pass I would rather not make the night before a rollout.

# Business360 2.13.6

The two cleanup items from the review, done properly this time rather than claimed.

## One typography owner, one font loader (actually)
- The template layer had a second Google Fonts loader and still emitted unscoped html, body and h1-h6 rules
  for size and colour. All of it is removed.
- Typography now comes only from Plugin::load_global_fonts() and Plugin::apply_global_typography().
- Verified: a directory page loads one set of font requests, an ordinary page loads none, and there is no
  unscoped body or heading rule anywhere in the output.

## One remote image downloader (actually)
- REST imports had two paths of their own: a hardened Google downloader and an unchecked download_url() for
  everything else. Both are gone.
- Every importer now calls Media::set_featured_from_url(), which enforces HTTPS, host validation, safe
  destinations, wp_safe_remote_get, a 10 MB ceiling, HTTP status and image content type.
- Verified: an import carrying an unsafe image URL still succeeds and simply has no thumbnail.

# Business360 2.13.5

Third review round. Two earlier changelog claims were overstated; both are now actually true.

## Verification wording, properly this time
- The remaining "verified businesses", "verified professionals", "verified providers" and standalone
  "Verified" labels are gone from the heroes, service pages and the SEO descriptions.

## One typography owner, one font loader
- The old typography generator in the template layer is removed. Body and heading styling now comes only from
  Plugin::apply_global_typography(), scoped to body.gw360-directory.
- Google Fonts are no longer loaded on pages the plugin does not own, which also saves two requests on every
  ordinary page of the site.

## One secure image downloader
- The Import Wizard used a separate downloader that skipped every check added in 2.13.4. Both paths now share
  Media::is_safe_url(): HTTPS only, real host parsing rather than substring matching, loopback and private
  addresses refused, wp_safe_remote_get, a 10 MB ceiling and a content-type check.

## Template routing
- The city specialist page follows the active pack instead of always loading the health design, with a common
  and then health fallback.

# Business360 2.13.4

Second round of review fixes. Every claim was checked in the code first.

## No invented data anywhere
- city-specialist.php still printed rand(1, 3000) as a review count and rand(900, 999) as views. Both now read
  real meta and the element is hidden when there is nothing to show. This was the last of it.

## Honest wording
- "Verified Business Badge", "Verified Businesses" and "Browse verified listings" are gone from 12 files.
  Nothing claims verification, because nothing is verified yet. Featured and Listed are used instead.

## Styling
- The plugin no longer applies fonts, body or heading styles on pages it does not own. Directory typography is
  handled in exactly one place.
- One canonical Inter definition, matching the font registry.

## Security
- Remote images: exact host matching instead of substring checks, HTTPS only, loopback and private addresses
  refused, wp_safe_remote_get, a 10 MB ceiling and a content-type check before anything is saved.
- The listings endpoint returns published listings by default for everyone. Drafts require edit_others_posts
  and private content additionally requires read_private_posts, so a contributor cannot read other people's data.

# Business360 2.13.3

## Overnight opening hours
- A span that runs past midnight now belongs to the day it starts on, so "Monday 8 PM to 2 AM" reads as open
  at 1 AM on Tuesday. Previously only the current day's row was checked, so late-night venues showed as closed.
- Tested across seven cases: normal hours, overnight spans before and after midnight, 24 hours, and closed days.

## Styling stays in its own lane
- The plugin's typography is applied only on its own pages (listings, location and service pages, the finder
  and the front page), not on every page of the site.
- Directory pages get a gw360-directory body class, and the body and heading rules are scoped to it.
- The site-wide removal of link underlines is gone. Underlines are now only suppressed inside the plugin's own
  containers, so the rest of a site keeps whatever its theme does.

# Business360 2.13.2

Fixes from an external code review of 2.13. All verified in the code before changing anything.

## Presets (the review was right: presets could silently revert)
- Presets wrote hero.style while the settings system reads hero.template, so the hero choice never applied.
- Preset fonts were not in the settings font registry, so saving settings reset the typography. The ten fonts
  the presets use are now registered (Libre Baskerville, IBM Plex Sans, Barlow, Barlow Condensed, Nunito Sans,
  Quicksand, Baloo 2, Rubik, DM Sans, Sora), and presets use the registry's own keys.
- The applied preset and its accent colour are now preserved through a settings save.

## No invented data
- Random view counts (rand(100, 1000)) removed from the tiles and the admin screens. Views come from real data
  or the element is hidden.
- The "4.5" fallback rating is gone. An unrated listing shows no rating rather than a made-up one.

## Permissions
- Importing still needs edit_posts, but publishing (publish, future, private) now also needs publish_posts.
- The public listings endpoint returns published listings only; anything else needs edit_posts.
- Bulk actions check each listing individually with edit_post, and publishing in bulk needs publish_posts.

## Template defects
- The plugin no longer requests pack-health.css, which does not exist; the Tailwind stylesheet loads on its own.
- The three submit-listing templates read the wrong option key (gw360_option instead of gw360_options), so
  premium pricing fell back to hard-coded defaults.

# Business360 2.13.1

## Accuracy
- Articles can no longer claim how long a business has operated or how long someone has practised
  ("has been serving the community for several years"). That is not in the data.
- A reviewer describing a long relationship is now written as evidence about that reviewer
  ("two reviewers describe relationships going back several years"), never as the age of the business.
- Reputation, standing and recognition may only be mentioned when the supplied description claims them,
  and then as the practice's own claim.

## Empty sections
- When no concern is supported by two or more reviews, the concerns list is left out entirely rather than
  announcing that none were found. Lines such as "No specific recurring concerns were noted in the reviews"
  are also stripped at save time, along with any list they emptied.

# Business360 2.13

## Design presets (Settings > Templates)
- Twelve niche presets: Health, Legal, Business & Finance, Home Services, Auto, Wellness & Beauty, Pets,
  Education & Events, Recreation & Seasonal, Retail & Shopping, Gaming & Casino, General Directory.
- One click sets the layout pack, hero style, body and heading fonts, heading scale, palette, accent colour
  and default view. Everything writes to the same style options the Style tab edits.
- The palette is shifted slightly using the site's own domain, so two sites on the same preset do not look
  identical. The shift is small enough that the palette stays right for the niche.
- The accent colour also drives the search finder, tiles and buttons added in 2.7.
- Three layout packs times twelve palettes gives thirty-six distinct looks with no new templates to maintain.

# Business360 2.12

## Articles that quantify instead of waffle
Every article is now written against a block of facts computed from the listing's own data, so it can say
"4 of the 7 reviews mention the front desk, 3 of them positive" instead of "many patients mention the staff".

- Review statistics: how many reviews were analysed, the positive and negative split, the period they cover,
  how many are from the last 12 months, and a count per theme (staff, wait times, how clearly things were
  explained, booking, cleanliness, billing, phone and messages, parking) with a positive/negative split.
- City benchmark: the average rating of the same service in the same city, how far this listing sits from it,
  and how many comparable listings it is rated above. Only shown when at least three others exist, and the
  listing is never compared with itself.
- Availability facts: days open, weekend cover, evenings past 6pm, early starts.
- The prompt now forbids "many", "several" and "some reviewers" where a count is supplied, and requires a
  short section on who the business suits and who it may not, drawn only from the evidence.

## Voice varies by site
Each site derives its own writing cadence from its domain, so pages across a network of directories do not
share one rhythm. The rules change sentence shape only, never the facts.

# Business360 2.11

## Structured data
- Listing schema now includes geo coordinates, areaServed (city and state), hasMap (the Google profile)
  and dateModified, alongside the existing address, phone, hours, image and sameAs.
- Organization and WebSite schema on every page, including the sitelinks SearchAction.
- ItemList schema on city, state, service and area pages, listing the businesses shown.

## Trust signals
- Listing Author setting (Settings > General): imported listings are attributed to a real user.
- Listing pages show "Compiled by <author> - updated <date>", with a rel="author" link and a
  machine-readable date. Freshness and authorship are what health, legal and finance sites are judged on.

## Other
- Imported images are saved as "business-name-city.jpg" instead of Google's CDN id.
- Hub pages get an Open Graph title and, where a listing has a photo, an Open Graph image.
- Page 2 and beyond of a hub page carry their own canonical rather than pointing at page 1.

# Business360 2.10.2

## Internal links inside the article
- The first mention of the city, the service and the state in the article body now link to their hub pages.
  Template links sit outside the post content, so SEO plugins and some crawlers never counted them.
- Each target is linked once, never inside a heading or an existing link, and later mentions are left alone.

## Rank Math
- Rank Math's own schema is switched off per listing at import, since the plugin already outputs
  LocalBusiness, BreadcrumbList and FAQPage. This is why the Schema column reads "Off" and that is correct.

# Business360 2.10.1

## Headings, finally guaranteed
Smaller models ignore the heading instruction no matter how firmly it is worded, so headings are now added
after the article is written, in two stages:
1. A cheap formatting pass asks the model only to insert headings, changing no wording. The result is used
   only if it keeps at least 80% of the original text.
2. If that fails, headings are inserted in code from what each paragraph is actually about (staff, wait
   times, how clearly things are explained, booking, the facility, billing, rating, hours, location).
   The opening paragraph stays unheaded and not a word of the article is changed.

# Business360 2.10

## Listing Photos setting (Settings > General)
- Choose what happens to photos at import:
  - Import photos from Google (default, unchanged behaviour)
  - Import photos, but skip ones that look like profile or user photos (keeps storefront and interior shots,
    skips avatar-sized and contributor images, which are the ones most likely to show an identifiable person)
  - Do not import photos
- Affects new imports only; existing photos stay as they are.
- The middle option is a pattern-based filter, not a guarantee.

# Business360 2.9.3

## Rank Math
- Imports now fill Rank Math's own fields, so listings stop scoring near zero:
  focus keyword ("doctor in austin", from the listing's category and city), SEO title and meta description.
  Anything already set by hand is left alone.

## Article cleanup
- A paragraph ending in a colon that introduces nothing is removed ("Austin Medical Group PLLC is located at:"
  followed by no list). A colon that does introduce a list or heading is kept.

# Business360 2.9.2

## Article quality
- Headings are now required, not suggested: the prompt states that every section must begin with its own
  <h2> and that an article without them is wrong. The existing single retry still catches the rest.
- Em dashes are removed from generated articles. One joining a clause becomes a comma
  ("rushed in some situations, suggesting..."), otherwise a plain dash.
- Doubled punctuation from bold labels is fixed ("Wednesday:: 8 AM" becomes "Wednesday: 8 AM").
- The article no longer repeats what the sidebar already shows: lists of Address, Phone, Website and the
  full week of opening hours are dropped, and hours are summarised in prose instead. Genuine lists such as
  recurring praise and concerns are kept.
- Lead-ins left dangling by those removals ("here are the details you need:") are cleaned up.

# Business360 2.9.1

## Scraper form
- Country, state and city fields now suggest as you type on both the Single and Infinite tabs, including the
  state and city fields the Infinite Scraper adds after the page loads (they were missed in 2.9).
- Suggestions follow the country you enter: US states for United States, Indian states for India, and so on.
- Each city field offers the cities of its own state, so a second state block suggests that state's cities.
- Results are cached in the page, so lists appear instantly after the first lookup.

# Business360 2.9

## Listing SEO
- Meta title and description for every listing, built from its own data:
  "Hill Family Medicine, Austin, TX | Hours, Reviews and Contact" and a description with the rating,
  review count and how many days a week it opens. Rank Math is respected: our values are used only
  where it has none of its own.
- Open Graph and Twitter card tags, including the listing photo.
- BreadcrumbList structured data on listings and location pages, so Google can show the trail.
- FAQPage structured data, built from the questions actually on the page (the article FAQ when present,
  otherwise the template FAQ).
- Duplicate schema removed: listing pages output one business schema, from the plugin, using the
  Listing Schema Type setting. The old template copy also included Google's ratings in aggregateRating,
  which Google's review snippet guidelines do not allow.
- Alt text on imported photos ("<business>, <category> in <city>"), with a one-time backfill for images
  imported before this version.
- Articles without any h2 headings are regenerated once with the requirement restated.

## Hub page content
- City, state, service and service-by-city pages now open with a paragraph of real, computed facts:
  how many listings, the average rating and total reviews, how many are rated 4.5+, how many open at
  weekends or into the evening, and which areas are covered. Nothing is invented and no AI tokens are used.
- Added to all 27 hub templates across the three packs.

# Business360 2.8

## Site Setup (Business360 > Site Setup)
- One click creates the page set a directory site needs, worded for the chosen niche:
  Find page (with the search, service tiles and city tiles already in place), About, Contact,
  How We Rank and Where Our Data Comes From, Editorial Policy, Privacy Policy, Terms, Disclaimer,
  and Claim or Update Your Listing.
- Wording follows the niche: "Find a Doctor" for health, "Find a Lawyer" for legal, "Find a Contractor"
  for home services, and so on, with the right audience word throughout.
- Niche-appropriate disclaimers: no medical advice for health, no legal advice for legal, no financial
  advice for finance, a 21+ and responsible gambling note for gaming.
- Builds a header menu (Home, Find, About, Contact) and a footer menu (the policy and trust pages),
  and assigns them to the theme's menu locations when it can identify them.
- Every page gets a real author, since pages with no author look automated.
- Existing pages are never overwritten unless you tick the box, so hand-written pages survive.
- Safe to run twice: the second run creates nothing and changes nothing.

# Business360 2.7.1

## Fixes
- Titles and addresses are decoded at import, so "Austin &#8211; Shoal Creek" reads "Austin - Shoal Creek".
- Reviews with no text are dropped at import and skipped by the three listing templates, so listings no
  longer show a blank review card with empty stars.
- Prompt: the model must never mention that information is unknown, unavailable or not specified, never end a
  sentence with a colon that leads nowhere, and never comment on days of the week that were not supplied.
- Prompt: every HTML tag must be complete and closed, which stops broken output such as "<h3 Question <p Answer".

# Business360 2.7

## Faceted search and discovery (all niches)
- [business360_search]: filter by service, city, state, rating, "open now", has website, has phone and 15+ reviews,
  with keyword search, sorting (best, highest rated, most reviewed, A to Z, newest), paging and shareable URLs.
- Facet counts update with the filters, so every option shows how many listings it holds.
- Map view (Leaflet + OpenStreetMap) with a marker per listing and popups linking to profiles.
- Coordinates are parsed from the Google Maps URL at import, and existing listings are backfilled once.
- "Open now" is calculated from the stored hours in the site timezone, including hours past midnight.

## Blocks for homepages and hub pages
- [business360_categories] and [business360_cities]: tiles with live listing counts.
- [business360_featured]: featured listings (tick Featured on any listing), topped up with the best rated.
- [business360_links]: footer blocks for popular services, cities and states with counts.
- Docs tab lists every shortcode and its options.

# Business360 2.6

## Locations
- Bundled reference data: 229 countries, 5,308 states and provinces with ISO codes, and 29,738 US cities by state.
  Sources: dr5hn/countries-states-cities-database (ODbL) and kelvins/US-Cities-Database (MIT).
- Imports now normalise locations, so "tx", "TX" and "texas" all become one "Texas" term, "us" becomes
  "United States", and "austin" becomes "Austin". Capitalisation handles McAllen, O'Fallon and Isle of Palms.
- If a city is typed into the state field, the import files it as a city instead of creating a bogus state.
- Scraper forms suggest countries, the states of the chosen country, and the cities of the chosen US state.

## Check and Fix Locations (Business360 > Locations)
- Scans location terms for cities filed as states, states filed as cities, duplicates such as "TX" and "Texas",
  near-duplicates differing only by case or punctuation, and terms with no listings.
- One-click fixes, or Fix all. Listings are moved before any term is deleted.
- When a city is moved out of States, the correct state is taken from each listing's address, so
  Austin, TX and Austin, Minnesota end up in different states.
- Deletions run last and re-check the live count, so a term that just received listings is never removed.

# Business360 2.5.2

## AI safety
- Layered prompts now forbid review analysis when no reviews are supplied. With an empty review block the
  model must write a short factual profile (250 to 400 words) instead of inventing themes, praise or
  concerns. This prevents fabricated "what patients say" sections when the scraper returns no reviews.

# Business360 2.5.1

## Fixes
- Listing pages showed another business's phone number: the "You May Also Like" tiles overwrote the page's
  $phone, $addr, $stars and $reviews variables, so the sidebar Call button, Google Maps link and anything
  rendered after the tiles used the last related listing's data (or vanished when that listing had none).
  All 69 tile and list-item includes across the three packs now run in an isolated scope.
- Website links saved as Google redirects ("/url?q=https://site.com/&opi=...&sa=U...") are unwrapped to the
  real URL at import. Google tracking parameters are removed and missing schemes added.
- One-time repair on the next admin page load: existing listings with Google redirect website links are fixed
  automatically (the number repaired is stored in the gw360_urls_repaired_251 option).

# Business360 2.5

## AI provider
- New Provider setting: OpenAI, DigitalOcean Inference (https://inference.do-ai.run), or any OpenAI-compatible endpoint.
- Model is now a free-text field (any model ID), with suggestions.
- One shared AI client for scraper imports, JSON imports and the Test API button.
- Automatic parameter fallback: if a model rejects penalties/top_p (common with Claude via compatible APIs)
  or max_tokens (OpenAI reasoning models), the request is retried with a smaller parameter set.
- Code fences in model output are stripped.
- Number inputs fixed: max tokens accepts any value (was steps of 10), penalties accept two decimals.

## Layered prompts
- Prompt mode: Layered (core rules + niche rules + category notes) or Custom (the existing prompt box).
  Existing sites stay on Custom until switched, so nothing changes on upgrade.
- 12 niche presets: general, health, legal, finance, home services, auto, wellness, pets, education/events,
  recreation/seasonal, retail/community, gaming. Each sets the audience word, niche rules, review themes and
  closing reminder; all editable, with a Load preset button.
- Category notes: "Category = note" lines, matched against each listing's category, so one site can
  cover several categories with specific guidance.
- Optional FAQ section in AI articles (off by default).

## Prompt preview
- AI Content > Prompt Preview shows the exact prompt for any listing (or the latest one), which niche and
  category note were applied, review count, endpoint, model and approximate tokens, with warnings for
  missing reviews or hours. Nothing is sent to the AI.
- New listings store their original description (gw360_sourceDescription) for previews and regeneration.

## Quality gate (Settings > General)
- Minimum Google reviews, require hours, require phone or website, skip permanently closed.
- Failing listings are skipped, or imported as drafts without an AI article (no token cost).

## Template FAQ toggle (Settings > General)
- Hides the built-in FAQ section on listing pages in all three packs.

## Thin location pages (Settings > General)
- Location archives and service x location pages with fewer than N listings (default 3) get noindex, follow.
  Applied to the plugin's own meta, the service-geo templates, WordPress core robots and Rank Math.
  Pages become indexable automatically when they reach the threshold.

# Business360 2.4.1

## Scraper
- A request timeout (cURL error 28) or a Cloudflare/gateway timeout (504/524) is no longer shown as
  "Scraping Failed". The scraper server keeps running after WordPress stops waiting and posts each
  listing to this site, so the screen now says the scrape is running in the background, with a
  View Listings link. Applies to Single, Bulk and Infinite scraping.
- Docs tab: {{reviews}} description updated.

# Business360 2.4

## AI content
- Fixed: review placeholders. `{{reviews.0.text}}` always rendered blank and `{{reviews}}` rendered "Array".
  Now supported: `{{reviews}}` (up to 10 reviews as "[Review N] text" lines), `{{reviews.0}}`..`{{reviews.9}}`,
  and legacy `{{reviews.0.text}}`. Review HTML is stripped, whitespace collapsed, each review capped at 1,200 chars.
- Fixed: the prompt was sent twice per call (raw template with unrendered {{placeholders}} as the system
  message, rendered copy as the user message). Now: short fixed system message that marks listing data and
  reviews as untrusted, rendered prompt as the user message. Roughly halves prompt tokens.
- REST import and Import Wizard now share one renderer (`GW360\render_ai_prompt`). Wizard AI prompts no longer
  receive `<a>` tags for {{bizWebsite}} / {{googleUrl}}, and hours arrive as "Day: time" lines, not an HTML table.

## Currency
- New Currency setting (General > Premium Plan Pricing). Default USD. Options: USD, CAD, AUD, GBP, EUR, INR, AED.
- Replaced hardcoded "AED" in the three submit-listing templates, the admin payment-plan field, and settings labels.
- Fixed divide-by-zero in "Yearly savings" when monthly price is 0.

## Schema
- New "Listing Schema Type" setting (General). Single listing pages output schema.org LocalBusiness-subtype
  JSON-LD: name, PostalAddress (parsed from US-style addresses, taxonomy fallback), telephone, url, sameAs,
  image, openingHoursSpecification (parsed from Google hours strings).
- Deliberately no aggregateRating/review markup: ratings come from Google, and Google's review snippet
  guidelines do not allow marking up ratings aggregated from other sites.
- Filter `gw360_listing_schema` to adjust output per site.

## Fixes
- pack-health/geo-state.php: stray `endif` caused a PHP parse error (fatal) on Health pack state pages.
- Removed stray "single-listing copy.php" files from the packs.
