Skip to content
VakanssiDocs
VakanssiDocs
Get Vakanssi
esc

Import jobs from a CSV

Bulk-create job listings from a spreadsheet by uploading a CSV, mapping its columns to Vakanssi's job fields, and importing, with a downloadable template to start from.

On this page(5)

Got a spreadsheet of open roles, maybe exported from another system or built by hand? The Import jobs (CSV) card under Hiring, then Tools, then Import turns it into real job listings in a few clicks: upload the file, tell Vakanssi which column is which, preview the result, and import. It only creates jobs; nothing else on your site is touched.

Migrating from another hiring plugin instead?

This page is for a plain spreadsheet. If your jobs and applications live in WP Job Openings, Simple Job Board, or WP Job Manager, use the dedicated Import tool instead, which brings across applications and CVs too.

Finding the screen

The CSV importer sits on the same screen as the migration importer: Hiring, then Tools, then the Import tab, in a card called Import jobs (CSV). The Tools screen opens only for administrators and the HR / Compliance role (see Roles & permissions).

Running an import

  1. Click Hiring, then Tools, then the Import tab, and find the Import jobs (CSV) card.
  2. Not sure of the format? Click Download the template for a ready-made CSV with the right columns and two example rows to copy.
  3. Choose your CSV file and click Upload & map columns.
  4. On the mapping screen, check each column’s dropdown. Vakanssi auto-matches common header names (like “Job title” or “Pay period”), but you can re-map anything by hand. A preview table below shows the first 10 rows so you can sanity-check the match.
  5. Tick Publish jobs immediately if you want the roles to go live right away. Leave it unticked to import them as drafts you review and publish yourself.
  6. Leave Skip rows that match a job you already have (same title and location) ticked, which it is by default, so re-running a file never doubles your board. If the preview finds rows that already exist, it tells you how many (in a file longer than 200 rows, how many of the first 200). Untick it only when you deliberately want a row imported again.
  7. Click Import jobs. The screen shows progress and keeps going in small batches on its own until it is done, then reports how many jobs were created and how many rows were skipped, with a line-by-line log.
Step 4, the mapping screen. A file that uses the template's headers matches itself; anything unrecognized starts on Skip this column.

What each column means

Build your own file with a header row using any of these column names, or start from the downloadable template:

ColumnRequiredNotes
TitleYesRows with no title are skipped, not imported.
DescriptionNoBasic HTML is kept; everything else is stripped.
DepartmentNoCreated as a Department term if it doesn’t already exist.
LocationNoCreated as a Location term if it doesn’t already exist. Vakanssi tries to detect a country from the text; if it can’t (a plain city name, or “Remote”), the import log flags it once per batch, since Google for Jobs needs a country to list the job.
TypeNoEmployment type, see accepted values below. Unrecognized values are left blank, not rejected.
SalaryNoThe amount. Needs a valid Currency to be saved; a second “Salary max” column makes it a range, or one cell can hold a range itself (“50000-70000” or “50000 to 70000”). A “k” suffix is read as thousands (“50k” becomes 50,000). A value of 0 is treated as “not disclosed” and left off rather than published as a zero salary.
CurrencyNoRequired alongside Salary, see format below.
UnitNoThe pay period, see accepted values below.
Apply URLNoA URL or an email address (stored as a mailto: link). Anything else is left blank.
RemoteNoWorkplace type, see accepted values below.
ExpiryNoThe date the listing closes. Unparseable dates are left blank.

Accepted values

  • Type: Full Time, Part Time, Contract (or Contractor / Freelance), Temporary (or Temp), Internship (or Intern), Volunteer, Per Diem, or Other. Matching ignores case and spacing.
  • Currency: a 3-letter ISO code (USD, EUR, GBP, and so on). A Salary value without a valid currency is dropped rather than guessed, the same rule the other importer uses.
  • Unit: HOUR, DAY, WEEK, MONTH, or YEAR. Anything else is left blank.
  • Remote: remote, hybrid, or onsite (also accepts yes / no as shorthand for remote / onsite).
  • Expiry: any date format PHP’s strtotime() understands (for example 2026-12-31 or December 31, 2026); it is normalized and stored as YYYY-MM-DD.

Good to know

  • Your upload is kept for a day. If you pause partway through mapping columns, come back within 24 hours and your file and column choices are still there; the mapping screen shows exactly when it expires. After that, you need to upload the file again.
  • Create-only. The importer never edits an existing job in place. It does match each row against the jobs you already have, on title plus location (the same title at a different location counts as a genuinely different opening), and reports every match in the log.
  • Duplicate protection. By default the Skip rows that match a job you already have box is ticked, so re-running the same file changes nothing; untick it and a match is imported again as a separate job.
  • File limits. The file must end in .csv, be plain text, and be no larger than 5 MB. Anything else is refused with a short message saying why.
  • 2000-row cap. Files are truncated at 2000 data rows, and the screen flags it when that happens. Split larger files if you hit the limit.
  • One import at a time. Rows are imported 25 per batch, and only one batch runs on the site at once. If someone else is importing, or you start a second run in another tab, Vakanssi says another import batch is already running; wait, then try again.
  • Jobs only. This importer creates job listings, it does not touch applications, candidates, or any other data. To also migrate applications from another plugin, use the Import tool instead.
  • Imported jobs are created as drafts unless you tick Publish jobs immediately on the mapping step.

For developers: changing the limits

The size cap, the row cap, and the batch size come from three internal tuning filters, not part of the public hook contract: vakanssi/csv_import/max_bytes (5 MB), vakanssi/csv_import/max_rows (2000), and vakanssi/csv_import/batch_size (25). See Hooks.