Overview#
Slatework is a website for a recruiting software company, built as a WordPress block theme. The fictional
Slatework, Inc. makes an applicant tracking system (ATS) for companies with 50 to 1,000 employees, is based at 418
West Short Street in Lexington, Kentucky, and works in Eastern time (America/New_York). The theme has a home page
whose hero is a live hiring pipeline board, a product tour (job board picker and posting preview, stage rules, a
weighted interview scorecard, a panel scheduler across US time zones, an offer pay band check and report charts),
per-employee pricing with a monthly or yearly switch and a cost-per-hire calculator, filterable customer stories, a
searchable integrations directory with a detail dialog, a security and compliance page with a data retention
example, resources with rolling monthly webinars and articles, a demo request form 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/slatework.
Headings, copy, lists, cards, quotes, buttons and the billing 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 pipeline board, the scorecards, the job board picker, the scheduler, the offer check, the pricing calculator,
the customer story list, the integrations directory and dialog, the retention example, the webinars and their
registration form, the article list and the demo request form) work as in the HTML version: they are Custom HTML
blocks driven by assets/js/main.js, which reads Slatework's content from assets/js/data.js. The drawings and
charts are Custom HTML blocks with inline SVG, so their colors follow the light and dark themes. Colors and fonts
are design tokens in theme.json: change them in Appearance > Editor > Styles and the whole site follows. Every
upcoming date is worked out in Eastern time from rules rather than fixed dates, so the demo never goes stale.
The look is corporate and structured: white paper with hairline grids, a deep indigo brand color, a marigold highlight, Hubot Sans headings and Fira Sans body text, with a full dark mode.
Quick start#
Requirements: WordPress 7.1 or newer and PHP 7.4 or newer. No plugins are needed.
- Download
slatework.zipfrom freeframe.dev/templates/slatework (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 Slatework.
- Go to Appearance > Slatework setup and click Create the demo pages. This creates the Home, Product, Pricing, Customers, Integrations, Security, Resources 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 > Slatework pages) made of section patterns. Every section is also offered on its own in the block inserter under Patterns > Slatework.
| Page | Slug | Page pattern | Sections (pattern files in patterns/) |
|---|---|---|---|
| Home | / |
page-home.php |
home-hero (pipeline board), customer-logos, pillars, home-scorecard, results, home-cta |
| Product | /product/ |
page-product.php |
product-hero, sourcing (#sourcing), pipeline-rules (#pipeline), interviews (#interviews), scheduling (#scheduling), offers (#offers), reports (#reports), product-cta |
| Pricing | /pricing/ |
page-pricing.php |
pricing-hero (billing switch), plans, calculator (#calculator), compare-plans, billing-faq |
| Customers | /customers/ |
page-customers.php |
customers-hero, stories (filters and the list from CASES), customers-cta |
| Integrations | /integrations/ |
page-integrations.php |
integrations-hero, directory (from INTEGRATIONS), api, integration-dialog |
| Security | /security/ |
page-security.php |
security-hero, controls, retention (#retention), self-id, subprocessors |
| Resources | /resources/ |
page-resources.php |
resources-hero, webinars (with registration), articles (from POSTS) |
| Book a demo | /demo/ |
page-demo.php |
demo-request |
| 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-slatework/
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 dark mode script, theme colors 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 > Slatework 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 Slatework's content (window.SLATEWORK): STAGES, CANDIDATES, COMPETENCIES,
BOARDS, INTERVIEWERS, OFFER_BAND, PLANS, CASES, INTEGRATIONS, POSTS 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/ logo.svg, favicon.svg and the social image
assets/fonts/ Hubot Sans and Fira Sans, with their licenses
src/theme.css the Tailwind CSS source of assets/css/theme.css (also the dark colors)
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-slatework.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 light 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-brand: var(--wp--preset--color--brand) in src/theme.css), so changing Brand in Styles changes every button, link and
focus ring that uses brand.
| Color | Light | Dark | Used for |
|---|---|---|---|
| Paper | #ffffff |
#0f1117 |
Page and card background |
| Canvas / Canvas 2 | #f4f4f1 / #e9e9e3 |
#161922 / #1f2330 |
Alternate bands, board columns / tracks |
| Line / Line strong | #dddfd7 / #878b7f |
#2b303f / #707790 |
Hairlines / inputs and chart axes |
| Ink, Ink soft, Ink faint | #15171e, #454955, #595d69 |
#eceef5, #b6bbcb, #9ba1b4 |
Text |
| Brand / Brand strong | #3a3fd0 / #2b2fa8 |
#a3a9ff / #c2c6ff |
Buttons, links, focus / hover |
| Brand soft / Brand line | #ecedfc / #c9ccf5 |
#23264a / #3c4180 |
Tinted chips and borders |
| Applied, Screen, Interview, Offer, Hired (and Soft) | stage colors | lighter stage colors | Board dots, chips, funnel bars |
| Danger / Danger soft | #b42318 / #fde8e6 |
#ff9b8f / #3a1714 |
Form errors |
| Night, Night 2, Night line, Mist | #13151d, #1d2030, #31364a, #c3c8d8 |
same | Footer and call-to-action bands, text on them |
| Marigold | #f2b33d |
same | Highlight fills, the button on dark bands |
The dark values are in src/theme.css (html.dark { --wp--preset--color--brand: #a3a9ff; ... }): when you change a
color in Styles, change its dark value there too and run pnpm build. The logo (assets/img/logo.svg),
favicon.svg, og-image.svg, the integration and customer marks in data.js and a few drawings use hex values
directly (#3a3fd0, #f2b33d); search for them if you change the brand completely.
The repeated pieces are classes in src/theme.css: .panel and .panel-lift (cards with a soft shadow),
.gridlines, .eyebrow, .h-display, .h-section, .lead, .link, .chip and the stage tones (.tone-hired,
.dot-offer...), .seg, .filter-btn, .rate and the form fields (.field, .field-label, .field-error,
.field-hint). Add them to any block under Advanced > Additional CSS class(es).
Typography#
Two families are bundled in assets/fonts/ and declared in theme.json (no requests to Google), the same files
Google Fonts serves to the HTML version:
- Hubot Sans (
font-display, headings; weights 500–800, widths 100–125%) is a variable font. Headings are set a little wider withfont-stretch: 112%, the logo at 115%. It draws its zero with a bar; that is the font's design. - Fira Sans (
font-sans, the body font; 400, 500, 600 and italic 400).
Swap a family in Styles > Typography, or add your own fontFace files to theme.json.
Content#
Page copy (headings, paragraphs, the feature pillars, the results, quotes, plans, the questions, the security
controls) is in the pages: edit it in the block editor. Everything the script renders lives in assets/js/data.js
on window.SLATEWORK, as in the HTML version:
| Constant | What it holds |
|---|---|
COMPANY |
Name, timeZone (America/New_York) and contact details |
STAGES |
The five pipeline stages, in order: applied, screen, interview, offer, hired |
REQ |
The requisition shown on the board (title, openings: 2) |
STAGE_BASE |
Candidates in each stage not shown as cards: applied: 38, screen: 9, interview: 3, offer: 0, hired: 0 |
CANDIDATES |
Board cards: id, name, source, age (days since applying), starting stage, avatar hue, optional score |
STAGE_REMAINING, TIME_TO_HIRE_TARGET |
Time-to-hire projection (offer: 4, hired: 0; target 30 days) |
COMPETENCIES, RATING_LABELS, RECOMMENDATIONS |
Scorecard competencies, weights and default ratings; score thresholds |
BOARDS, POSTING_LOCATIONS |
Job boards with 30-day price and typical applicants; posting locations |
INTERVIEWERS, WORK_HOURS, SCHEDULE_*, DISPLAY_ZONES |
Scheduler panel, working hours, busy blocks and time zones |
OFFER_BAND |
Pay band, slider range and approval rules for the offer check |
PLANS, ANNUAL_DISCOUNT, MIN_EMPLOYEES, MAX_EMPLOYEES, ENTERPRISE_HINT, DEFAULT_PRICING |
Pricing |
INDUSTRIES, SIZES, CASES |
Customer story filters and stories |
INT_CATEGORIES, INTEGRATIONS |
Integration categories and directory entries |
RETENTION, DEFAULT_RETENTION |
Data retention choices on the security page |
TOPICS, POSTS |
Article topics and articles (fixed past dates) |
WEBINAR_* |
Webinar rule, time and topics |
PERSONAL_DOMAINS, COMPANY_SIZES, DEMO_LEAD_DAYS, DEMO_TIMES |
Demo form checks and proposed meeting time |
Example: add an integration. Give it a unique id, an existing category, a tile color and a small mark drawn in
white inside a 40×40 box:
{ id: 'shiftnote', name: 'Shiftnote', category: 'messaging', bg: '#0f766e', setup: '2 minutes', direction: 'One-way',
blurb: 'Post interview reminders to the hiring team channel.',
syncs: ['Interview reminders', 'Scorecard due alerts'],
mark: '<circle cx="20" cy="20" r="9" fill="#fff"/>' }Category counts, search and the detail dialog pick it up automatically. The "22 integrations" line in the
directory pattern is the text shown before the script runs; update it if you want it exact.
Example: add a customer story to CASES with industry set to a key of INDUSTRIES and size to s, m or l.
metrics[0] draws the before-and-after chart. The home page logo row and quotes are blocks in the
customer-logos and results patterns; edit them there if you change customers.
The pricing calculator's "Book a demo with this estimate" link goes to the Book a demo page: the script turns the
HTML file name demo.html into your WordPress page URL with freeframe_slatework_page_urls() in inc/setup.php.
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 and footer logo is an Image block
(assets/img/logo.svg): select it and Replace to use your own. The feature pillar drawings, the customer logo
marks, the report charts, the integrations and security drawings, the most-read chart and the 404 board are Custom
HTML blocks with inline SVG whose fills use the theme's colors (fill-brand, stroke-line-strong), so they switch
with dark mode; replace a block with an Image block (keep roughly the same aspect ratio) when you have real
pictures. The integration and customer marks are drawn by the script from the mark strings in data.js.
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": Product, Pricing,
Customers, Integrations, Security and Resources). WordPress marks the current page's link with
aria-current="page" (drawn as an indigo bar under it). The "Book a demo" buttons in the header and the phone menu
are Button blocks. 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 copyright year is written by PHP and kept current by the script. The phone number and email appear in the footer and on the pricing and demo pages; search for them when you change them.
Dark mode#
The theme switch in the header ([data-theme-toggle]) toggles the dark class on <html> and saves the choice as
slatework:theme. A short script printed first in <head> (freeframe_slatework_head_script() in
inc/setup.php) applies the saved choice, or the visitor's system setting, before the page paints. To make light
the default regardless of the system setting, remove the matchMedia(...) check from that script. To remove dark
mode, remove that function and the switch's Custom HTML block from the header pattern.
Features#
Hero pipeline board#
Home page (home-hero pattern), section 5 of main.js (initPipeline). The board shows the requisition REQ
with five columns from STAGES. Each column's count is STAGE_BASE[stage] plus the cards in it.
- Drag and drop: with a mouse or pen, drag a card anywhere; on touch screens, drag by the card's initials
(
data-grip), so swiping the board still scrolls it. The board scrolls sideways when you drag near its edge. Escape cancels a drag. - Keyboard and screen readers: each card has a "Move" button (
data-move) that opens a menu of stages (role="menu"; arrow keys, Home, End, Escape). Choosing a stage moves the card, returns focus to it and announces the new count and time to hire. - Funnel: "reached" counts each stage plus every later stage. With the starting data: Applied 61, Screen 19, Interview 7, Offer 2, Hired 1, so Applied to Hired is 1.6%.
- Projected time to hire: the average of
age + STAGE_REMAINING[stage]over cards in Offer and Hired, rounded. Start: 25 days, "5 days under the 30-day target". Moving Ramona D. to Offer makes it 23 days; then dragging Esmeralda P. to Hired makes "2 of 2 openings filled" and 22 days. - Moves are saved (
slatework:pipeline); "Reset board" restores the starting data.
Interview scorecard#
Home (home-scorecard) and product (interviews) pages, initScorecards. Every [data-scorecard] panel lists
COMPETENCIES with 1–4 rating buttons (role="radio", arrow keys change the rating). The weighted score is
sum(weight × rating) / 100. The defaults give 3.25, Hire; rating Product knowledge 4 gives 3.55, Strong
hire. Thresholds are in RECOMMENDATIONS.
Job boards and posting preview#
Product page #sourcing, initBoards. Checking boards updates the board count, the 30-day cost and typical
applicants (default 3 boards, $0, 60 applicants; adding Talentcast makes $179, 76). The posting preview
follows the title, location and pay range fields and flags a maximum below the minimum.
Panel scheduler#
Product page #scheduling, initScheduler. For each of the next SCHEDULE_DAYS (5) weekdays after today in Eastern
time, it intersects every chosen interviewer's working hours (9:00 a.m. to 5:00 p.m. in their own zone) minus their
busy blocks and proposes up to 3 slots, at most two per day. Times show in the visitor's zone by default; "Show
times in" switches between US zones.
Offer pay band check#
Product page #offers, initOffer. Inside the band ($68,000–$84,000) only the hiring manager approves; below it the
people team is added; above it the VP and Finance are added (OFFER_BAND.rules).
Pricing and calculator#
Pricing page, initPricing. Monthly prices per employee are in PLANS (Essentials $5, Growth $8); yearly billing
takes ANNUAL_DISCOUNT (20%) off: $4 and $6.40. Companies under MIN_EMPLOYEES (50) are billed as 50. Default (200
employees, Growth, yearly, 40 hires): $1,280 a month, $15,360 a year, $384 per hire. The choice is saved
(slatework:pricing); URL parameters override it: ?billing=monthly|annual, ?plan=essentials|growth,
?employees=1–1000, ?hires=1–2000. The billing questions are Details blocks with the class faq.
Customer stories#
Customers page, initCustomers. Industry buttons and a company size select filter CASES; the URL keeps them as
?industry= and ?size=s|m|l.
Integrations directory#
Integrations page, initIntegrations. Search matches name, description and category; category buttons show counts.
The URL keeps ?category= and ?q=. Each card opens a <dialog> (the integration-dialog pattern) with what
syncs; Escape or Close returns focus to the card.
Data retention example#
Security page #retention, initRetention. Choosing 12, 24 or 36 months shows the date a candidate rejected today
would be anonymized and the reminder a month earlier, worked out from today in Eastern time.
Webinars and articles#
Resources page, initResources. Webinars are on the second Thursday of each month at 1:00 p.m. Eastern, the next 3
at least 3 days away. Articles in POSTS keep their real dates and can be filtered by topic (?topic=).
Menu, header and motion#
The menu button (#menu-toggle) opens the phone menu with aria-expanded; Escape closes it and returns focus. The
header gets a soft shadow once the page scrolls. Elements with .reveal fade in once as they scroll into view. With
prefers-reduced-motion: reduce there is no reveal or drag animation.
Keeping the demo current#
Nothing dated goes stale. All upcoming dates are computed from today in Eastern time (COMPANY.timeZone):
| Content | Rule | Switch |
|---|---|---|
| Interview slots | Next 5 weekdays after today | Busy blocks use business day numbers |
| Webinars | Second Thursday of the month, at least 3 days away | WEBINAR_DATES = null; set an array of 'YYYY-MM-DD' strings for fixed dates |
| Proposed demo time | First weekday at least DEMO_LEAD_DAYS (1) after today, at 10:00 a.m. or 2:00 p.m. Eastern |
DEMO_TIMES |
| Retention example | Today plus 12, 24 or 36 months | |
| Copyright year | Current year | written by PHP, filled again by the script |
Articles keep their fixed past dates. For reviews and screenshots, ?now=YYYY-MM-DDTHH:MM (read as Eastern time)
pretends it is another moment, for example /resources/?now=2027-11-10T09:00; turn it off with
ALLOW_NOW_PARAM = false at the top of main.js.
Block styles#
In the block settings' Styles panel:
| Block | Styles |
|---|---|
| Button | Fill (default, the indigo button), Outline, Marigold (on dark), Ghost (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).
Forms#
All forms validate in the browser with inline messages linked by aria-describedby, focus the first problem and
then show a success panel. No form sends anything until you connect it.
| Form | Page | Checks | Success |
|---|---|---|---|
Demo request (data-demo-form) |
Book a demo | Names, work email (format, and not a personal domain from PERSONAL_DOMAINS), company, role, size |
"Thanks, {name}. Your demo request is in.", reference SW-XXXXXX, proposed time in the visitor's zone and in Eastern, next steps |
Webinar registration (data-webinar-form) |
Resources | Name, email | Registration reference WB-XXXXX and the session time |
The Book a demo page also reads ?plan=essentials|growth|enterprise&employees= to preselect the plan and company
size, and ?topic=security to tick "Security and reporting".
To connect a form service such as Formspree, add the request inside setupForm in assets/js/main.js (in a child
theme), where it calls onSuccess, and show the success panel only when the service answers OK:
fetch('https://formspree.io/f/your-id', { method: 'POST', body: new FormData(form), headers: { Accept: 'application/json' } })
.then(function (r) { if (r.ok) { /* run the existing success code */ } else { /* show an error */ } });You can also replace a form's Custom HTML block with a form plugin's block; add the classes field-label, field
and btn-primary to its labels, fields and button so it matches.
Saved data (localStorage)#
All storage goes through safeStorage in main.js, which falls back to memory when localStorage is blocked
(private modes, sandboxed frames), so the features keep working for the visit.
| Key | Shape | Validation |
|---|---|---|
slatework:theme |
"light" or "dark" |
Anything else is ignored |
slatework:pipeline |
{ "v": 1, "stages": { "ramona": "offer", ... }, "order": ["ramona", ...] } |
Unknown candidates or stages are dropped; missing cards keep their starting stage |
slatework:pricing |
{ "billing": "annual", "employees": 200, "plan": "growth", "hires": 40 } |
Each field checked against its allowed values and range |
These are the HTML version's keys. All values read from the URL are checked with own-key lookups, so
?plan=toString is ignored.
SEO and sharing#
Page titles come from WordPress: the page title, a vertical bar and the site name (for example "Pricing: per-employee
plans for growing companies | Slatework"); the home page shows "Slatework: applicant tracking and hiring software for
growing companies", built from the site title and tagline (Settings > General) by
freeframe_slatework_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.
Accessibility#
Built in: a skip link to the main content (added by WordPress, styled by the theme), landmarks (header, labeled
navigation, main, footer), one h1 per page, sections labeled by their headings, visible focus outlines, AA contrast
in both themes, a full keyboard path for the pipeline board (the Move menu) with announcements in a live region,
scorecard ratings as radio groups, filters with aria-pressed, a native <dialog> for integrations, form errors
linked with aria-describedby, charts with role="img" and a description, and reduced-motion support. The demo
passes axe (WCAG 2.1 A and AA) in light and dark 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 Ink soft color 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-slatework, 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-slatework. All text in patterns, templates and PHP
goes through WordPress's translation functions; the script's own labels and messages (validation errors, the menu
button, status lines) are translated in PHP (freeframe_slatework_script_strings() in inc/setup.php). Sentences
the script builds from pieces (dates, counts, prices, announcements) are written in English in main.js; translate
them there. Slatework'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-slatework wp-content/themes/freeframe-slatework/languages/freeframe-slatework.potSave freeframe-slatework-es_ES.mo (for example) in wp-content/languages/themes/ or in the theme's languages/
folder. Page content created by Slatework 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 Slatework is updated (your candidates, plans, stories and
integrations in particular). Create wp-content/themes/slatework-child/style.css:
/*
Theme Name: Slatework Child
Template: freeframe-slatework
*/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-slatework-data) under the same handle in the
child's functions.php:
add_action( 'wp_enqueue_scripts', function () {
wp_deregister_script( 'freeframe-slatework-data' );
wp_register_script( 'freeframe-slatework-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-slatework), keeping the inline window.freeframeSlatework
strings and 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 > Slatework.
- The board keeps an old arrangement. It's saved in
slatework:pipeline; click "Reset board". - The scheduler shows no slots. The panel has no shared time in the next five weekdays. Check
busyblocks andWORK_HOURSindata.js, or pick a shorter interview. - Dates look a day off. Dates are computed in Eastern time; change
COMPANY.timeZoneindata.jsfor another home zone. Check for a leftover?now=in the URL. - "Book a demo with this estimate" goes to the wrong page. The script links to
/demo/. If you renamed the page, change its URL infreeframe_slatework_page_urls()ininc/setup.php. - A form says "received" but nothing arrives. The demo forms are not connected; see Forms.
- Slatework 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 > Slatework 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: Hubot Sans and Fira Sans are licensed under the SIL Open Font License 1.1 (OFL.txt in each folder of
assets/fonts/). Slatework, its customers, integrations, interviewers and people are fictional.