WP Manifestindependent plugin directory
manifest / content / viget-post-type-taxonomy-sync

Viget Post Type Taxonomy Sync WP Registry grade B. Medium-severity findings · 1 findingWP RegistryMedium-severity findings · 1 findingOpen the reportB

A WordPress plugin that keeps selected post types and taxonomies in sync, storing related IDs in post and term meta.

★ 0stars
9release downloads
695composer installs
v2.1.1latest · 17d ago

Install

Download viget-post-type-taxonomy-sync.zip From the v2.1.1 release on GitHub, Oct 6, 2026

Upload it under Plugins → Add New Plugin → Upload Plugin, then activate.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/vigetlabs/viget-post-type-taxonomy-sync/releases/download/v2.1.1/viget-post-type-taxonomy-sync.zip

On Packagist as viget/viget-post-type-taxonomy-sync:

composer require viget/viget-post-type-taxonomy-sync
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

WordPress 5.9+ PHP 8.2+ Latest release CI status License

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.
  • Automatically creates, updates, and deletes the paired term/post when either side is saved or deleted.
  • 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

  1. Download the latest release zip.
  2. Upload it via Plugins → Add New → Upload Plugin, or extract it to wp-content/plugins/viget-post-type-taxonomy-sync/.
  3. 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

  1. Go to Settings → Post/Tax Sync.
  2. Add a mapping between a post type and a taxonomy, then save.
  3. Publishing a post of that type creates/updates a term of that taxonomy with a matching name and slug (and vice versa).
  4. Use the row's Sync button at any point to backfill existing content or clean up orphaned terms/posts for that mapping.

Only one taxonomy can be mapped per post type (and vice versa). 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), Admin, the REST API, and the GitHub updater (with mocked HTTP responses).

Releasing a new version

Versioning, tagging, and publishing are handled by one command:

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.

Changelog

See readme.txt for the full version history.

License

GPL-2.0-or-later

Releases

4 releases. Each count is every asset in that release; expand a row for the breakdown.

Tag
Published
Assets
Downloads
v2.1.1 latest
Oct 6, 2026 17d ago
viget-post-type-taxonomy-sync.zip
3
Oct 2, 2026 20d ago
viget-post-type-taxonomy-sync.zip
3
Sep 23, 2026 29d ago
viget-post-type-taxonomy-sync.zip
2
Aug 4, 2026 2mo ago
viget-post-type-taxonomy-sync.zip
1
B grade

Security

Viget Post Type Taxonomy Sync 2.1.1 · audited by WP Registry

Medium-severity findings.

1 medium
Audited release
2.1.1
Findings
1
Worst severity
medium
Content hash
6f1b93e5d604ca63a22ca04d…

Findings

  • medium Sync creates, renames, and deletes the paired post or term without that object's capability

    missing_capability

    Settings → Post/Tax Sync (manage_options) can map any public post type to any public taxonomy, including Posts→Categories or Tags→Pages. After that, Sync::handle_post_save and upsert_term_for_post run on save_post for every published post of the mapped type and call wp_update_term / wp_insert_term with the post title and slug. wp_insert_term does not check edit_terms, and on a term_exists collision the handler adopts an unowned term (no _vgptts_post_id, which is every pre-existing category) and then renames its name and slug to the post. handle_post_delete then wp_delete_term's that term when the user deletes the post, without delete_terms. An Author, who has publish_posts and delete of their own posts but not manage_categories, can therefore create a category, take over and rename an existing category by publishing a post with the same title, and delete that category by deleting the post. In the other direction, saved_term → handle_term_save calls wp_insert_post with post_status publish (and wp_update_post on later term edits) without the paired post type's publish_posts or edit_post capability. An Author who types a new tag while saving a post hits wp_set_object_terms → wp_insert_term with no extra cap, so a Tags→Pages mapping publishes a Page they cannot otherwise publish. pre_delete_term → handle_term_delete calls wp_delete_post( $post_id, true ), permanently deleting the paired post with no delete_post check, including posts the term editor cannot delete when the post type's caps are stricter than the taxonomy's delete_terms cap. Subscribers, customers, and logged-out visitors cannot fire these hooks. The manual Sync and Remove AJAX actions are not affected: both use check_ajax_referer and current_user_can( 'manage_options' ), and the nonces are only printed on the manage_options settings screen.

    includes/class-sync.php:183-404

    Recommendation

    Before writing the paired object, require the capability that object demands: edit_terms or delete_terms on the taxonomy, and publish_posts, edit_post, or delete_post on the post type. Do not adopt a pre-existing term unless the current user can edit it, and do not force-delete a post the current user cannot delete. The manage_options bulk sync action can keep its administrator bypass.

WP Registry hashes the installable build and reports on that exact bytes-for-bytes copy. Embargoed findings are withheld until they are disclosed, so a clean verdict means nothing public is outstanding. WP Manifest does not audit code itself.