Hire
Job listings and applications for Craft CMS 5.
Hire is what WP Job Openings is to WordPress, built the way Craft does things — jobs are real elements, with a field layout, per-site URLs, drafts, revisions, permissions, search, relations and the trash. Applications are elements too, so the inbox is Craft's own element index, with sources, sorting, search, bulk actions and exporting already working.
{{ craft.hire.listing() }}
That is a working careers page — search box, filters, results, pagination — rendered server-side so it works with JavaScript off, is indexable, and every filter is a link you can paste into an email.
{{ craft.hire.applyForm(job) }}
{{ craft.hire.schema(job) }}
That is the application form and the JobPosting structured data Google for Jobs reads.
What you get
Jobs are elements. A field layout for the advert itself, per-site URI formats and templates, drafts and revisions so a job can be written before it is published, element search, relations, the trash, and an index with the columns a careers page wants — reference, applications, openings, location, salary, closing date.
Applications are elements too. Which means the inbox already has sources, sorting, keyword search across everything the candidate wrote, a bulk "move to stage" action, and Craft's own exporter — none of it reimplemented.
Structured data that actually validates. An invalid
JobPostingfails silently: it is not flagged anywhere a site owner looks, it simply never appears in the jobs carousel. Hire builds it rather than leaving it to a template — including the two rules everybody gets wrong, that a remote job needsjobLocationTypeandapplicantLocationRequirements, and thatemploymentTypehas a fixed vocabulary your own wording has to be mapped onto.A form builder. Name, email, phone, CV and cover letter are built in and map onto real columns, because Hire has to be able to email the applicant, spot a duplicate and key a CSV. Everything else is a question of your own — dropdowns, checkboxes, dates, numbers, consent, headings, file uploads — validated on the server, stored as JSON, and read back next to the question that produced it.
A hiring pipeline. Stages you design, each declaring whether it means still in the running, hired, or not proceeding — which is what lets a job's filled count move by itself when somebody is hired, and lets "open applications" be a meaningful filter. Ratings, notes, and an append-only history of who moved whom and when.
Emails that reach people. A confirmation to the applicant and a notification to the hiring side, both editable as ordinary Craft system messages and translatable per site. Per-stage emails, so moving a candidate to "Interview" is what sends the invitation. Everything queued by default, because sending inside the request means a slow mail server presents to the applicant as a form that hangs.
Spam defences that cost an applicant nothing. A honeypot, a signed timestamp, and a rate limit — in that order, before any CAPTCHA is considered. A CAPTCHA is available (reCAPTCHA v2 and v3, hCaptcha, Turnstile) and off by default, because it is a tax on disabled applicants and a third-party script on a page where somebody is typing their employment history.
Uploads that are checked twice. The extension against the site's list, and the file's detected type against the extension — a script renamed
payload.pdfclears the first test and fails the second. Filenames are prefixed with a random token so that two candidates who both called their filecv.pdfcannot download each other's, and CVs are streamed through the control panel rather than linked to directly.A retention policy that actually deletes. Applications past the retention period are hard deleted, CV included — because a policy that leaves the data in the trash is not a policy. IP addresses are off by default. There is an erasure button that erases.
A JSON endpoint at
/hire/jobs.json, anonymous and cacheable, returning exactly what the built-in listing would have shown — same filters, same semantics — so a bespoke front end and the supplied one can never disagree.CSV export with a UTF-8 BOM (so Excel on Windows does not mangle every accented name) and formula injection defused (so a candidate who types
=HYPERLINK(…)into a text box has not written code that runs on the recruiter's machine).
Requirements
- Craft CMS 5.3 or later
- PHP 8.2 or later
To install this plugin, copy the command above to your terminal.
This plugin doesn't have any reviews.








