Overview#
Wardline is a corporate B2B SaaS website for a compliance automation product, built as a WordPress
block theme. The fictional company, Wardline, Inc., is based at 1520 E Cary St in Richmond,
Virginia, and makes a platform that helps startups and mid-size companies prepare for SOC 2,
ISO 27001, HIPAA, GDPR, PCI DSS and NIST CSF with continuous control monitoring, evidence
collection, policies, vendor risk, access reviews and a public trust center. The theme has a home
page with a control dashboard that switches between frameworks; a six-tab platform tour with a
product mockup per tool; a framework explorer with control families and cross-mapping; an
eight-question readiness assessment; a pricing calculator; a searchable integrations directory; a
trust center with rolling report dates and a document request form; customer stories with
before-and-after charts; a three-step demo booking in the visitor's time zone; 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/wardline.
Headings, copy, lists, plan cards, story text, buttons and the pricing questions are core
WordPress blocks arranged in block patterns, so you edit them in the block editor without touching
code. The parts that are worked out in the browser (the dashboard, the framework cards, the tabs
and product mockups, the explorer, the assessment, the calculator, the directory, the trust center
lists and form, the story filter and charts, and the demo booking) work as in the HTML version:
they are Custom HTML blocks driven by assets/js/main.js, which reads the product data from
assets/js/data.js. Colors and fonts are design tokens in theme.json: change them in
Appearance > Editor > Styles and the whole site follows. Every date is worked out in
America/New_York (Eastern time) from rules rather than fixed dates, so the demo never goes stale.
The copy is careful about what a compliance tool can claim: Wardline helps customers prepare, and independent auditors (a licensed CPA firm for SOC 2, an accredited certification body for ISO 27001) issue reports and certificates. Keep that distinction if you adapt the theme for a real product.
Quick start#
Requirements: WordPress 7.1 or newer and PHP 7.4 or newer. No plugins are needed.
- Download
wardline.zipfrom freeframe.dev/templates/wardline (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 Wardline.
- Go to Appearance > Wardline setup and click Create the demo pages. This creates the Home, Platform, Frameworks, Readiness assessment, Pricing, Integrations, Trust center, Customers and Book a demo 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.
- 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 > Wardline pages) made of section patterns. Every section is also offered on its own in the block inserter under Patterns > Wardline.
| Page | Slug | Page pattern | Sections (pattern files in patterns/) |
|---|---|---|---|
| Home | / |
page-home.php |
home-hero (control dashboard), customer-logos, how-it-works, framework-cards (built from FRAMEWORKS), numbers, who-does-what, home-story, home-cta |
| Platform | /platform/ |
page-platform.php |
platform-header, product-tour (six tabs; #evidence opens one), roles, access-security, platform-cta |
| Frameworks | /frameworks/ |
page-frameworks.php |
frameworks-header, framework-explorer (#explorer), overlap-matrix, who-issues-what, frameworks-cta |
| Readiness assessment | /assessment/ |
page-assessment.php |
assessment (questions and results), assessment-method |
| Pricing | /pricing/ |
page-pricing.php |
pricing-plans (plan cards), pricing-calculator (#calculator), plan-comparison, pricing-faq |
| Integrations | /integrations/ |
page-integrations.php |
integrations-header, integrations-directory, integrations-other, integrations-connect, integrations-cta |
| Trust center | /trust/ |
page-trust.php |
trust-header (report dates), trust-controls, trust-documents, subprocessors, document-request (#request) |
| Customers | /customers/ |
page-customers.php |
customers-header, story-filter, story-kelvara (#kelvara), story-mendwell, story-hirebeam, story-results, customers-cta |
| Book a demo | /contact/ |
page-contact.php |
demo-booking |
| 404 | any missing URL | templates/404.html |
404 |
WordPress 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-wardline/
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 scripts (with the script's strings and page URLs), editor
styles, the `js` class script, theme color and favicon, page titles,
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 styles
inc/site-setup.php Appearance > Wardline 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/data.js the product data (window.WARDLINE): FRAMEWORKS, CONTROLS, INTEGRATIONS,
PLANS, ADDONS, ASSESSMENT, TRUST_CATEGORIES, DOCUMENTS, DEMO and more
assets/js/main.js every interaction (the HTML version's script plus a WordPress adapter)
assets/icons/ the icons used by Icon blocks (outline SVG paths)
assets/img/ favicon.svg (header logo), logo-footer.svg, social image, illustrations
assets/fonts/ Anek Latin, Source Sans 3 and Roboto Mono, with their licenses
src/theme.css the Tailwind CSS source of assets/css/theme.css
src/icons.css icons drawn after button text with CSS (generated)
src/editor-css.mjs writes assets/css/editor.css after each build
languages/ freeframe-wardline.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.txtCustomizing#
Brand and colors#
The palette is in theme.json (settings.color.palette) and shows in Appearance > Editor >
Styles > Colors. The stylesheet maps every Tailwind color to these presets
(--color-teal: var(--wp--preset--color--teal) in src/theme.css), so changing Teal in Styles
changes every button, link, chip and focus ring that uses teal.
| Color | Value | Used for |
|---|---|---|
| Ink | #0b1a2c |
Headings, body text, dark bands, the header strip and footer |
| Paper / Card / Cloud | #f6f8fa / #ffffff / #edf1f5 |
Page background, panels, alternate bands |
| Line / Line strong | #dbe2ea / #93a1b3 |
Hairlines and input borders |
| Slate / Slate 2 | #3f4d61 / #566376 |
Secondary text and captions (AA on light backgrounds) |
| Frost | #a9b8ca |
Secondary text on ink |
| Teal, Teal deep, Teal soft, Teal bright | #0b6f80 … |
The accent: buttons, links, focus rings, charts |
| Passing, Attention, Failing (and their soft tints) | green, amber, red | Status pills, always with a symbol and a word |
Some SVG art (the seals, Venn diagram, charts and monograms in main.js, and the inline mockups
and illustrations in the patterns) uses hex values directly; search for #0b6f80 to update them
too.
Typography#
Three families are bundled in assets/fonts/ and declared in theme.json (no requests to Google):
- Anek Latin (500–700) for headings (
font-display) - Source Sans 3 (400–700, italic 400) for body text (
font-sans, the body font) - Roboto Mono (400, 500) for control IDs, labels and figures (
font-mono)
Swap a family in Styles > Typography, or add your own fontFace files to theme.json. In SVG,
quote "Source Sans 3" (font-family="'Source Sans 3'"), because a family name ending in a number
must be quoted.
Content#
Page copy (headings, paragraphs, plan cards, story text, the pricing questions) is in the pages:
edit it in the block editor. Everything data-driven lives in assets/js/data.js on
window.WARDLINE, as in the HTML version:
| Constant | What it holds |
|---|---|
FRAMEWORKS |
Six frameworks with a one-letter code, seal shape, issuer, summary and prep |
FAMILIES |
Fifteen control families by two-letter prefix |
CONTROLS |
The 81-control library as [id, title, frameworkLetters] |
INTEGRATION_CATEGORIES, INTEGRATIONS |
Six categories and 24 integrations with checks, setup minutes and access |
ANNUAL_DISCOUNT, PLANS, ADDONS |
Pricing rules |
ASSESSMENT |
Sizes, five scored questions, targets, deadlines and score bands |
TRUST_CATEGORIES, SUBPROCESSORS, DOCUMENTS, PERSONAL_DOMAINS |
Trust center content and email checks |
DEMO, SPECIALISTS |
Demo form options, slot times and routing |
STORIES |
Customer stories and their before-and-after metrics |
Adding a control mapped to SOC 2, ISO 27001 and NIST CSF updates every count, bar, Venn diagram and matrix cell:
["AC-10", "Break-glass accounts sealed and alerted", "SIN"],Adding an integration:
{ id: "shiftledger", name: "Shiftledger", category: "hr", checks: 7, summary: "…", access: "Read-only report token", minutes: 5 },Numbers in the copy that come from the data (81 controls, 24 integrations, 361 checks) are spans
with data-stat that the script fills, so they follow data.js. Edit data.js in a child theme
(see Child themes) so an update doesn't overwrite it.
Images and artwork#
All artwork is SVG drawn for this template; there are no photos. The header logo is an Image block
(assets/img/favicon.svg), the footer logo another (assets/img/logo-footer.svg): select one and
Replace to use your own. The step illustrations, the integrations hub, the 404 shield, the six
platform mockups and the hero dashboard are Custom HTML blocks with inline SVG and HTML; they are
pictures of a product, not content, so replace a whole block with an Image block (keep roughly the
same aspect ratio) when you have real screenshots. Framework seals (seal()), integration
monograms (monogram()), the Venn diagram and the story charts are drawn by main.js. The seals are
original generic badges, not any standards body's mark; keep it that way unless you have permission
to use an official logo. The customer marks next to the logo names are Icon blocks.
The social image is assets/img/og-image.png (1200 x 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 has two Navigation blocks showing the same menu: the desktop one (from 1024 px) and the
one in the phone menu. Edit the menu once in Appearance > Editor > Navigation (the setup creates
"Main menu": Platform, Frameworks, Integrations, Pricing, Customers, Trust center and Readiness
assessment). A menu item with the class ff-mobile-only (Readiness assessment, under the link's
Advanced settings) only shows in the phone menu, as in the HTML version, where the desktop
header links to it from the dark strip at the top. WordPress marks the current page's link with
aria-current="page", and the script marks the header's "Book a demo" button on the demo page
(class ff-current-link). 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 link columns are List blocks: click a link to change it, press Enter to add one. The
office status line (class ffd-office-status) is replaced by the script; the copyright year is
written by PHP. The phone number and emails appear in the header, the footer and several pages;
search for them when you change them.
Features#
Hero control dashboard#
initHeroDashboard() switches the dashboard on the home page between three frameworks with the
[data-dash-fw] buttons (aria-pressed). Each framework's passing, attention and failing counts,
readiness percentage and audit-window offset are in the states object inside that function. The
audit window date is today plus the offset (46 days for SOC 2, 73 for ISO 27001, 29 for HIPAA), so
on Nov 3, 2026 SOC 2 shows "Dec 19, 2026 · in 46 days".
Platform tabs#
initTabs() drives the product-tour section with the ARIA tabs pattern: arrow keys, Home and End
move between tabs, and the URL hash (#controls, #evidence, #policies, #vendors, #access,
#trust) opens a tab directly. The tab list and each product mockup are Custom HTML blocks; the
text beside each mockup is ordinary blocks inside the tab panel Group. Dates inside the mockups use
data-day-offset (see Keeping the demo current).
Framework explorer and cross-mapping#
initFrameworks() on the Frameworks page renders the selected framework's issuer, preparation
note, control count and families from FRAMEWORKS and CONTROLS, then compares it with a second
framework. A control counts toward a framework when its letters include the framework's code.
With the shipped data SOC 2 has 61 controls, ISO 27001 63, HIPAA 36, GDPR 17, PCI DSS 49 and NIST
CSF 46; SOC 2 and ISO 27001 share 57 ("57 of SOC 2's 61 controls (93%) also count toward
ISO 27001. Adding ISO 27001 after SOC 2 means 6 new controls, not 63."). renderMatrix() draws the
pairwise matrix; each number links to that pair. URL parameters: ?fw=<id>&vs=<id|none> (soc2,
iso27001, hipaa, gdpr, pci, nist); unknown values fall back to SOC 2 compared with
ISO 27001. The page keeps the URL in step with history.replaceState.
Readiness assessment#
initAssessment() steps through eight questions (size, cloud, policies, identity,
logging, vendors, target, deadline); options come from ASSESSMENT. In assess():
- Score: the five scored answers add up their
points(20 each at best, 100 in all). - Band: 80+ "Well prepared", 55+ "Solid foundation", 30+ "Early stage", below that "Starting out".
- Gaps: every scored answer below 20 points, ranked by points missing (ties keep question order); 10 or more missing is "High priority", otherwise "Medium priority".
- Range:
low = round((targetLow + gapWeeks) × sizeFactor),high = round((targetHigh + gapWeeks × 1.5) × sizeFactor), with size factors 1, 1.15, 1.35, 1.6. - Deadline verdict: "Realistic" when
highfits the deadline weeks (13, 26 or 52), "Tight" when onlylowfits, "At risk" otherwise; "No date" with no deadline.
Example: 51–200 people, one cloud set up by hand, draft policies, MFA without SSO, some logs, no
vendor reviews, SOC 2 Type II, 3–6 months gives 47 ("Early stage"), 16–24 weeks and
"Realistic". Answers are saved as they are chosen; the results link to
/contact/?fw=<framework>&size=<size>.
Pricing calculator#
initPricing() and quote() on the Pricing page. The plan follows the employee count (5–2,000):
Essentials up to 100, Growth up to 500, Scale up to 2,000.
monthly = base + extra employees × perEmployee + extra frameworks × extraFramework + add-ons
annual per month = round(monthly × (100 − ANNUAL_DISCOUNT) / 100)| Plan | Base | Included employees / frameworks | Per extra employee | Per extra framework | Included add-ons |
|---|---|---|---|---|---|
| Essentials | $690 | 25 / 1 | $8 | $240 | none |
| Growth | $1,450 | 100 / 2 | $6 | $200 | Trust center |
| Scale | $3,200 | 500 / 3 | $4 | $160 | Trust center, vendor risk |
The default (60 employees, 1 framework, annual) is $776 a month ($9,312 a year). 120 employees,
2 frameworks, vendor risk and training is Growth at $1,656 a month billed annually. The plan
cards' "from" prices ($552, $1,160, $2,560) are filled from PLANS; the matching card gets a teal
ring and the "Matches your estimate" label.
Integrations directory#
initIntegrations() filters INTEGRATIONS by category chip and a search over name, summary and
category, and sorts by name or by number of checks. Chip counts follow the search, the filters are
saved, and ?category=<id> (cloud, identity, hr, ticketing, code, endpoint) opens a
category. Identity and SSO plus "mfa" shows "2 integrations · 33 automated checks".
Trust center#
initTrust() renders the control categories (TRUST_CATEGORIES, 20 of 21 passing), the
subprocessor table and the report dates. The script looks for its markup inside [data-trust]; in
WordPress the first trust section carries the class ff-trust and the adapter puts data-trust on
<main>. "Request access" buttons check that document in the request form below; ?doc=<id>
prechecks one.
Customer stories#
initStories() draws two bars per metric from STORIES[].metrics (before in gray, after in teal,
each with a text label and an aria-label), and the chips filter the story sections by framework
(class ffd-frameworks--soc2_pci on each story Group becomes data-frameworks="soc2 pci").
Demo booking and time zones#
initDemo() on the Book a demo page runs three steps: team (role, size, at least one framework,
timeline), details (name, work email, company, note) and a time. Slots are DEMO.times in Eastern
time (10:00, 11:30, 13:00, 14:30, 16:00) on the next five business days after today, skipping
weekends and US federal holidays computed by rule in holidaysFor(year) (Saturday holidays move to
Friday, Sunday holidays to Monday). With ?now=2027-11-24T12:00 the days are Fri Nov 26 to Thu
Dec 2, with the note "Closed Nov 25 for Thanksgiving Day." Some slots show as booked by a fixed hash
of date and time (slotTaken()). Times show in the visitor's own zone with the Richmond time
underneath; the "Show times in" select switches between it and six others, and ?tz= preselects
one. The call is routed by SPECIALISTS (HIPAA to Soledad Ilunga, PCI DSS to Evander Lachance, 201+
employees to Ravindra Satterwhite, everyone else to Leontyne Fairbairn). ?fw=, ?size= (s1–s4)
and ?plan= prefill the first step.
Menu, office status and motion#
initMenu() toggles the phone menu (aria-expanded, Escape closes it and returns focus).
initOfficeStatus() shows "Open now" or "Closed now" for Mon–Fri, 8:30 a.m.–5:30 p.m. ET, and
"Closed today for …" on federal holidays. Elements with .reveal fade in as they scroll into view;
reduced motion shows everything at once, and the pulse dot in the status strip stops.
Keeping the demo current#
Nothing dated goes stale:
KEEP_DEMO_CURRENT = trueinmain.jsrolls the trust center dates: the SOC 2 Type II period ends on the latest September 30 whose report has been issued (the fourth Wednesday of October), the ISO 27001 certificate runs in three-year cycles from March 14, 2025, and the latest penetration test is the most recent August. On Nov 3, 2026 that is Oct 1, 2025 – Sep 30, 2026, issued Oct 28, 2026. Set it tofalseto show the fixed dates inFIXED_REPORTS.data-day-offset="-3"(withdata-format="short|medium|weekday") fills a date relative to today;data-todayfills today's date;data-yearfills the copyright year (also written by PHP).- The hero audit window, the document review day and the demo slots are worked out from today.
?now=YYYY-MM-DDTHH:MMpreviews the whole site at another Eastern time.
For a real site with fixed dates, set KEEP_DEMO_CURRENT to false, edit FIXED_REPORTS, and
replace the data-day-offset elements in the mockups with real dates.
Block styles#
In the block settings' Styles panel:
| Block | Styles |
|---|---|
| Button | Fill (default, the teal button), Ghost, Ink, Light (on dark), Outline (on dark) |
The class is-small on a Button block makes it the smaller size. The arrow after button text is
drawn with CSS (icon-after-arrow-right, from src/icons.css). The pricing questions are Details
blocks with the class faq, which draws the summary and its plus sign.
Forms#
There are two forms that collect details, and neither sends anything until you connect it. They are in Custom HTML blocks.
| Form | Pattern | Validates | Success state |
|---|---|---|---|
Document request (data-access-form) |
document-request |
at least one document, full name, company, a valid work email (not a personal domain from PERSONAL_DOMAINS), the NDA box when a chosen document needs it |
reference TR- + 6 characters, the next business day for review, next steps |
Book a demo (data-demo-form) |
demo-booking |
step 1: role, size, a framework, timeline; step 2: first and last name, work email, company; step 3: a slot | reference DM-MMDD-XXXX, the time in Eastern and the visitor's zone, the specialist, next steps |
To connect a form service such as Formspree, post the form data in the submit handler and show the
success panel only when the service answers OK. In assets/js/main.js (in a child theme), find the
comment "To connect a real endpoint" (document request) or "To connect a real scheduler" (demo):
const response = await fetch("https://formspree.io/f/your-id", {
method: "POST",
body: new FormData(form),
headers: { Accept: "application/json" },
});
if (!response.ok) {
// show an error message and stop
}Make the handler async. For bookings you would usually call your scheduling tool's API instead
and use its confirmed time. You can also replace a form's Custom HTML block with a form plugin's
block; add the classes label, field and btn to its labels, fields and button so it matches.
Saved data (localStorage)#
| Key | Shape | Validation on read |
|---|---|---|
wardline:assessment:v1 |
{ "size": "s2", "cloud": "single", …, "target": "soc2t2", "deadline": "d6" } |
each answer must be a known option key |
wardline:pricing:v1 |
{ "employees": 120, "frameworks": 2, "addons": ["vendor"], "billing": "annual" } |
whole numbers in range, known add-on ids, monthly or annual |
wardline:integrations:v1 |
{ "category": "identity", "q": "mfa", "sort": "name" } |
known category or all, up to 60 characters, name or checks |
wardline:demo-draft:v1 |
{ "role", "size", "frameworks", "timeline", "first", "last", "email", "company", "note" } |
known keys only, strings trimmed; removed after booking |
These are the HTML version's keys. All access goes through safeStorage in main.js: when
localStorage is blocked (sandboxed iframes, strict privacy settings), it falls back to memory, so
every feature keeps working for the page view. Keys from storage and the URL are checked with
Object.prototype.hasOwnProperty, so values like ?fw=constructor are ignored. To reset, clear the
site's data in the browser.
SEO and sharing#
Page titles come from WordPress: the page title, a vertical bar and the site name (for example
"Pricing and cost calculator | Wardline"); the home page shows "Wardline: compliance automation for
SOC 2, ISO 27001 and HIPAA", built from the site title and tagline (Settings > General) by
freeframe_wardline_front_title(). 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 x 630 image) as the default social image. WordPress
already generates a sitemap at /wp-sitemap.xml. A SoftwareApplication or Organization
structured-data block is a good addition once you have real details.
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, visible teal
focus rings (bright teal on dark bands), the ARIA tabs pattern, toggle buttons with aria-pressed,
a menu button with aria-expanded, status shown with a symbol and a word as well as color, charts
with text labels and aria-label summaries, live regions for counts, overlap text and estimates,
inline errors tied to their fields with aria-describedby and aria-invalid, focus moved to the
first problem, keyboard-focusable scrollable tables, and reduced-motion support. The demo passes axe
(WCAG 2.1 A and AA) in its checks.
When you edit: keep one Heading 1 per page, give images alt text (or mark them decorative), label every field you add, and keep body text at the Slate colors or darker.
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; keep each class name whole in the script (not built from pieces).
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-wardline, without node_modules/) and upload it
in Appearance > Themes, or copy the folder to wp-content/themes/ on your server. Use HTTPS, and
connect the forms before you go live.
Translations#
The theme is translation-ready with the text domain freeframe-wardline. All text in patterns,
templates and PHP goes through WordPress's translation functions; the script's own labels and
messages (validation errors, statuses, button labels) are translated in PHP
(freeframe_wardline_script_strings() in inc/setup.php). Sentences the script builds from pieces
(dates, estimate lines, the overlap sentence) are written in English in main.js; translate them
there. The product's content in assets/js/data.js is edited there directly. Create a translation
with Loco Translate, or with WP-CLI and Poedit:
wp i18n make-pot wp-content/themes/freeframe-wardline wp-content/themes/freeframe-wardline/languages/freeframe-wardline.potSave freeframe-wardline-es_ES.mo (for example) in wp-content/languages/themes/ or in the theme's
languages/ folder. Page content created by Wardline 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 Wardline is updated (your frameworks, prices
and integrations in particular). Create wp-content/themes/wardline-child/style.css:
/*
Theme Name: Wardline Child
Template: freeframe-wardline
*/Templates, parts, patterns and theme.json in the child theme override the parent's files of the
same name. To use your own data.js, replace the parent's data script (freeframe-wardline-data)
under the same handle in the child's functions.php:
add_action( 'wp_enqueue_scripts', function () {
wp_deregister_script( 'freeframe-wardline-data' );
wp_register_script( 'freeframe-wardline-data', get_stylesheet_directory_uri() . '/data.js', array(), '1.0', array( 'in_footer' => true, 'strategy' => 'defer' ) );
}, 15 );Do the same for assets/js/main.js (handle freeframe-wardline), keeping the inline
window.freeframeWardline strings and page URLs. 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 > Wardline.
- The assessment opens on the results. Answers are saved; use "Start over", or remove
wardline:assessment:v1. - Demo slots are on the wrong days. Dates come from the visitor's clock in Eastern time; check
for a leftover
?now=in the URL, and editholidaysFor()for your own office closures. - Framework or booking links go to the wrong page. The script links to
/frameworks/and/contact/. If you renamed those pages, change their URLs infreeframe_wardline_page_urls()ininc/setup.php(in a child theme, filter the inline script). - Report dates don't match your real report. Set
KEEP_DEMO_CURRENTtofalseand fillFIXED_REPORTS. - Wardline 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 > Wardline pages.
License#
Split license: the PHP code and block markup are licensed under the GNU GPL, version 2 or later, and the CSS,
JavaScript, images and design under the Freeframe Commercial License (unlimited sites for you and your
clients; no resale or redistribution as a theme). The full terms, with your licensee details, are in
LICENSE.txt and at https://freeframe.dev/license#commercial. Third-party components keep their own licenses.
Fonts: Anek Latin, Source Sans 3 and Roboto Mono are licensed under the SIL Open Font License 1.1 (OFL.txt
in each folder of assets/fonts/). Wardline, its customers, integrations, subprocessors and people are
fictional.