# Job Expiration

Every job page the plugin renders carries a `validThrough` date in its JobPosting structured data. That date tells Google when the opening stops being current. Get it wrong and Google either drops the listing early or keeps showing a role you filled months ago — and neither is visible from your site, because the date lives in the page source, not on the page.

This page explains where that date comes from, how to change it for one job, and what expiry does *not* do.

## What expiration actually controls

Expiration feeds exactly one thing: the `validThrough` property in the [JSON-LD JobPosting schema](https://loxo.w4dev.com/docs/job-schema-and-seo/) on the single job page.

It does not control visibility. An expired job stays published, stays in the jobs directory, keeps its URL, and still accepts applications. Nothing in the plugin filters listings by expiry date. This is the most common misunderstanding on this page, so it is worth stating plainly: **the expiration date is an SEO signal, not a switch.**

What *does* take a job off your site is its status in Loxo. When a sync sees a status other than **Active** or **Open**, the WordPress post is moved to *pending* and disappears from the front end. See [Synchronizing Jobs](https://loxo.w4dev.com/docs/synchronizing-jobs/).

## Where the date comes from

Two sources, in this order:

1. **The job’s own expiry date.** If the job has one stored, it is used as-is. It gets there either from Loxo — the plugin copies Loxo’s *published end date* on every sync — or from you, by setting it in the admin Jobs list.
2. **Publication date + Default job validity.** Only used when the job has no expiry date of its own.

**Default job validity (in days)** lives under **Loxo Jobs → Settings → SEO Settings** (see [Plugin Settings](https://loxo.w4dev.com/docs/plugin-settings/)). It falls back to **180 days** whenever the field is empty or not a number, so a fresh install behaves as 180 days even before you touch it.

The precedence matters more than it looks. Raising Default job validity changes nothing for any job that already carries a date from Loxo — the setting is only ever consulted for jobs that have none. If your Loxo records all have a published end date, this field is effectively inert.

## Setting a date for one job

1. Go to **Loxo Jobs** in the admin.
2. Find the **Expires** column at the right of the job list.
3. Click the **Change** button next to the date to open the date picker. The date itself is read-only — the button is the way in.
4. Pick a date. It saves immediately, over the REST API; there is no separate save button.

The picker will not offer a date earlier than the job’s publication date. Because the save goes through the REST API it needs a user who can manage options — and it reports nothing back either way, so the date in the field is not by itself proof that the save landed. Reload the page to confirm.

One thing to know about that column: it is never blank. When a job has no stored expiry, the column shows the calculated fallback instead — publication date plus Default job validity. A date in the column therefore does not prove the job has a date of its own.

A hand-set date survives future syncs as long as Loxo has no published end date for that job. If Loxo does have one, the next sync overwrites your date with Loxo’s.

## How this relates to Auto-Extend Expiry

[Auto-Extend Expiry](https://loxo.w4dev.com/docs/auto-extend-expiry/) is a free add-on that keeps every eligible job’s expiry inside a rolling window — by default 90 days ahead — so `validThrough` never drifts into the past on jobs you are still hiring for.

Once it is enabled it owns the date, but it only rewrites dates that fall outside its window. A stored date closer than the renew threshold — 14 days by default — or further out than the interval of 90 days is reset to today plus the interval. A date between those two bounds is left alone, so a hand-set date 30 days out survives, until time carries it into the renew window and the next check moves it.

What it does do on every sync, whether or not the date changes, is discard the published end date arriving from Loxo and write the value it owns instead. So while the add-on is enabled, Loxo’s date no longer reaches the job. If you need one job left out of this entirely, the add-on has a per-job **Do not auto-extend** checkbox.

## Troubleshooting

| Symptom | Cause | Fix |
|---|---|---|
| Raised Default job validity, `validThrough` unchanged | The job already has its own expiry date from Loxo, so the setting is never consulted | Change the published end date in Loxo, set the date in the Expires column, or use Auto-Extend Expiry |
| Date set in the Expires column reverts after a sync | Loxo supplies a published end date for that job and the sync copies it over yours | Clear or correct the date in Loxo itself — that is the source of truth |
| Date set by hand keeps moving on its own | Auto-Extend Expiry is enabled and your date falls outside its window — under 14 days away, or more than 90 days out | Tick **Do not auto-extend** on that job, or turn the add-on off. A date between those bounds is left where you put it |
| Expired job still listed on the site | Expected — expiry only feeds schema | Change the job’s status in Loxo and re-sync |
| Clicking the Expires field does nothing | The field is read-only by design | Use the **Change** button beside it |
| Picked a new date, it reverts on reload | The REST save failed silently — usually a capability or security-plugin block | Sign in as an administrator and check the browser console for a rejected request to `loxo/v1/job-expiration` |

## FAQ

### Does an expired job get deleted or hidden?

No. Nothing happens on your site at all. The date passes, `validThrough` becomes a past date, and Google stops treating the listing as current. The page itself is untouched.

### Can I clear a job’s expiry date so it falls back to the default?

Not from the Expires column — the date picker can only set a date, not empty one. Clearing it means removing the job’s `date_expires` post meta directly, for example with WP-CLI.

### What date format does the schema use?

`YYYY-MM-DD`, in UTC, whichever source the date came from.

## Related documentation

- [Auto-Extend Expiry](https://loxo.w4dev.com/docs/auto-extend-expiry/) — automatically rolls each job’s expiration forward so validThrough stays realistic without manual edits.
- [Job Schema and SEO](https://loxo.w4dev.com/docs/job-schema-and-seo/) — the full JobPosting output that `validThrough` is part of.
- [Plugin Settings](https://loxo.w4dev.com/docs/plugin-settings/) — where Default job validity lives.
- [Synchronizing Jobs](https://loxo.w4dev.com/docs/synchronizing-jobs/) — how job status and dates get updated from Loxo.

Source: https://loxo.w4dev.com/docs/job-expiration/
