WP Manifestindependent plugin directory
manifest / unclassified / wp-ks-cases

KS Cases

Cases as a content type, with compatible archives, templates, listings, and a reversible migration from the legacy "cases" category.

★ 0stars

Install

Download source zip No release zip yet

This is the repository archive. It installs, but the folder name will carry the branch suffix and updates will not flow.

Install straight from GitHub with WP-CLI:

wp plugin install https://github.com/kostyasorokin/wp-ks-cases/archive/refs/heads/main.zip
No built-in updater. New versions won't appear under Dashboard → Updates. Install new releases yourself, or let Git Updater track the repository.

Cases as a dedicated WordPress content type. The plugin registers ks_case with separate case categories and tags, keeps individual case addresses at /cases/<name>/, and provides an archive, a single template, card partial, theme API, shortcode, and service CTA.

It also includes an explicit, reversible importer for sites that previously stored cases as ordinary posts in the cases category. Activation never moves content by itself.

Requirements

PHP 8.5 and WordPress 6.7 or newer.

Install and adopt existing cases

  1. Put the directory at wp-content/plugins/ks-cases and activate KS Cases.
  2. Open Cases → Import.
  3. Review the posts found directly in the cases category.
  4. Click Import these cases.

While legacy posts remain, the original category continues to own its archive, so activation cannot replace the live listing with an empty CPT query. Once the import succeeds, cases use /cases/ for the listing and /cases/<name>/ for individual entries. The former /category/cases/ address permanently redirects to /cases/.

The importer changes only wp_posts.post_type, leaving each post ID and its content, author, publication date, featured image, comments, custom fields, and Yoast data in place. It copies meaningful categories and all tags into the case-only vocabularies, records the original term IDs for rollback, then removes the case relationships from the blog taxonomies. Structural blog and cases categories are intentionally not copied.

Before conversion the importer records the old permalink. Old addresses that no longer match the new structure answer with a permanent redirect. When TranslatePress is present, redirects also recognise its known language prefixes.

The same screen can restore everything imported by this tool to ordinary posts, including the exact original blog category and tag relationships. Cases created directly in the new content type are never included in that rollback.

Settings

Cases → Settings stores these options:

Option Default Purpose
ksCasesCaseSlug cases Address of one case
ksCasesArchiveSlug cases Address of the listing
ksCasesSingularName translated “Case” Admin wording
ksCasesPluralName translated “Cases” Admin menu wording
ksCasesArchiveEyebrow translated “Our results” Line above the archive title
ksCasesArchiveTitle plural name Archive heading
ksCasesArchiveSubtitle translated default Archive introduction
ksCasesPerPage 12 Archive page size
ksCasesMenuIcon dashicons-awards Admin menu icon

Address changes schedule one rewrite flush on the next request. Existing URLs are not guessed when settings change; add redirects before changing a live address.

Categories and tags

Cases never share the blog's built-in category and post_tag taxonomies:

  • ks_case_category — hierarchical case categories, with public term URLs at /cases/category/<name>/;
  • ks_case_tag — case tags, with public term URLs at /cases/tag/<name>/.

Both appear under the Cases admin menu, in the case list, block editor, REST API, and public templates. Migrated terms are separate WordPress term records even when their names and slugs match blog terms.

The public archive automatically shows every non-empty case category below its introduction and a complete case-tag cloud after the card listing. The active category is marked for visitors and assistive technology.

Service block

The case edit screen includes a Service block metabox with a heading, a multiline subtitle, and a multiple select populated by ks_service posts. When at least one public service is selected, the plugin appends one custom CTA after the editorial content. Selected services appear as normal links whose labels are their complete post titles; no Gutenberg block markup is stored or rendered.

The heading, subtitle, and ordered service IDs are protected, revisioned post meta. If KS Services is inactive, the selector explains the dependency. If a selected service stops being public, its link is omitted on the front end.

Case team

With KS Team active, the case edit screen shows a Case team checklist. Select everyone who worked on the case and save it. The single case page then shows their names, current job titles, and featured photos from KS Team. Each person links to their profile when KS Team's public member pages are enabled. Unpublished members are omitted from the public case page.

The selected member IDs are protected, revisioned post meta. Deactivating KS Team hides the selector and public cards while preserving the saved selection.

Shortcode and theme API

[ks_cases] lists all published cases newest first. Optional attributes:

[ks_cases limit="6" columns="3"]
[ks_cases category="military-affairs" limit="4" columns="2"]

category is a ks_case_category slug. columns is clamped to 1–4 and limit="0" means all cases. An empty query returns an empty string.

Themes can use KonstantinSorokin\Cases\Helpers\Cases:

  • Cases::all( string $category = '', int $limit = 0 )
  • Cases::card( int $postId )
  • Cases::archiveUrl()
  • Cases::settings()
  • Cases::categories( int $postId )
  • Cases::tags( int $postId )
  • Cases::categoryLinks( int $postId, string $separator = ', ' )
  • Cases::tagLinks( int $postId, string $separator = ', ' )
  • Cases::serviceBlock( int $postId )
  • Cases::teamMembers( int $postId )

Templates and extension points

A classic theme can override the plugin fallbacks with:

  • archive-ks_case.php
  • single-ks_case.php
  • taxonomy-ks_case_category.php
  • taxonomy-ks_case_tag.php
  • taxonomy-ks_case.php
  • ks-cases/case-card.php
  • ks-cases/service-block.php
  • ks-cases/team-members.php

The Kerimov Partners child theme already ships the archive and single templates, preserving the current site design.

Filters:

  • ksCasesPostTypeArgs — all register_post_type() arguments.
  • ksCasesCategoryTaxonomyArgs — all case category taxonomy arguments.
  • ksCasesTagTaxonomyArgs — all case tag taxonomy arguments.
  • ksCasesPerPage — archive page size after reading the setting.
  • ksCasesFallbackTemplate — plugin fallback path and requested theme file.

The stored post type can be overridden as KS_CASES_POST_TYPE in wp-config.php, but only before the first case exists. Changing it later does not move stored rows. Taxonomy constants follow the same rule.

Development

The shipped Composer autoloader contains no third-party packages. Development tools live separately so they cannot leak into production:

composer tools
composer check

The check runs WordPress Coding Standards, PHPStan level 8, and the unit suite.