Skip to main content

Locations

5 min read

Locations

Shared across every PremiumPress product. 3 classes in inc/Locations.

CountryTax CountryTax.php​

Country as a real taxonomy — what makes "browse by country" work. A listing's country has always been free-text meta (country, written by the listing editor, the importer, the API and the demo seeder alike). Free text cannot be browsed: it has no archive, no count, and "UK" / "Great Britain" / "England" are three different countries as far as a query is concerned. So this service mirrors that meta onto a listing_country term, normalised through Content\Countries first. THE META STAYS THE SOURCE OF TRUTH. Everything that already writes country keeps working untouched — no fork's ListingEditor, listing-form.php or importer needed a line changed — because the sync hangs off the meta hooks, which every one of those paths goes through. That is deliberate: the country field is cloned into 17 fork editors and 15 form views, and editing all 32 to add a term picker would be 32 chances to get it wrong. The taxonomy metabox is therefore hidden from the post editor (meta_box_cb => false) so there is exactly ONE place a country is set. Terms are created LAZILY: on the first save that mentions a country, and on the first visit to a country's archive. There is no 197-term seed — an install's term table only ever holds the countries it actually uses or someone has browsed to. Registered only where ThemeProfiles::supportsMaps() — the location-driven product lines. A stock-photo, software or coupon site has no country archives at all. NOT in Ppt\Directory\ on purpose. Theme::boot() drops EVERY Ppt\Directory* service the moment a fork owns the profile, so a class living there would exist on the base Directory site and nowhere else — silently absent on the other fourteen product lines. Shared subsystems that every fork needs get their own namespace (the same reason Stories, Bookings and Compare have theirs).

API
available()register()backfill()taxonomy()url()slug()counts()onMetaWrite()onMetaDelete()sync()termId()ensureRequestedTerm()robots()filterFacetTerms()
inc/Locations/CountryTax.php

LocationTax LocationTax.php​

Locations as a real, nested taxonomy — Country > City > Area — with clean URLs: /gb/ United Kingdom /gb/london/ London /gb/london/mayfair/ Mayfair /us/new-york/ New York Why it exists: a listing's town has always been free-text meta (city), browsed through a ?s&near=London search. That gives no real page per place — nothing Google can index, nowhere for an owner to write about the area, and a URL nobody would share. CountryTax made countries browsable; this makes the whole path browsable. THE META STAYS THE SOURCE OF TRUTH — the same rule CountryTax lives by, for the same reason. country, city and the new district meta are written by 23 fork editors, the importer, REST and the demo seeder; the sync hangs off the meta hooks every one of those paths goes through, so none of them needed to learn about terms. The taxonomy's post-editor metabox is hidden so there is exactly one place a location is set. Terms are created LAZILY, on the first save that mentions a place. A listing is filed under its DEEPEST term only (Mayfair, not Mayfair + London + UK); a hierarchical taxonomy query includes children by default, so /gb/london/ still lists Mayfair. URLs are built from each term's own path segment (term meta ppt_loc_seg): the ISO alpha-2 code for a country, sanitize_title(name) below that. Not from the term slug — slugs are unique per taxonomy, so a second "Birmingham" (US) would get birmingham-united-states and leak that into its URL. Segments are only unique among siblings, which is all a path needs. Root-level country codes and conflicts: /gb/ is only claimed when nothing else on the site already answers there (a page or post called "gb", a post type / taxonomy base, or another rewrite rule). A conflicting country falls back to /location/gb/…, and the admin is told which ones. Only countries actually in use get a rule, so the site never claims 200 two-letter paths it has no content for. Registered only where ThemeProfiles::supportsMaps() — the location-driven product lines, exactly like CountryTax.

API
available()register()taxonomy()queryVars()rewrites()invalidate()onTermMeta()onPostDeleted()onRulesFlushed()conflicts()countrySegments()parseRequest()termFromPath()seg()termLink()url()redirects()termByName()total()busiest()onMetaWrite()onMetaDelete()sync()urlCode()
inc/Locations/LocationTax.php

SearchCountries SearchCountries.php​

The country lock — confine a site to the countries it actually trades in. A directory serving one country still searches the whole planet: type "Springfield" and the geocoder offers five of them, ask for anything within 25km of Detroit and Windsor, Ontario comes back with it. This narrows both halves of that problem from ONE setting (Settings ▸ Maps ▸ "Search countries"), because they are two different problems and fixing either alone leaves the site still wrong: 1. GEOCODING. Every provider can be told which countries to resolve in — Mapbox country=, Google components=country:, Nominatim countrycodes=. Without this the location box can centre the search on a place the site does not cover. 2. RESULTS. Restricting the geocoder does nothing for a search with no location in it at all (a keyword, a category, a bare archive), and nothing for a radius that reaches over a border. So the listing query is ANDed with a listing_country clause as well — see lockQuery(). LISTINGS WITH NO COUNTRY ARE KEPT. The clause is "an allowed country, OR no country term at all". country is free-text meta that plenty of paths never write (older imports, the API, some demo seeds), and CountryTax only mirrors what it is given — so a strict IN clause would empty the search results of any site whose catalogue predates the taxonomy. Keeping them is the conservative half of a trade: a genuinely foreign listing that was never geocoded stays visible until its country is filled in. Sites that would rather be strict can say so: add_filter('ppt_country_lock_untagged', '__return_false'); NOT in Ppt\Directory\ for the reason CountryTax spells out at length: Theme::boot() drops every Ppt\Directory* service the moment a fork owns the profile, so a class living there would be silently absent on fifteen product lines. It sits beside the taxonomy it queries.

API
register()available()codes()active()names()cacheKey()providerParam()lockQuery()taxLock()slugs()
inc/Locations/SearchCountries.php