Changelog — JPKCom ACF Jobs

Versionsverlauf des WordPress-Plugins JPKCom ACF Jobs.

Versionsverlauf von jpkcom-acf-jobs. Die Einträge stammen unverändert aus der README des Projekts. Eine ausführliche Anleitung mit Tipps findest du im Projekt-Guide.

1.5.5

  • Fixed: the 1.4.0 release note and the Abilities API section both listed a password-protected job alongside a redirecting one and an expired one, as a job whose detailed fields are withheld. That understated what actually happens. A redirecting or expired job is returned, as a summary, with the reason stated. A password-protected job is not returned at all: query-jobs omits it, list-filters does not count it, and get-job answers with the same message and the same 404 it gives an id that names nothing — deliberately identical, so the abilities cannot be used to work out which post IDs the site holds. Both places have been corrected, and the documentation now also records that the /jobs/ archive and the [jpkcom_acf_jobs_list] shortcode do list such a job, which makes this the one point where the abilities are narrower than the site's own listing. No code is affected — the behaviour was always this; only its description was wrong

1.5.4

  • Added: the updater's four security messages are now translated in all seven languages — German, Spanish, French, Hungarian, Italian and Polish. These are the messages a site owner sees when an update is refused because its checksum does not match or cannot be checked at all, so they are exactly the ones that should not appear in a foreign language
  • Changed: the five translations without a .po — Spanish, French, Hungarian, Italian, Polish — were extended directly in their PHP translation file, the format WordPress loads first and the one they were written in. Their existing entries are untouched, verified entry by entry
  • Hardened: the build check added in 1.5.2 reported entries carrying a context as missing from the compiled catalogue although they were present. It now reads the context the way WordPress stores it

1.5.3

  • Fixed: the note published with 1.5.1 about the Spanish, French, Hungarian, Italian and Polish translations was wrong. It said they existed "only in their compiled form", could not be updated and were frozen. None of that is true. Those five are authored directly as PHP translation files — the format WordPress has loaded first since 6.5, and a supported way to ship a translation, not a by-product of something else. They are maintainable in exactly the way they were written. What is true is narrower: they cover the texts of the earlier releases and have not caught up with the newer ones, which is an ordinary backlog. The note has been corrected and the same wrong assumption removed from the developer documentation
  • Changed: the build check introduced in 1.5.2 no longer treats a PHP translation file containing more than its .po as a failure. That is a legitimate state here — for five of the seven locales the PHP file is the only source. It is now reported as a note, with the warning that regenerating from the .po would delete the difference, which is the mistake 1.5.1 actually made. A translation present in the .po and missing from the PHP file still fails the build, because it means the translation is not being served

1.5.2

  • Fixed: version 1.5.1 removed 27 German translations. They existed only in the compiled translation file and not in the source file it is generated from, so regenerating the source overwrote them — and because WordPress reads the compiled file first, those were the translations actually being shown. Affected were parts of the settings screens and the employment type labels, among others. All 27 are restored and are now in the source file as well, so they can be maintained for the first time. Nothing else changed: no existing translation was altered
  • Hardened: the build now also compares the compiled translation file against its source, in both directions. A translation in the source but not in the compiled file means the build step was skipped; one in the compiled file but not in the source means the source is not the source, and the next regeneration destroys work — which is precisely what happened in 1.5.1. Neither can pass unnoticed again

1.5.1

  • Fixed: the translation catalogue was last generated in October 2025 and had fallen far behind. It listed 64 texts while the abilities file alone contains 129, so every message the abilities return appeared in English on a translated site, and nothing indicated that. The catalogue now covers the whole plugin: 64 entries became 210. The existing German translations are unchanged and one obsolete entry was dropped; the newly listed texts are not translated yet and still appear in English
  • Fixed: an explanatory comment had been placed between the note for translators and the text it describes, which silently detached the two — the note would never have reached a translator. Found by the first run of the regeneration step this release adds
  • Hardened: the build now fails when the catalogue falls behind the code. Regenerating it was neither automated nor on the release checklist, which is how ten months went by without anyone noticing. It is now both
  • Note: the Spanish, French, Hungarian, Italian and Polish translations are maintained directly as PHP translation files, the format WordPress loads first, and have no .po alongside them. They currently cover the texts of the previous releases and are behind the rest. The wording originally published here — that they could not be updated and were frozen — was wrong; see 1.5.3

1.5.0

  • Fixed: jpkcom-acf-jobs/get-job accepted input it does not understand. Sending a parameter the ability never declared — a mistyped name, or a filter that only exists on query-jobs — was answered with a normal, successful response in which that parameter had simply been ignored. The other two abilities refused the same input with a clear error naming what they accept, so a caller that had learned the rule from them had every reason to trust the one ability that did not follow it. get-job now refuses it the same way. This can change what an existing caller sees: a request that sent extra parameters and got an answer will now get an error instead, naming the parameter it rejected and the ones it accepts
  • Changed: the message all three abilities return for an unrecognised parameter is now worded for all of them. It previously explained the danger only in terms of filtering, which does not describe get-job, where the answer is determined by the job ID alone
  • Changed: WordPress 7.0 is now the minimum. Up to 6.9 an unexpected error inside an ability callback ended the whole request with a blank page instead of a readable message, and the plugin carried its own guards against that. From 7.0 WordPress catches it itself. The guards stay in place, but the plugin is no longer tested against 6.9 and no longer claims to run there
  • Hardened: two build checks were added, because the defect above was invisible to a green test suite — every check written for the parameter guard happened to target an ability that had it. One check now asserts that every ability calls the guard at all; the other compares the parameters each ability guards against the parameters it publishes in its schema, so the two cannot drift apart unnoticed
  • Changed: the "no input given" default of list-filters and query-jobs is now written directly as an empty object instead of being produced by a helper. What clients receive is unchanged

1.4.0

  • Added: three read-only WordPress Abilities — jpkcom-acf-jobs/list-filters, jpkcom-acf-jobs/query-jobs and jpkcom-acf-jobs/get-job — so AI assistants, MCP clients and REST automation can read your job listings as structured data instead of scraping the page. They are on by default for logged-in users with the read capability and can be switched off with define( 'JPKCOM_ACFJOBS_ABILITIES', false ); see the Abilities API section above
  • Added: jpkcom_acf_jobs_ability_meta, jpkcom_acf_jobs_ability_capability and jpkcom_acf_jobs_ability_query_args filters, so a site can change which abilities are exposed, who may run them, and what their query contains
  • Added: the abilities return only jobs your site's own listing shows, and withhold salary, address and application details for jobs that have no public detail page — one that redirects to an external application URL, or one that has expired. This entry as originally published also named password-protected jobs here. That was wrong: such a job is not trimmed, it is not returned at all, by any of the three abilities; see 1.5.5
  • Added: includes/jobs-data.php, which now holds the job visibility rule that previously existed as three separate copies — in the [jpkcom_acf_jobs_list] shortcode, in the job archive query, and about to become a fourth. The shortcode and the archive return exactly what they returned before; this was verified by comparing the generated SQL, the returned post IDs and the rendered HTML before and after the change
  • Hardened: a single job whose stored data is corrupt — the usual causes are an import, a migration or a translation copy — no longer takes the whole listing down. It used to make the query answer with a blank server error for every caller, on whichever page that job fell, until someone repaired the data. The job is now left out of the list, the rest of the page answers normally, and the response says how many were left out
  • Hardened: asking for one job whose detail data is unreadable now returns that job's summary with a stated reason instead of claiming the job does not exist — which it did while the listing was showing that same job
  • Fixed: the visibility figures beside the filter list were wrong on any site whose jobs have no expiry date, which is the ordinary case once the date field has been saved and cleared. Every such job was counted as expired while the same response listed it, so the numbers could add up to more jobs than the site has. They are now derived from the listing rule itself and add up exactly
  • Changed: the job query no longer returns a site-wide visibility block beside a filtered result. The figures never changed with the filters, so reading them next to a filtered total suggested jobs that do not exist. They remain on the filter-list ability, where they describe the site
  • Fixed: include_closed — the only switch that changes which jobs come back — could not be sent over the REST route at all, because that route accepts only GET and the parameter demanded a strict true/false. It now accepts the same spellings every other WordPress REST endpoint does
  • Fixed: the filter-list ability published an input description that is not valid JSON Schema, which made strict AI clients reject the tool — and with it the other two, since a client that refuses one entry can refuse the whole list. A later attempt at that fix briefly made any request with an unrecognised parameter answer with a server error, without credentials; both are closed
  • Fixed: a parameter the abilities do not accept — a typo, or a filter sent at the wrong nesting level — used to be ignored silently, so the answer was every job on the site presented as a filtered result. All three abilities now refuse it and name what they accept
  • Fixed: the search description promised to cover job content. It searches titles only, because this plugin stores job text in ACF fields; a search that found nothing was being read as proof that no such job exists. The description now says what it does not reach and points at the filters that do
  • Hardened: if another plugin alters the job query after this one has built it, the abilities now detect that the query which ran is not the query they built and refuse to answer, rather than returning an unfiltered list labelled as a filtered one. What they cannot detect — a plugin that changes only paging, ordering or the search term — is documented rather than implied
  • Added: tools/seed-jobs.php and tools/unseed-jobs.php for creating and removing the edge-case job fixtures a test installation needs
  • Fixed: the source-level guards in tests/test-conventions.php matched only one spelling of the date rule, so gmdate( 'Y-m-d' ) and date( 'Y-m-d', $timestamp ) both slipped past although each carries the timezone bug the rule exists to prevent. They also scanned includes/ alone, and the taxonomy guard could not see the 'taxonomy' => '…' array form. All three gaps are closed
  • Note for developers: reading an ACF wysiwyg field with the default two-argument get_field() runs WordPress's shortcode and oEmbed pipeline, which for a job description containing a bare URL performs an outbound HTTP request and creates a database row. Every long-form field in this plugin is now read unformatted, and a test fails the build if that changes. CLAUDE.md documents this and eleven further traps in detail

1.3.11

  • Fixed: the debug schema template printed an untranslated German sentence after the translated parse-error message; it now prints the translated message alone, escaped with esc_html__()
  • Changed: the update manifest generator now defaults a missing Network: header to false instead of true, matching WordPress' own default. No change for this plugin, which declares Network: true explicitly
  • CI: the lint and guard workflow now also runs on pushes to main. It only covered pull requests, so a direct push with bypass rights skipped every check
  • Changed: comments, workflow step names and CI output across the repository are now English throughout, and the developer notes in CLAUDE.md were translated and trimmed. No effect on the shipped plugin

1.3.10

  • Changed: Tested up to raised to WordPress 7.1
  • Changed: the bundled updater's runtime floor now matches the plugin's own minimum. It bailed out below WordPress 6.8 while the plugin header has required 6.9 for several releases, so the check could never fire on a supported installation
  • Docs: the remaining "WordPress 6.8" requirement statements now say 6.9, matching the plugin header
  • CI: the release manifest's fallback values for requires and tested now say 6.9 and 7.1. They only apply when the README metadata cannot be read, but a stale fallback would have published a minimum the plugin no longer supports

1.3.9

  • Changed: the plugin banners (assets/banner-1544x500.avif, assets/banner-772x250.avif) are now a plain #3c4955 surface with no lettering

1.3.8

  • Fixed: the attributes partial looked terms up under job_attribute, the field name, instead of job-attribute, the registered taxonomy. get_term_by() returned false for every string value and the attribute was dropped from the output with no error anywhere. Not reached with the shipped return_format => 'id', but immediate the moment anything hands that partial strings
  • Fixed: tools/check-term-sync.php could not run at all — a declare(strict_types=1) halfway down the file made the documented wp eval-file invocation a fatal error
  • Fixed: the same script reported every translated post as drifted, because it compared raw meta against wp_get_object_terms(), which WPML rewrites to the current language
  • Added: tests/test-conventions.php compares every literal taxonomy argument against the slugs actually passed to register_taxonomy()
  • Docs: corrected the section on tax_query. None of the three fields the list shortcode filters is taxonomy-backed, so the switch made in jpkcom-acf-references does not apply here

1.3.7

  • Fixed: job expiry was compared against the UTC date. WordPress sets the PHP timezone to UTC, so date( 'Y-m-d' ) returns the UTC day and expired listings stayed visible for the length of the site's UTC offset after local midnight (1–2 hours for Europe/Berlin). shortcodes.php, archive.php and redirects.php now use current_time( 'Y-m-d' ). The date() call in schema.php is deliberately unchanged — it round-trips a stored date string and never refers to "now"
  • Fixed: the single-job redirect checked current_user_can( 'administrator' ), passing a role name where a capability belongs. That works only because the role is a key in the capability array, bypassing map_meta_cap and missing differently named roles with the same rights. Now checks manage_options
  • Added: tools/check-term-sync.php — a read-only checker reporting whether the serialised job_attribute meta values and the real job-attribute term assignments agree. Groundwork for moving the shortcode filters from unindexed meta_query + LIKE to indexed tax_query
  • Added: tests/test-conventions.php — regression guards for both fixes above, precise enough to leave the legitimate schema.php date call alone. Run in CI on every pull request
  • Docs: CLAUDE.md gained the Security & Correctness section it was missing — the only JPKCom plugin without one

1.3.6

  • Security: update packages are now verified before installation — the verified file is handed to WordPress instead of being downloaded a second time, so the bytes that were checked are the bytes that get installed
  • Security: a missing or unfetchable SHA-256 checksum now aborts the update instead of installing unverified code (previously it silently skipped verification)
  • Security: pinned every GitHub Action to a full commit SHA and added Dependabot with a 7-day cooldown, so a moved tag can no longer change the release build
  • Security: tightened which download the updater claims, so sibling plugins cannot match each other's package
  • Fixed: sprintf() calls in the updater bound named arguments to a variadic parameter, which raises ArgumentCountError on PHP 8.3
  • Fixed: the "View Details" modal could fail with a TypeError when the manifest omitted requires_plugins
  • Performance: a failed manifest fetch is now cached for an hour instead of being retried on every admin request
  • Added: CI workflow on every pull request (PHP lint, named-argument check, YAML validation, action-pinning guard)

1.3.5

  • Fixed broken <main> element in the single job template: it was closed immediately after opening, leaving the entire job content outside of it and producing an unmatched closing tag at the end of the template
  • Fixed a leftover duplicate logo call in the job company partial that passed the ACF field array where an attachment ID is expected, which could render an unrelated image before every company logo

1.3.4

  • Raised the minimum WordPress version to 6.9 and "Tested up to" to WordPress 7.0
  • Switched license metadata to the SPDX identifier GPL-2.0-or-later with the HTTPS license URI

1.3.3

  • Security: prevent JSON-LD script-tag breakout (stored XSS) in JobPosting schema output (JSON_HEX_TAG | JSON_HEX_AMP, plus output-point hardening in single-job.php)
  • Security: updater prefers exact match against manifest download_url over the slug heuristic, so a tampered manifest can no longer bypass the checksum gate
  • Security: updater checksum comparison is now timing-safe (hash_equals()) with an is_string() guard against hash_file() failures
  • Security: manifest fetch uses wp_safe_remote_get() (SSRF defense-in-depth)
  • Fixed PHP warning + missing contributor names in the plugin detail popup (display_name now provided)
  • Fixed PHP warning/deprecation on wp plugin list by completing the no_update transient entry (new_version, package, tested, requires_php)

1.3.2

  • Fixed missing output escaping across all templates and debug templates (esc_html__(), esc_html(), esc_url(), esc_attr())
  • Fixed pagination template: added flex-wrap with row-gap-2 for responsive wrapping on small screens
  • Fixed pagination template: empty <li> elements no longer rendered when no previous/next post exists
  • Fixed pagination template: previous/next links now use proper page-link class for consistent Bootstrap styling
  • Fixed pagination template: archive URL now escaped with esc_url()

1.3.1

  • Fixed updater checksum verification failing on manual ZIP uploads (local file path instead of URL)
  • Fixed release ZIP missing top-level directory, causing WordPress to not recognize the update

1.3.0

  • Added archiv redirect options

1.2.5

  • Added translation for "job_type"

1.2.4

  • Added translations for ES, FR, HU, IT and PL

1.2.3

  • Added check for "SitePress" class

1.2.2

  • Fix for incorrect database content caused by WPML

1.2.1

  • Fix for incorrect database content caused by WPML

1.2.0

  • Security enhancement
  • AI support

1.1.12

  • Added WPML support

1.1.11

  • Improvements to jpkcom_acfjobs_textdomain()

1.1.10

  • Updater bugfix

1.1.9

  • "display_name" for update-core.php

1.1.8

  • "display_name" for plugin-install.php

1.1.7

  • New namespace for updater

1.1.6

  • Updater bugfix

1.1.5

  • Plugin icon support

1.1.4

  • Plugin details

1.1.3

  • Updater bugfix

1.1.2

  • Improvements for GitHub workflow

1.1.1

  • Improvements for GitHub workflow

1.1.0

  • Improvements for GitHub workflow

1.0.9

  • Removed plugin dependency

1.0.8

  • Improvements for GitHub workflow
  • Improvements to plugin JSON
  • Updater improvements

1.0.7

  • Improvements for GitHub workflow
  • Bugfix plugin JSON
  • Updater improvements

1.0.6

  • Bugfix for GitHub workflow

1.0.5

  • Bugfix plugin JSON

1.0.4

  • Bugfix for GitHub workflow

1.0.3

  • Updater improvements

1.0.2

  • Bugfix for GitHub workflow

1.0.1

  • GitHub workflow

1.0.0

  • Initial Release