Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Statamic Jobs Laravel Package

jonassiewertsen/statamic-jobs

A Statamic addon for adding job listings to your site. Manage job openings as content in the control panel and display them on the front end with ready-made templates, making it easy to build a careers or vacancies section without custom code.

View on GitHub
Deep Wiki
Context7

Getting Started

jonassiewertsen/statamic-jobs is a Statamic addon that layers job-posting functionality (listing, detail pages, closing dates, and an application flow) on top of a Statamic collection, so editors manage openings in the Control Panel while you render them with Antlers or Blade.

Install and upgrade constraints (v1.5.0):

composer require jonassiewertsen/statamic-jobs
  • v1.5.0 adds Statamic 5 and Laravel 11 support. That means PHP 8.2+ and statamic/cms: ^5.0.
  • If you are still on Statamic 4 / Laravel 10 / PHP 8.1, stay on ^1.4 and do not let the constraint float to ^1.5.

Where to look first:

  1. The README — it's the authoritative source for the tag names and the expected collection handle, which have historically been the two things people get wrong.
  2. config/statamic/jobs.php (publish it with php artisan vendor:publish) — routes, collection handle, mail/notification target.
  3. vendor/jonassiewertsen/statamic-jobs/resources/views — the templates you'll almost certainly want to publish and restyle.
  4. vendor/jonassiewertsen/statamic-jobs/src/Tags — the Antlers tags available to you, and the fastest way to see what arguments are actually supported versus what the docs imply.

First use case: get a /jobs index and a /jobs/{slug} detail page rendering from real content before touching the application form. Create or seed the jobs collection, add two or three entries with a closing date, publish the views, and render the listing in an Antlers template. Once content flows end-to-end, wire up the application submission — that's the part with the most integration surface (validation, mail, spam) and the part most likely to need custom work anyway.

Implementation Patterns

Treat the addon as a content layer, not a controller layer. The durable pattern is: jobs live in a Statamic collection with a blueprint you control; the addon supplies the routes and the listing/detail rendering; anything bespoke (filters, salary bands, departments) is a field in the blueprint plus a query scope in your own template or a small custom tag. This keeps you out of the addon's internals and makes upgrades like v1.5.0 a non-event.

Listing with filters via Antlers:

{{ jobs limit="10" sort="date:desc" }}
  {{ if is_open }}
    <a href="{{ url }}">{{ title }}</a>
    <time datetime="{{ closing_date }}">{{ closing_date format="j M Y" }}</time>
  {{ /if }}
{{ /jobs }}

Prefer the addon's own "open/closed" logic over hand-rolled date comparisons — closing-date semantics (end of day, timezone) are exactly the kind of thing that silently drifts when you reimplement it.

Detail pages: either let the addon own the route, or disable its routing in config and use a standard Statamic route:

Route::statamic('jobs/{slug}', 'jobs.show', ['layout' => 'layout']);

The second option is usually better in an existing site — you inherit your layout, SEO partials, and static caching behaviour instead of fighting a package-provided view.

Application form: keep the submission handling in your app, not the addon. A FormRequest for validation, a queued Mailable or Notification for delivery, and a redirect back with a flash message. If the addon ships a submission endpoint, use it as the starting point and then move to your own route as soon as you need custom fields, file uploads (CV), or CRM forwarding.

public function store(JobApplicationRequest $request, Entry $job)
{
    Notification::route('mail', config('statamic.jobs.application_to'))
        ->notify(new JobApplicationReceived($job, $request->validated()));

    return back()->with('success', __('Application received.'));
}

Blade-first teams: call the tag from PHP rather than duplicating markup — Statamic::tag('jobs')->limit(10)->fetch() — then @foreach as normal.

Expiry and archiving: drive closing dates from the entry's own date field and let the addon decide visibility. For anything scheduled, add a small command or use Statamic's scheduler to unpublish stale entries; don't rely on the front-end if alone, since closed jobs remain publicly reachable by URL.

Multisite: scope the listing by site explicitly and give each site its own collection tree if the copy differs. Shared job entries across locales work, but the application email target is site-agnostic in config — resolve it per-site in your notification, not from a single global env var.

Testing: assert on the rendered output of the listing tag and on your own submission route. The latter is the valuable one; if you swap the addon out later, those tests survive.

Gotchas and Tips

v1.5.0 is a compatibility release, not a feature release. There is no new API to learn — the entire risk surface is the dependency bump. The practical consequences:

  • composer update on a Statamic 4 project will not pull v1.5.0 (good), but a fresh install on a new Statamic 5 project will, so your CI matrix needs to cover the new PHP 8.2 / Laravel 11 baseline.
  • Any view overrides you published from v1.4.x are now stale relative to the addon's own templates. Diff them. Published views are copies — they do not receive fixes from later addon versions, which is the single most common source of "the update didn't change anything" confusion.
  • Run the full upgrade in a branch: composer update, php artisan statamic:stache:clear, php artisan view:clear, then click through listing → detail → application submission. Statamic 5's upgrade touches more than this addon, so isolate whether a break is yours or the addon's.

Route conflicts. Statamic's catch-all route will swallow /jobs/{slug} if your route is registered after it. Register custom job routes in a service provider's boot() before Statamic's, or use Route::statamic() and let the addon handle it.

Caching will bite you. Wrapping the listing in {{ cache }} is a big win on job boards, but entries changing in the CP won't invalidate a raw {{ cache }} block. Use Statamic's static caching with invalidation on save, or accept a short TTL and document it. Symptom: "I unpublished a job and it's still live" — almost always cache, not the addon.

Empty state is a real state. A board with zero open jobs still renders the listing; ship an {{ if no_results }} branch or you'll ship a blank page to production. Same for a job with no closing date.

Email is the fragile part. The application flow depends on your mail config, not the package's. Queue the notification (a slow SMTP handshake on a synchronous request looks exactly like a broken form to the user), set MAIL_FROM_ADDRESS to a domain you actually control, and check spam on first deploy. Also add a honeypot or rate limiter — public application forms attract bots within days.

Debugging order: php artisan statamic:stache:clear → check the collection handle matches config → confirm the entry is published and the date window is open → dump Statamic::tag('jobs')->fetch() in tinker to separate "no data" from "no rendering". Reaching for the addon's source is usually the last step, not the first.

Extension points worth knowing: the published config (collection handle, route prefix, mail target), the published views (your primary customisation surface), entry lifecycle events if you need to sync postings to an external ATS, and your own custom tag if the built-in query arguments stop being enough.

Version pinning advice: pin ^1.4 explicitly in any project that hasn't finished the Statamic 5 upgrade. Composer will resolve correctly today, but an unrelated composer update on a dependency that widens its own constraints can drag you across the boundary at the worst possible moment.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
shitoudev/permissionmanager