viget / viget-post-type-taxonomy-sync
Keeps selected post types and taxonomies in sync, storing related IDs in post and term meta.
Package info
github.com/vigetlabs/viget-post-type-taxonomy-sync
Type:wordpress-plugin
pkg:composer/viget/viget-post-type-taxonomy-sync
Requires
- composer/installers: ^1.0 || ^2.0
Requires (Dev)
- phpunit/phpunit: ^9.6
- yoast/phpunit-polyfills: ^4.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
- dev-main
- v2.2.0
- v2.1.1
- v2.1.0
- v2.0.2
- v2.0.1
- dev-bd/hide-add-new-on-tagged-post-types
- dev-bd/registered-mapping-status
- dev-bd/one-to-many
- dev-bd/remove-notice
- dev-bd/scope-add-new-term
- dev-bd/registered-mappings
- dev-mh/registered-mappings
- dev-bd/nvmrc
- dev-bd/gitattributes-generated
- dev-bd/changelog-2.0.2-fix
- dev-bd/release-2.0.2
- dev-bd/dependabot-config
- dev-fix/adopt-existing-term-on-conflict
- dev-bd/dependency-updates
- dev-feature/source-of-truth
- dev-feature/auto-create-taxonomy
- dev-fix/register-hooks-before-cpt-registration
- dev-fix/wp-env-plugin-path
- dev-fix/ci-workflow
This package is auto-updated.
Last update: 2026-11-03 16:03:42 UTC
README
Viget Post Type Taxonomy Sync
Keeps a post type and a taxonomy in sync automatically: publish a post and a matching term is created (and kept up to date); create or edit a term and the matching post follows along. Handy when a taxonomy needs to double as a lightweight, linkable "profile" for a post — e.g. syncing a product post type to a product-line taxonomy so other content can be tagged with a product without duplicating its data.
Features
- Define any number of post type ↔ taxonomy mappings from Settings → Post/Tax Sync, including several taxonomies for one post type, or register them in code with the
vgptts_registered_mappingsfilter. Registered mappings show on the settings page as locked rows that can be synced but not changed. - Automatically creates, updates, and deletes the paired term/post when either side is saved or deleted.
- Keeps a trashed or unpublished post's term and relationships, hidden from the editor and related lookups, until the post is deleted permanently.
- Syncs hierarchy: when both the post type and taxonomy are hierarchical, parent/child relationships are mirrored too.
- A manual "Sync" action per mapping backfills missing terms/posts and removes orphaned ones.
- Hides the auto-managed taxonomy's term-management UI (submenu, "Add New Term" controls, block editor panel) so editors don't edit synced terms directly.
- Excludes a post's own synced term from its taxonomy picker, so a post can't be tagged with itself.
- A small set of filters for customizing behavior without forking, and a read-only REST API for fetching synced relationships — see docs/api.md.
- Checks for updates from GitHub releases directly in the WordPress dashboard.
Installation
Manual
- Download the latest release zip.
- Upload it via Plugins → Add New → Upload Plugin, or extract it to
wp-content/plugins/viget-post-type-taxonomy-sync/. - Activate the plugin.
Composer
composer require viget/viget-post-type-taxonomy-sync
Requires composer/installers (installed automatically as a dependency) to place the plugin in wp-content/plugins/.
Usage
- Go to Settings → Post/Tax Sync.
- Add a mapping between a post type and a taxonomy, then save.
- Publishing a post of that type creates/updates a term of that taxonomy with a matching name and slug (and vice versa).
- Use the row's Sync button at any point to backfill existing content or clean up orphaned terms/posts for that mapping.
A post type can sync to several taxonomies, each with its own Sync row. A taxonomy syncs to one post type, so a second mapping for a taxonomy that's already mapped isn't saved. If both the post type and taxonomy are hierarchical, parent/child structure is mirrored automatically.
Auto-Updates
This plugin checks GitHub releases every 12 hours and surfaces available updates directly in Plugins in wp-admin — no wordpress.org listing required. See includes/class-github-plugin-updater.php.
Note: shipping a custom update checker is intentionally incompatible with wordpress.org's plugin directory (the Plugin Check tool flags it as a hard error under plugin_updater_detected). If this plugin is ever submitted there, the updater would need to be removed first.
Developer API
Public methods, filters, and REST API routes are documented in docs/api.md.
Development
npm install # install JS build tooling npm run start # watch mode npm run build # production build (writes to build/, which is committed) npm run lint:js # eslint npm run lint:css # stylelint composer install # PHP dependencies (composer/installers)
Local WordPress environment
npm run env:start # boots WordPress + this plugin via @wordpress/env (requires Docker)
npm run env:stop
Tests
PHPUnit tests run against a real WordPress install via @wordpress/env's tests-wordpress/tests-cli services (WP core's test suite is downloaded automatically the first time it's needed):
npm run env:start # only needed once per session composer install # installs phpunit + yoast/phpunit-polyfills npm test
The suite covers Core, Settings, Sync (including regression tests for two WordPress-core hook-signature bugs fixed in 2.0.0 — see the changelog), one post type syncing to several taxonomies, the data upgrade, Admin, the REST API, and the GitHub updater (with mocked HTTP responses). Run it as multisite with npx wp-env run tests-cli --env-cwd=wp-content/plugins/viget-post-type-taxonomy-sync -- env WP_MULTISITE=1 vendor/bin/phpunit.
Releasing a new version
Write the changelog entry first. Add a = X.Y.Z = section at the top of the Changelog in readme.txt for the version you're about to cut. The release command refuses to run without it.
Then:
npm run release -- patch # or: minor | major
This bumps package.json, syncs the version into the plugin header/constant and readme.txt (see bin/sync-version.js), commits, tags vX.Y.Z, and pushes. Pushing the tag triggers .github/workflows/release.yaml, which builds the plugin zip and publishes a GitHub release.
Never edit the version by hand. Four places have to agree - package.json, the plugin header, VGPTTS_PLUGIN_VERSION, and readme.txt's Stable tag - and the script is what keeps them that way.
If the changelog entry is missing you'll get:
readme.txt has no changelog entry for 2.1.0.
Add a "= 2.1.0 =" section under "== Changelog ==" describing this release, then re-run.
Nothing is written when that happens, so add the entry and re-run. npm version has already bumped package.json by then, so either amend it or let the re-run carry it.
Changelog
See readme.txt for the full version history.