Overview#
Wander is a site for a small-group tour company, built as a WordPress block theme. The fictional
brand is Saltwind Journeys, a travel company on Bristol's harbourside that runs trips of twelve
travellers or fewer in Morocco, Peru, Norway, the Aegean, Japan and Tanzania. The theme has a home
page with a trip finder, featured tours, regions, traveller postcards and a newsletter; a tours page
you can filter by region, style, duration, month and budget; tour pages with a day-by-day
itinerary, an illustrated route map, departure dates and a booking widget with a live-priced
enquiry; a destinations page with a month-by-month seasonality chart; a journal with a topic filter
and an article; an about page; a contact page with an FAQ; and a 404 page. It is version 1.0.0 (see
template.json and style.css), works with WordPress 7.1 and PHP 7.4 or newer, and is the
WordPress version of the HTML template of the same name. See it live at
freeframe.dev/templates/wander.
The pages (headings, copy, region cards, reviews, the journal, the about and contact pages, buttons)
are core WordPress blocks arranged in block patterns, so you edit them in the block editor without
touching code. The tours work as in the HTML version: the twelve trips and six regions are lists in
assets/js/main.js, and the script draws the tour cards, the filters' results, the tour page, the
departure dates, the prices and the seasonality chart from them. There are no photos: every
landscape, route map and portrait is an SVG illustration drawn by the same script. Colours and fonts
are design tokens in theme.json: change them in Appearance > Editor > Styles and the whole site
follows.
Quick start#
Requirements: WordPress 7.1 or newer and PHP 7.4 or newer. No plugins are needed.
- Download
wander.zipfrom freeframe.dev/templates/wander (the WordPress tab). - In your WordPress admin go to Appearance > Themes > Add New Theme > Upload Theme, choose the zip and click Install Now, then Activate. The theme is listed as Freeframe Wander.
- Go to Appearance > Wander setup and click Create the demo pages. This creates the Home, Tours, Tour, Destinations, Journal, Article (Walking the High Atlas), About and Contact pages from the theme's page patterns, sets Home as the front page (Settings > Reading) and creates the header menu. Pages that already exist with the same slug are left alone, so it is safe to click it again.
- In Settings > General, the demo uses "Saltwind" as the Site Title and "Journeys · Bristol" as the Tagline: the header shows both next to the logo. Set your own.
- Visit your site. Edit any page in Pages, and the header, footer and templates in Appearance > Editor.
You can also try the theme without installing anything: the Try it in WordPress button on freeframe.dev opens it in WordPress Playground (WordPress running in your browser) with the demo pages already set up.
To work on the theme's files locally you need Node.js 24 and pnpm; WordPress itself runs in WordPress Playground, so there is no PHP, web server or database to install:
pnpm install
pnpm dev # builds the CSS, then starts WordPress with the theme at http://127.0.0.1:9400pnpm dev signs you in as admin (password password) and creates the demo pages. The site is
rebuilt from scratch every time you start it; your edits to theme files are live, edits made in the
WordPress admin are not kept.
Pages#
Each page is a page pattern (in Patterns > Wander pages) made of section patterns. Every section is also offered on its own in the block inserter under Patterns > Wander.
| Page | Slug | Page pattern | Sections (pattern files in patterns/) |
|---|---|---|---|
| Home | / |
page-home.php |
home-hero (postcards and stamp), trip-finder, ticker, featured-tours (tour cards), why-travel, regions (destination cards), reviews, journal-teaser, newsletter |
| Tours | /tours/ |
page-tours.php |
tours-header, tours-results (filters, sort, chips and tour grid), private-trip-cta |
| Tour | /tour/?id=atlas-sahara |
page-tour.php |
tour-hero (key facts and price), tour-details (highlights, itinerary, route, included, dates, booking widget, enquiry), tour-related, tour-mobile-bar |
| Destinations | /destinations/ |
page-destinations.php |
destinations-hero, seasonality (the year at a glance), region-morocco, region-andes, region-nordics, region-aegean, region-japan, region-africa, when-to-go-cta |
| Journal | /journal/ |
page-journal.php |
journal-header, journal-feature, journal-stories (topic filter and story cards), journal-cta |
| Article | /article/ |
page-article.php |
article-progress (reading progress bar), article-body (header, contents and story), article-trips |
| About | /about/ |
page-about.php |
about-hero, about-numbers, about-story (timeline), guides, responsible (commitments and where your money goes), about-cta |
| Contact | /contact/ |
page-contact.php |
contact-header, contact-form (form, office and emergency line), faq |
| 404 | any missing URL | templates/404.html |
404 |
The script finds the tours, tour and contact pages by their slugs (tours, tour, contact): if
you rename one, change its URL in freeframe_wander_page_urls() in inc/setup.php too. Posts use
templates/single.html; the blog, archives and search results use templates/index.html,
templates/archive.html and templates/search.html.
Project structure#
freeframe-wander/
style.css theme header (name, version, requirements, license); no styles
theme.json design tokens: palette, fonts, font sizes, spacing, layout widths, button
functions.php loads the files in inc/
inc/setup.php stylesheet and script (with its strings and page URLs), editor styles,
the `js` class script, pattern categories
inc/icons.php registers assets/icons/*.svg for the Icon block
inc/icon-labels.php the icons' names shown in the editor
inc/block-styles.php button block style
inc/site-setup.php Appearance > Wander setup: creates the demo pages and the menu
templates/ page.html (pages), page-with-title.html, single.html, index.html,
archive.html, search.html, 404.html
parts/ header.html and footer.html (they show the header and footer patterns)
patterns/ every section and page (PHP files with block markup)
assets/css/theme.css the compiled stylesheet (do not edit: built from src/)
assets/css/editor.css the same for the block editor (generated by src/editor-css.mjs)
assets/js/main.js tours and regions, illustrations, filters, tour page, booking, forms
assets/icons/ SVG icons for the Icon block
assets/img/ logo, favicon, social image
assets/fonts/ Caprasimo, Outfit and Kalam, with their licenses
src/theme.css the Tailwind CSS source of assets/css/theme.css
src/icons.css icons drawn before or after text with CSS (generated)
src/editor-css.mjs writes assets/css/editor.css after each build
languages/ freeframe-wander.pot, the template for translations
blueprint.json WordPress Playground setup used by `pnpm dev`
screenshot.png the picture shown in Appearance > Themes
package.json the CSS build and the local WordPress (Node.js tooling)
readme.txt, README.md, DOCS.md, CHANGELOG.md, LICENSE.txtCustomising#
Brand and colours#
The colours are in theme.json (settings.color.palette) and in Appearance > Editor > Styles >
Colors > Palette:
| Colour | Default | Used for |
|---|---|---|
| Paper | #fbf5ea |
the page background |
| Postcard | #fffaf1 |
cards, form fields, stamps |
| Sand, Dune | #f4e6cc, #ecd5ad |
panels, chart cells |
| Line | #e2cfae |
borders and dashed rules |
| Ink | #23180f |
text, outlines and the offset card shadows |
| Muted | #66523f |
secondary text |
| Clay, Clay dark | #b0431d, #8c3214 |
the brand: primary buttons, links, eyebrows |
| Sun, Sun deep | #f4a62a, #b86e00 |
stamps, the ticker, highlights; stars and icons |
| Sea, Deep | #0e5a5f, #0a3b3f |
dark bands, "best" season, the footer |
| Lagoon, Coral | #7cc4b8, #ef7b5a |
decoration and charts |
| Foam | #fff9ef |
text on dark backgrounds |
| White, Black | for your own blocks |
The theme's stylesheet reads these colours from the palette (bg-clay, text-muted...), so
changing Clay in Styles recolours every button and link at once. A few colours are written directly
into SVG: the landscape palettes (SKIES and LAYERS) and the route map pins in
assets/js/main.js, the logo (assets/img/logo.svg), the 404 compass and the favicon.
Typography#
Three fonts are bundled in assets/fonts/ and declared in theme.json
(settings.typography.fontFamilies), so no request goes to Google: Caprasimo (preset display)
for headings, prices and stamps, Outfit (variable, 300 to 700; preset sans) for text, and
Kalam (400 and 700; preset hand) for the handwritten postcard notes (the hand class).
Caprasimo has a single weight, so headings use font-normal. To use other fonts, install them in
Styles > Typography > Fonts (the Font Library) and select them, or replace the fontFace
entries in theme.json. The utility classes read the presets (--wp--preset--font-family--display,
--sans, --hand), so keep those slugs. The route map labels and the postmarks name Outfit
directly (font-family="Outfit, sans-serif").
Font sizes are the presets in theme.json (xs 0.75rem to 9xl 8rem, the Tailwind scale).
Content#
Edit pages in Pages: click any text to change it, select a button to change its link. Sections are groups; open List View (the stacked lines icon at the top left) to select a section, move it, duplicate it or delete it. To add a section from another page, use the block inserter (+) > Patterns > Wander.
What the script draws or fills is in Custom HTML blocks: edit those in the block's HTML view, and
keep their ids and data- attributes.
| Pattern | Custom HTML | What it is |
|---|---|---|
| most sections | <div class="art-frame …" data-art="dunes" data-time="dusk">, <span … data-avatar="…"> |
landscapes and portraits, see Images and artwork |
home-hero, newsletter, about-hero, contact-form, 404 |
the postmarks and the compass | decorative SVG |
trip-finder |
the finder form | see Trip finder |
ticker |
the scrolling place names | hidden from screen readers (decoration) |
featured-tours, tour-related, article-trips |
the tour grid (data-featured-tours, data-related, data-tour-list="toubkal-trek,atlas-sahara,inca-trail") |
tour cards from the tour list |
tours-results |
the filters and the results (count, sort, chips, grid, empty state) | see Tour filters |
tour-hero, tour-details, tour-mobile-bar |
the breadcrumb, rating, artwork, highlights, itinerary, map, included lists, dates table, booking widget, enquiry form and price bar | see Tour page |
seasonality, region-* |
the legend, the table and each region's chart (data-season="morocco") |
see Seasonality |
journal-stories |
the topic buttons and the status line | see Journal filter |
responsible |
the "where your money goes" bar and its legend | an illustration with a text alternative |
| all pages | breadcrumbs, forms and their success messages | see Forms |
header, footer |
the menu button, the footer wave and the toast | driven by the script |
A few blocks carry a class (Block settings > Advanced > Additional CSS class(es)) that the script or stylesheet reads:
ffd-<name>--<value>is turned into the attributedata-<name>="<value>"when the page loads (blocks can't store data attributes):ffd-tour--nameon the tour page's heading marks it to be filled with the tour's name,ffd-topic--foodfiles a journal story under Food,ffd-region-count--moroccoshows a region's number of trips ("2 trips").revealfades a block in as it scrolls into view.link-cardon a group makes the whole group clickable: the first link inside it stretches over the group (the region cards on the home page, the logo).stampandstamp-innerdraw the perforated postage stamp;airmailthe striped airmail border;eyebrowthe small clay heading with a dash;displaythe Caprasimo headline style;handthe handwritten font.
The tour list
Tours are the TOURS list in section 1 of assets/js/main.js. Each tour looks like this:
{
id: 'dolomites-huts', name: 'Dolomites Hut to Hut', region: 'alps', country: 'Italy', style: 'hiking',
days: 8, price: 2290, single: 280, rating: 4.8, reviews: 0, group: 12, level: 'Moderate', badge: 'New',
months: [6, 7, 8, 9], scene: 'mountains', time: 'day', featured: 0,
summary: 'Seven days between mountain huts, with your bags sent ahead.',
highlights: ['Tre Cime at sunrise', 'Nights in family-run huts', 'Via ferrata taster'],
includes: ['Hut-to-hut luggage transfers'], excludes: [],
stops: [[20, 70, 'Cortina'], [45, 45, 'Tre Cime'], [75, 30, 'Sesto']],
itinerary: [
{ d: '1', t: 'Cortina', x: 'Meet the group and walk to the first hut.', stay: 'Rifugio Lago' },
{ d: '2–7', t: 'Hut to hut', x: 'Six days on high trails.', stay: 'Mountain huts' },
{ d: '8', t: 'Departure', x: 'Transfers to Venice airport.', stay: '' }
]
}| Field | Notes |
|---|---|
id |
Unique, lower case, used in /tour/?id=… and /contact/?tour=… (any letter case) |
region, style |
The id of a REGIONS and a STYLES entry: the tour then appears under those filters. A new region also needs a checkbox in the filters (the Custom HTML of tours-results: copy a <label class="pill-check"> and change value and data-count-for), an option in the trip finder, and a region section on the destinations page if you want one |
price, single |
The lowest price per person and the own-room supplement per person, in pounds |
months |
The months (1–12) the tour departs: they drive the month filter and the departure dates |
scene, time |
The card and hero artwork (see Images and artwork) |
stops |
Route map points [x, y, name], x and y as percentages of the map's width and height |
itinerary |
Accordion rows: d the day or range, t the title, x the text, stay the overnight (empty hides it) |
featured |
1 to 4 puts the tour on the home page in that order and first in "Recommended" sort |
badge |
Optional label on the card |
The other settings sit next to the list: REGIONS (with each region's season), STYLES,
DURATIONS, INCLUDED and EXCLUDED (lines on every tour page), PRICE_MIN and PRICE_MAX (the
budget slider), PEAK_SUPPLEMENT (£150), DEPOSIT (£300 per person), MAX_TRAVELLERS (8),
BOOKING_CUTOFF (21 days) and DEPARTURE_DAYS. Prices are formatted as pounds with
toLocaleString('en-GB') and dates with Intl.DateTimeFormat('en-GB'); change money(), fmtShort
and fmtLong for another currency or locale. The tour page's blocks contain Atlas to the Sahara as
default text; the script replaces it with the tour from the URL.
Edit assets/js/main.js in a child theme (copy it there and load it instead), or your tours are
overwritten when you update the theme. Tour names, summaries and itineraries are data, not
translatable strings.
Images and artwork#
There are no photos. Every landscape is an SVG drawn by art(scene, time, label) in
assets/js/main.js. Scenes are dunes, mountains, fjord (with northern lights at night),
coast, fuji and savannah; times are dawn, day, dusk and night. Place one anywhere with
a Custom HTML block (add data-label to give it alt text; without it the art is decorative):
<div class="art-frame aspect-[4/3] rounded-[2rem]" data-art="coast" data-time="dusk" data-label="Sunset over Milos"></div>The art is cropped to fit its frame, so any aspect ratio works. To use a photo instead, replace the
Custom HTML block with an Image block (cards and region sections are 4:3, the tour hero 21:9 on
desktop), or return an <img> from art(). The art-frame class adds a subtle paper grain over
whatever is inside. routeMap(tour) draws the tour page map from stops, and avatar(spec) the
guide and traveller portraits for elements with data-avatar="skin,hair,style,background" (style
is short, long, bun, curly or bald). In the editor the frames are empty: the script draws
them on the site.
The logo is assets/img/logo.svg in an Image block next to the Site Title and Site
Tagline blocks in the header (the title alone in the footer); the words come from Settings >
General. Icons are Icon blocks: select one and pick another from the Wander collection or
WordPress's own. The social image is assets/img/og-image.png (1200 × 630, source og-image.svg);
the favicon assets/img/favicon.svg is used until you set a Site Icon in Settings > General.
Navigation, header and footer#
The header and footer are template parts (parts/header.html, parts/footer.html) showing the
header and footer patterns. Edit them in Appearance > Editor > Patterns > Header / Footer.
The header pattern starts with the announcement bar ("Next season's departures are open").
The header has two Navigation blocks showing the same menu: the desktop one and the one in the
mobile menu. Edit the menu once in Appearance > Editor > Navigation (the setup creates "Main
menu"). Its first link (Home) is hidden in the desktop header, as in the HTML version; keep Home
first, or remove the .site-nav … :first-child rule in src/theme.css. A Navigation block that
doesn't point at a menu shows the most recently created one; to pin a menu, select the Navigation
block and choose it in the block settings, for both blocks.
The footer's Trips and Saltwind menus and the bottom links are List blocks: click a link to change
it, press Enter to add one. The Instagram, booking conditions and privacy links point to #;
replace them with your own pages.
Features#
Trip finder#
initFinder(). The form #trip-finder on the home page (the trip-finder pattern) has four
selects (region, month, style, duration). On submit it opens the tours page with only the
chosen values as URL parameters, for example /tours/?region=japan&month=4. Without JavaScript the
form still submits to the tours page.
Tour filters#
initTours() on the tours page. The form #tour-filters has checkboxes named region, style and
duration (several in one group combine with OR, groups combine with AND), a month select and a
max budget slider. #sort orders by recommended, price, length or rating (SORTS). Every change
re-renders #tour-grid, updates the live count #result-count, the removable chips in
#active-filters and the small count next to each option (how many trips you'd see if you ticked
it), and writes the state to the URL:
/tours/?region=morocco,japan&style=hiking&duration=medium&month=5&max=3000&sort=price-ascNames and values are case-insensitive, lists can be comma-separated or repeated, and unknown values
are ignored, so filtered views can be linked (the footer's "Hiking & trekking" link is
/tours/?style=hiking). When nothing matches, #tour-empty appears with a reset button. On phones
the filters are behind #filters-toggle (aria-expanded), with a badge showing how many are active.
When a month is chosen, card links carry it (/tour/?id=…&month=5) so the tour page preselects a
departure in that month.
Tour page#
initTourPage(). /tour/?id=lofoten-peaks shows that tour (any letter case); a missing or unknown id
shows the first tour. The browser tab title, the blocks marked ffd-tour--name (and summary,
days, price, rating, reviews, level, group, region, country, style, single), the
hero art, highlights, included and excluded lists, route map and related tours are filled from the
data. The itinerary is a list of buttons with aria-expanded; the first day starts open and
"Expand all days" opens or closes every day.
Departures and prices#
departures(tour, limit) works out the next eight departures: in each month in tour.months, a
departure leaves on the first Saturday on or after each day in DEPARTURE_DAYS, skipping any sooner
than BOOKING_CUTOFF days from today. Months rated 3 ("best") in the region's season cost
PEAK_SUPPLEMENT more and are marked "Peak". Places left are demo data from a stable hash of the tour
and date, so they are the same on every visit: 0 shows "Full", 1–3 "Only N left", and a departure
with four or more travellers booked shows "Guaranteed". Replace departures() with your real dates
if you have them; the table and widget only need objects of the form
{ start, end, month, price, peak, left, guaranteed }.
Booking widget and enquiry#
The #booking-widget card has a departure select (#dep-select), a travellers stepper (1 to
MAX_TRAVELLERS, never more than the places left) and a room choice. quote() returns the price per
person, the own-room supplement, the total and the deposit, shown live in an aria-live list.
"Choose" buttons in the dates table select a departure. The current choice is written to the summary
above the enquiry form and to its hidden fields (tour, departure, travellers, room, total),
so a connected form receives everything. On phones a fixed bar at the bottom shows the total.
?date=YYYY-MM-DD, ?month=5 and ?travellers=3 preselect choices.
Seasonality#
initSeasons() on the destinations page builds the #season-table table (a row per region, a cell
per month, each with a screen-reader label such as "April: Best") and fills each
[data-season="<region id>"] element with a 12-bar chart and the list of best months, all from
REGIONS[].season. Levels are 0 (avoid), 1 (possible), 2 (good) and 3 (best). The table scrolls
sideways on small screens with the region names kept in view.
Journal filter#
initJournal(). The topic buttons (data-topic-btn, with aria-pressed) show only the story cards
whose topic matches; #journal-status announces the result and the URL keeps ?topic=. To add a
story, duplicate a story card in List View and change its class ffd-topic--<topic> to one of
guides, stories, food or practical.
Scroll reveal, ticker, progress and back to top#
Blocks with the reveal class fade in when scrolled into view. The home page ticker scrolls with CSS
and pauses on hover; the hero stamp floats (float). On the article page the progress bar grows with
how far you have read. Reveals, the ticker and the float stop for visitors who prefer reduced
motion. The back-to-top button appears after scrolling about one screen down, returns to the top and
moves focus to the main content; to remove it, delete the "Back to top" part of
assets/js/main.js and the .back-to-top styles in src/theme.css, then run pnpm build.
Block styles#
In the block settings' Styles panel:
| Block | Styles |
|---|---|
| Button | Fill (default, the clay button), Outline, Sun |
The classes is-px-5, is-px-7, is-px-8, is-py-2-5, is-py-3-5 and is-py-4 on a Button block
make it wider or taller (the hero buttons use them); icon-after-arrow-right adds the arrow.
FAQ answers on the contact page are Details blocks: add one by duplicating an answer in List
View; its summary layout comes from classes starting with [&>summary]: and its round plus button
is drawn by CSS (ff-faq).
Forms#
All forms with data-validate are checked by initForms() in assets/js/main.js: errors appear on
blur and on submit, the first invalid field is focused, and each error is in the element
<field id>-error, linked with aria-describedby. Rules come from attributes in the forms' Custom
HTML: required (checkboxes must be ticked; message from data-msg), type="email", type="tel"
(digits, spaces, +, (, ) and -, 7 to 20 characters), minlength and data-label (the words
in the "Enter …" message).
| Form | Where | Success state |
|---|---|---|
Newsletter (#newsletter-form) |
Home (newsletter) |
#newsletter-success |
Enquiry (#enquiry-form) |
Tour (tour-details, #enquire) |
#enquiry-success, repeating the booking summary |
Contact (#contact-form) |
Contact (contact-form) |
#contact-success |
The form's data-success attribute names its success box. Nothing is sent, and the success
messages say so. To collect submissions, use a form plugin (replace the form's Custom HTML block with
the plugin's block; add the classes field, field-label and btn-primary to its fields, labels and
button), or post the form in onValid() in section 11 of assets/js/main.js (in a child theme), for
example to Formspree:
function onValid(form) {
fetch('https://formspree.io/f/your-id', {
method: 'POST', body: new FormData(form), headers: { Accept: 'application/json' }
}).then(function (res) {
if (res.ok) showSuccess(form); else toast('Something went wrong. Please email us.');
});
}Then change the success text in the patterns to say the message was received. Every field has a
name, so FormData carries all values; keep a name on any field you add. The contact form's trip
list is filled from TOURS, and /contact/?tour=kumano-kodo preselects a trip.
SEO and sharing#
Page titles come from WordPress: the page title, a vertical bar and the site name (for example
"Tours | Saltwind"); the home page shows the site name and tagline (Settings > General). The tour
page sets its title from the tour ("Lofoten Peaks & Fjords — 7 days in Norway | Saltwind") once
the script runs (and the meta description, if an SEO plugin prints one). The theme doesn't output meta
descriptions or Open Graph tags; use an SEO plugin such as Yoast SEO, Rank Math or The SEO Framework,
and give it assets/img/og-image.png (or your own 1200 × 630 image) as the default social image.
WordPress already generates a sitemap at /wp-sitemap.xml. Tours are drawn by JavaScript from one
page; if search visibility for each tour matters, give each tour a page of its own.
Accessibility#
Built in: a skip link to the main content (added by WordPress, styled by the theme), landmarks
(header, labelled navigation, main, footer), one h1 per page, labelled sections, breadcrumbs with
aria-current, visible focus rings, the menu button with aria-expanded and a label that changes
with its state (Escape closes the menu), real checkboxes and radios for filters and room choices,
live regions for the result count, the journal status, the booking total and the toast, an
itinerary of buttons with aria-expanded, FAQ answers in <details>, a seasonality table with text
for every cell, text alternatives for the route map, region charts and meaningful art (decorative art
is hidden), form errors announced through aria-describedby and aria-invalid, and reduced-motion
support for every animation. The demo passes axe (WCAG 2.1 A and AA).
When you edit: keep one Heading 1 per page, give images alt text (or mark them decorative), add
data-label to art that carries meaning, keep link text meaningful, and label any field you add to a
form (<label for="...">).
Building and deploying#
You only need this if you change the theme's files. The stylesheet assets/css/theme.css is
compiled with Tailwind CSS from src/theme.css and the classes used in patterns/, parts/,
templates/, inc/ and assets/js/:
pnpm install
pnpm build # compile assets/css/theme.css and assets/css/editor.css
pnpm watch # recompile assets/css/theme.css on every change (run pnpm build before you commit)Run pnpm build after adding a utility class to a pattern, template or the script's markup,
otherwise the class has no style. Classes you type in the editor's Additional CSS class(es)
field are only styled if the stylesheet already contains them.
To deploy, zip the theme folder (named freeframe-wander, without node_modules/) and upload it in
Appearance > Themes, or copy the folder to wp-content/themes/ on your server.
Translations#
The theme is translation-ready with the text domain freeframe-wander. All text in patterns,
templates and PHP goes through WordPress's translation functions; the script's strings (tour cards,
filters, the tour page, booking messages, seasons, form errors) are translated in PHP
(freeframe_wander_script_strings() in inc/setup.php). Tour names, summaries and itineraries are
data in assets/js/main.js. Create a translation with Loco Translate, or with WP-CLI and Poedit:
wp i18n make-pot wp-content/themes/freeframe-wander wp-content/themes/freeframe-wander/languages/freeframe-wander.potSave freeframe-wander-de_DE.mo (for example) in wp-content/languages/themes/ or in the theme's
languages/ folder. Page content created by Wander setup is copied into your pages in the site's
language at that moment; translate it in the editor like any other content.
Child themes#
Use a child theme for changes you want to keep when Wander is updated (your tours in particular).
Create wp-content/themes/wander-child/style.css:
/*
Theme Name: Wander Child
Template: freeframe-wander
*/Templates, parts, patterns and theme.json in the child theme override the parent's files of the
same name. To use your own copy of assets/js/main.js, dequeue the parent's script
(freeframe-wander) and enqueue yours with the same dependencies in the child's functions.php.
The parent's stylesheet only contains the classes the parent uses: if your child theme uses new
utility classes, compile a stylesheet for the child (copy package.json and src/theme.css, point
the @source lines at the child's folders) and enqueue it.
Troubleshooting#
- The pages look unstyled or new classes do nothing. The stylesheet only contains classes it
found when it was built. Run
pnpm buildafter editing patterns, then reload. - "This block contains unexpected or invalid content". A pattern or page was edited by hand with markup that doesn't match the block. Click Attempt recovery, or re-insert the section from Patterns > Wander.
- Tour cards link to a page that doesn't exist. The script links to
/tour/,/tours/and/contact/. If you renamed those pages, updatefreeframe_wander_page_urls()ininc/setup.php. - A new tour doesn't appear under a filter, or shows no departures. Its
regionandstylemust match anidinREGIONSandSTYLES, and itsmonthsmust be numbers from 1 to 12; departures are only generated for the next 15 months and never sooner thanBOOKING_CUTOFFdays away. - Prices look higher than "from". Departures in a region's best months add
PEAK_SUPPLEMENT; set it to0to turn peak pricing off. - Home is missing from the desktop menu, or another link is. The desktop header hides the menu's first link. See Navigation, header and footer.
- Wander setup says the pages exist, but they are empty. It never overwrites existing pages. Delete (and empty the trash of) the pages with those slugs, or open each page and insert its page pattern from Patterns > Wander pages.
- The forms don't send anything. They are demo forms; see Forms.
License#
MIT, which is compatible with the GPL that WordPress requires (see LICENSE.txt in the theme
folder). Free for personal and commercial use. The illustrations, logo and social image are included
under the same license. Caprasimo, Outfit and Kalam are licensed under the SIL Open Font License 1.1
(OFL.txt in each folder of assets/fonts/).