Add viator-collector plugin (Hop On Hop Off front-end reskin)

Consolidate the plugin into the TourWebsite repository (its separate
nested git repo has been removed). Includes the full new-design reskin:
scoped design stylesheet, SVG icon sprite, rebuilt listing/single/section
templates, and homepage hero/FAQ/testimonials shortcodes.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J4hNL1PSHxXbu94SCenpKj
This commit is contained in:
2026-09-12 21:11:20 +03:30
parent 99e5413fee
commit 7ada8860f8
42 changed files with 9019 additions and 0 deletions

View File

@@ -0,0 +1,299 @@
# Viator Collector — "Hop On Hop Off" Front-End Re-skin
**Date:** 2026-09-11
**Status:** Design — pending approval
**Author:** Amir Bagheri (with Claude)
## 1. Goal
Replace the entire visual front-end of the `viator-collector` WordPress
plugin with the new "Hop On Hop Off" design that currently exists as a
static mockup in `../new front/`, **without changing any of the plugin's
data model, query logic, or WordPress plumbing**. Every dynamic value
keeps coming from the `viator_tour` post type, its meta, and its
taxonomies exactly as today; only markup, CSS, icons, JS interactions,
and decorative assets change.
## 2. Decisions (locked)
| Question | Decision |
|---|---|
| Surfaces to re-skin | All three: listing/archive, single tour, homepage sections |
| Header / nav / footer | **Content only** — the WordPress theme (e.g. Astra) keeps providing site header/nav/footer. The plugin re-skins only its content area. |
| Listing filter behavior | **Keep server-side** (WP_Query + GET params + server pagination). Only the look changes. No switch to `main.js` client-side filtering. |
| Homepage static chrome | **Include it** — plugin also ships hero/booking, FAQ, and testimonials as shortcodes so the full `index.html` look is achievable. |
| Old CSS/JS | **Replace** — retire `vc-listing.css`, `vc-single.css`, `viator-collector.css`, `vc-sections.css`, and the Lucide dependency. |
## 3. Source of truth
The three canonical mockup pages are:
- `new front/index.html` — homepage (hero+booking, destinations rail, feature/bus section, most-liked tours rail, about, testimonials marquee, articles, FAQ)
- `new front/tours.html` — listing/archive (hero with horizontal filter bar, tour grid, results count, pager)
- `new front/tour.html` — single tour (hero-tour banner, facts, overview, gallery, includes/excludes, good-to-know, cancellation policy, reviews, booking aside)
Driven by `new front/css/style.css` (~3096 lines, token-based) and
`new front/js/main.js` (~419 lines).
**Ignored:** `new front/tourdetailsinfo.html` and
`new front/tourdetailscontent.html` are raw Figma/React export scraps
(absolute-positioned, Tailwind classNames). They are not part of the
design system and will not be used except as visual reference for the
booking aside (already fully expressed in `tour.html`).
## 4. Architecture
### 4.1 Scoping strategy (critical)
Because the plugin renders inside a WordPress theme, the new design's
generic class names (`.container`, `.section`, `.hero`, `.btn`,
`.rating`, `.meta`, `.dcard`, `.footer`, `.site-header`…) and its global
resets (`*`, `html`, `body`, `ul`, `a`, `button`) **must not leak** into
or fight the theme.
Approach:
- Every plugin surface is wrapped in the existing `#vc-app` scope
(already used by `shortcode_listing` and `single-viator_tour.php`).
Homepage section shortcodes get wrapped in `#vc-app` too.
- The ported stylesheet is transformed so **every rule is prefixed with
`#vc-app`** (e.g. `.dcard` → `#vc-app .dcard`). The `:root { --… }`
token block stays global (harmless custom properties).
- Global resets on `*`/`html`/`body` are dropped or converted to scoped
equivalents (`#vc-app`, `#vc-app *`). `scroll-behavior`,
`overflow-x:hidden` on `html`/`body` are dropped (theme's concern).
- Header/nav/footer CSS (`.site-header`, `.nav`, `.burger`, `.footer`,
`.skip-link`) from the mockup is **not** ported — the theme owns those.
Exception: the `.footer` "back to top" ring-badge is a reusable widget
we may keep for section use; TBD, default = drop.
### 4.2 Asset organization
New plugin asset layout:
```
viator-collector/assets/
css/
vc-design.css # ported + scoped style.css (single stylesheet)
js/
vc-frontend.js # existing server-side filter behaviors (kept, trimmed)
vc-design.js # ported interactions: rails, accordion, marquee, ring-badge
img/
(decorative design assets copied from new front/assets: bus-iso.png,
bus-open-top.png, tower.png, ellipse-17.png, ellipse-17-2.png,
hero.png, hero2.png, hero3.jpg)
icons/
sprite.svg # the <symbol> icon set + #ringPathScroll path def
```
- **Decorative** images (bus, tower, ellipses, hero backdrops) ship with
the plugin — they are chrome, not tour data.
- **Demo tour images** (`city-*.png`, `liked-*.png`, `tour-*.png`) are
NOT shipped; those slots are filled by real tour data
(`_vc_primary_image_url`, gallery URLs) via `vc_tour_image_html()`.
### 4.3 Icons
The mockup uses an inline SVG sprite: a hidden `<svg class="sprite">`
holding `<symbol id="i-…">` defs, referenced by
`<svg class="icon"><use href="#i-…"></svg>`. It also defines
`#ringPathScroll` (the circular text path for the "BOOK NOW" badge).
- Ship the sprite as `assets/icons/sprite.svg` and print it once per
plugin page via a small helper (`vc_print_icon_sprite()`), guarded so
it prints at most once.
- Add a helper `vc_icon( $name )` returning
`<svg class="icon"><use href="#i-$name"></svg>`.
- Replace all current `<i data-lucide="…">` usages with `vc_icon()`.
Lucide enqueue is removed.
Icon name mapping (Lucide → sprite):
| Lucide | Sprite |
|---|---|
| map-pin | i-location |
| clock | i-duration |
| users / user | i-person / i-user |
| shield-check | i-shield-check |
| calendar-check | i-calendar |
| rotate-ccw | i-duration (or reuse) |
| clipboard-list | i-grid |
| images | i-grid |
| star (rating) | i-star |
(Exact per-call mapping finalized during implementation; any missing
glyph is added to the sprite.)
### 4.4 JavaScript
`vc-design.js` (new) ports from `main.js` only what our content uses:
- **Card rails** — `.rail` horizontal scroll with `[data-rail-prev/next]`
buttons (used by homepage destination/tour rails).
- **FAQ accordion** — `[data-accordion]` / `.acc__q`.
- **Testimonials marquee** — `[data-marquee]` duplicate-for-loop.
- **Ring-badge** — the rotating "BOOK NOW" SVG textPath (needs
`#ringPathScroll` in the sprite; animation is CSS).
- Hero booking/availability form `preventDefault` demo handlers become
real submits to the tour's booking URL / listing action (no console
stubs).
**Explicitly NOT ported:** `main.js` client-side listing filter/sort/
pager (server-side stays), and header/nav/burger/sticky-header (theme's).
`vc-frontend.js` is kept for the server-side listing behaviors it already
provides (auto-submit selects/checks, filter drawer on mobile). The
noUiSlider price slider is **removed** — the new design uses a Price
Range `<select>`, which the existing `get_filter_state()` already parses.
### 4.5 Enqueue changes (`class-vc-display.php::enqueue_assets`)
- Remove: Lucide, noUiSlider (css+js), `vc-listing.css`, `vc-single.css`,
`viator-collector.css`.
- Add: Google Fonts "Plus Jakarta Sans"; `vc-design.css`; `vc-design.js`.
- Keep: `vc-frontend.js` (trimmed).
- Gating logic (single vs archive vs shortcode page) stays as-is.
## 5. Surface-by-surface mapping
### 5.1 Listing / archive — `templates/listing.php` + `templates/card-tour.php`
Target markup: `new front/tours.html`.
- **Hero** → `section.hero.hero--archive` with eyebrow pill, `h1`, and the
horizontal **filter bar** `form.filters` (submits GET to the same
action as today). Replaces the old sidebar + noUiSlider layout.
- Search input → `vc_q`
- Destination `<select>` → `dest[]` (single value)
- Category `<select>` → `cat[]`
- Price Range `<select>` → `price` (values like `0-50`, `50-150`,
`150-1000`; already parsed by `get_filter_state()`)
- Duration `<select>` → `dur[]` buckets (`half`/`full`/`multi`, labeled
Half Day / Full Day / Multi-Day — adapted from the mockup's day
options to the plugin's real buckets)
- "Apply Filters" submit button
- Checkbox row (`filters__bar`): Free Cancellation → `freecancel`,
Best Deal → `bestdeal`, Likely to Sell Out → `sellout`
- A sort control (styled to the design) → `sort`
- **Results head** → `.results` with `#resultCount` ("Showing X–Y of Z
tours", server values) and a "Clear filters" link when filters active.
- **Grid** → `ul.tgrid` of `li.titem > article.dcard.dcard--wide` cards
(see 5.2). Active-filter chips retained, restyled.
- **Pager** → custom server-rendered pager matching `.pager` /
`.pager__num` design (replaces `paginate_links` default markup and the
JS pager). Preserves current query string.
- Empty state → styled "no tours" message.
### 5.2 Tour card — `templates/card-tour.php`
Target: the `.dcard--wide` card in `tours.html` (and the rail `.dcard`
in `index.html` for homepage rails — one template, optional modifier).
Fields → design slots:
| Design slot | Data source |
|---|---|
| `.dcard__img` | `vc_tour_image_html()` (real image) |
| `.rating` pill (`<b>4.0</b>/5` + star) | `_vc_rating` |
| `.dcard__title` | `get_the_title()` |
| meta "Start at" `$xx` | `_vc_price_from` + `_vc_currency` via `vc_money()` |
| meta "Duration" | `_vc_duration_text` / `vc_duration_human()` |
| ring "BOOK NOW" badge link | permalink |
| `.titem__desc` (listing only) | excerpt |
| card badge (Best Deal / Sell-out) | `vc_card_badge()` |
| destination line (if kept) | `viator_destination` term |
The card must render correctly both as a listing `li.titem` and as a
homepage rail `li.dcard`; a `$variant` arg selects wrapper/markup.
### 5.3 Single tour — `templates/single-viator_tour.php`
Target: `new front/tour.html`.
- **Hero-tour banner** → `section.hero-tour` with `hero-tour__photo`
(primary image), `hero-tour__kicker` ("Welcome to"), `hero-tour__word`
(destination/title), decorative `hero-tour__figure` (`tower.png`,
decorative asset). Breadcrumb retained.
- **Layout** → `.container.tour__layout` = `.tour__main` + `aside.tour__aside`.
- **Head** → `.tour-head__title` + `.tmeta` (rating, location, supplier).
- **Facts** → `ul.facts` of `li.fact` (Duration, Max Travelers, Free
Cancellation, Category) from `_vc_duration_minutes`,
`_vc_max_travelers`, `_vc_free_cancellation`, `viator_tag`.
- **Overview** → `section.tour__block` with `the_content()`.
- **Gallery** → `.gallery` (hero + thumbs) from `_vc_gallery_image_urls`.
- **Includes / Excludes** → `.lists` of `.ilist` with `.tick--yes/--no`
from `_vc_inclusions` / `_vc_exclusions`.
- **Good to know** → `tour__block` from `_vc_additional_info`.
- **Cancellation policy** → `.policy` of `.statcard--yes/--no` refund
tiers from `_vc_cancellation_policy`.
- **Reviews** → restyled summary from `_vc_rating` / `_vc_review_count`.
- **Booking aside** → `.bookcard`: From/price (`_vc_price_from`),
"Check Availability" → `_vc_booking_url`, `statcard--teal` Free
Cancellation + `statcard--yes` Reserve-now cards.
- **Mobile book bar** retained, restyled.
### 5.4 Homepage sections — `class-vc-sections.php` / `class-vc-display.php` shortcodes
Existing data shortcodes are re-skinned; new static-chrome shortcodes are
added.
Re-skinned (data-driven):
- `viator_top_destinations` → "Where you wanna go?" section: `sec-head`
(title + lead + See-all + `rail-nav` prev/next) over a
`ul.rail.rail--dest` of `.dcard`s. (`card-destination.php`)
- `viator_top_tours` → "Most Liked Tours" rail (same rail pattern,
`card-tour.php` in `dcard` variant).
- `viator_top_attractions` → the feature / "bus-tours" section styling.
- `viator_browse_activities` → activity section styling.
New (static chrome, per decision — full `index.html` look):
- `viator_hero` → the homepage hero + booking form
(`section.hero` + `form.booking` with Location/Date/Seats). Location
select is populated from `viator_destination` terms; submit routes to
the listing archive with the chosen filters (real behavior, not a
console stub).
- `viator_faq` → `section.faq` accordion (`[data-accordion]`). Content
supplied via shortcode attributes / inner content or a simple options
list (final content source TBD in plan).
- `viator_testimonials` → `section.testimonials` marquee
(`[data-marquee]`). Content via shortcode attributes/inner content.
The About and Articles sections from `index.html` are ordinary editorial
content; they are **not** plugin shortcodes (the user builds them with
the theme/builder). Noted here to bound scope.
## 6. Out of scope
- Site header, primary nav, burger menu, sticky header, site footer
(theme-owned).
- Any change to importing, cron, API, CPT/taxonomy registration, meta
keys, or query/filter logic.
- Client-side filtering/sorting/pagination (server-side retained).
- About / Articles homepage sections as plugin features.
## 7. Risks & mitigations
- **Style leakage / theme conflicts** → strict `#vc-app` scoping; drop
global resets; no header/footer CSS. Verify against Astra.
- **Generic class collisions** (`.container`, `.btn`, `.hero`) → all
scoped under `#vc-app`; test with theme active.
- **Duration option mismatch** (mockup "1/3/7 days" vs plugin
half/full/multi buckets) → use the plugin's real buckets with mockup
styling.
- **Icon coverage** → any glyph used by a template but missing from the
sprite is added to `sprite.svg`.
- **Ring-badge dependency** → ensure `#ringPathScroll` path def is in the
sprite so the rotating badge renders.
## 8. Acceptance criteria
- Listing, single, and homepage sections visually match the mockup within
the plugin's content area, with the theme's header/footer around them.
- All dynamic values render from real tour data; no demo images/text ship
as content.
- Server-side filtering, sorting, and pagination work via GET params as
before; shareable URLs preserved.
- No new console errors; Lucide and noUiSlider no longer loaded.
- No style bleed into the theme outside `#vc-app` (verified with Astra).