Hire for Craft CMS

Lite free · Pro $99 · Craft CMS 5

A careers page, an application form and a pipeline

Hire is job listings and applications for Craft CMS. Jobs and applications are elements, so the field layouts, per-site URLs, drafts, permissions, search, trash, element index and exporter are Craft's own rather than a second implementation of each.

Hire

A careers page in one line

The listing is rendered on the server, so it works with JavaScript off, is indexable, and every filter is a link you can paste into an email. The job page needs two more calls: the application form and the structured data Google for Jobs reads.

twig
{# The careers page: search, filters, results, pagination #}
{{ craft.hire.listing() }}

{# A job page #}
{% block head %}{{ craft.hire.schema(job) }}{% endblock %}

<h1>{{ job.title }}</h1>
<p>{{ job.locationLabel }} · {{ job.salary }} · closes {{ job.expiryDate|date('j F Y') }}</p>

{{ craft.hire.applyForm(job) }}

Features

Posting the job, taking the application, and what happens after.

Jobs are elements

A field layout for the advert, per-site URI formats and templates, drafts and revisions, search, relations and the trash. The jobs index shows the reference, applications, openings, location, salary and closing date.

  • Statuses: open, scheduled, closed, disabled
  • Closing dates enforced when the job is read, cron or no cron

Applications are elements too

The inbox is Craft's own element index: sources per stage, sorting, keyword search across everything the candidate wrote, a bulk move-to-stage action, and Craft's exporter. An unread badge sits on the sidebar.

Filters that mean what people mean

Ticking Engineering and Design shows either; ticking Engineering and Part time shows both. OR within a group, AND across groups, with live counts next to every filter. Groups are project config; terms like a new office are content.

JobPosting that validates

An invalid posting fails silently and never appears in Google for Jobs. Hire builds the structured data itself, including both halves of a remote job and employment types checked against Google's fixed vocabulary when the job is saved.

An application form, validated on the server

Name, email, phone, CV and cover letter map onto real columns. Pro adds thirteen question types of your own. A value posted under a handle the form doesn't define is dropped, and a rejected submission comes back with the answers still filled in.

Stages that say what they mean

Each stage is still in the running, hired, or not proceeding, so a job's filled count moves by itself when somebody is hired. Every move, email and first open goes into an append-only history.

  • Pro: your own stages, stage emails, ratings and notes

Emails that reach people

A confirmation to the applicant and a notification to the team, both ordinary Craft system messages. Queued by default, because a slow mail server inside the request looks to the applicant like a form that hangs.

Spam defences that cost the applicant nothing

A honeypot, a signed timestamp and a rate limit run before any CAPTCHA is considered. reCAPTCHA, hCaptcha and Turnstile are available and off by default. Every refusal except the rate limit returns the same message, so a script can't learn which check it failed.

CVs handled like personal data

Uploads are checked by extension and by detected file type, markup files are always refused, and filenames get a random prefix. CVs stream through the control panel behind a permission. Hire never picks a volume for you.

  • Pro: retention that hard-deletes, CV included
  • IP addresses off by default

Your own front end, same results

The built-in listing, craft.hire.results() and the JSON endpoint all make the same call, so a bespoke front end and the supplied one can never disagree. The endpoint is anonymous and CORS-open, and sorting is limited to an allow-list.

bash
GET /hire/jobs.json?department=engineering&jobType=full-time&q=php&page=2

php craft hire/jobs/expire --dry-run          # close jobs past their closing date
php craft hire/applications/export --file=out.csv --job-id=12
php craft hire/applications/prune --days=365 --dry-run

Hire in the control panel

The jobs index, the applications inbox, one application in the pipeline, and the careers page it all feeds.

The Hire jobs index in the Craft control panel, listing each job's reference, status, applications, openings, location, salary and closing date
The Hire applications index, with sources for unread applications and each pipeline stage, and a list of candidates with the job they applied for
A single application in the Hire control panel, showing the candidate's answers and CV, the current stage, and the history of moves and emails
A careers page rendered by craft.hire.listing(), with a search box, filters with counts, and a list of open jobs

Screenshots from a live install, not mockups.

Frequently Asked Questions

Questions worth answering before you install it.

Publish a job, then take the first application

Lite is free, with no cap on jobs or applications. Pro is $99 one-off with a $79/year renewal, and adds your own stages, stage emails, ratings and notes, more forms and questions of your own.