Skip to content
CoverKit CoverKit v0.1.13

Use cases and output profiles

This document matches the current PHP layer: Use_Case, Use_Case_Registry, Use_Case_Storage, and built-in implementations such as Sandbox_Use_Case and Open_Graph_Image_Use_Case.

TermMeaning
Use-case specAdvisory dimensions (recommended_settings()), settings schema, and mapping sources for the editor.
Open Graph request contextInternal bucket in Open_Graph_Image_Use_Case for eligibility: singular, front_page, or non_singular — not a separate PHP “source context” API.

Field values at render time come from the post (or preview) passed to Field_Resolver::collect_raw(); Open Graph settings (post types, front page, archives) live in the assignment settings object.

  • Use case — Defines schema, mapping sources, and init() hooks (for example wp_head, generation filters).
  • Registry — Stores registered types (slug → label, class, …) and boots active classes from the loader manifest option when coverkit_init runs.
  • Storage — Reads/writes per-template assignments in post meta and rebuilds the loader manifest when that meta changes.
  • RendererRenderer::generate( string $generation_key, $template_id, ?int $post_id = null, array $options = array() ) loads a template, applies field data, and runs the generator. Field wiring is in block attributes / {field} placeholders. Assignments live in template post meta _coverkit_use_cases (Use_Case_Storage::META_KEY).
  1. plugins_loaded priority 1: init() constructs Use_Case_Registry (constructor require_once’s includes/use-cases/bootstrap.php, which schedules coverkit_register_use_case() on coverkit_init at priority 5 only; it does not register immediately).
  2. init priority 15: fire_coverkit_init() runs do_action( 'coverkit_init' ).
  3. coverkit_init priority 5: built-in and plugin code call coverkit_register_use_case() so types exist before boot.
  4. coverkit_init priority 10: Use_Case_Registry::boot() reads the option Use_Case_Registry::LOADER_MANIFEST_OPTION (coverkit_usecases, list of active slugs), resolves each slug’s class from the registry, instantiates once, and calls Use_Case::maybe_init() (which runs init()).
  5. When template meta _coverkit_use_cases changes, Use_Case_Storage::rebuild_loader_manifest() rescans templates and rewrites coverkit_usecases.

Open Graph output is registered from Open_Graph_Image_Use_Case::init() (wp_head), not from the registry class.

PathRole
includes/class-coverkit-use-case.phpAbstract Use_Case.
includes/class-coverkit-use-case-registry.phpUse_Case_Registry singleton; type registration + manifest boot + reset() for tests.
includes/class-coverkit-use-case-storage.phpCanonical _coverkit_use_cases meta, sanitization, loader manifest rebuild.
includes/use-cases/class-coverkit-*-use-case.phpConcrete use cases; autoload: CoverKit\Foo_Bar_Use_Caseincludes/use-cases/class-coverkit-foo-bar-use-case.php.

Autoload rule: in coverkit.php, CoverKit\Use_Cases\Foo_Bar_Use_Caseincludes/use-cases/class-coverkit-foo-bar-use-case.php.

Register on coverkit_init at priority less than 10 so the slug exists before Use_Case_Registry::boot() runs.

Required args: label (string). Optional: class (Use_Case subclass), description, single (bool; install-wide singleton — at most one template site-wide may have active: true for this slug; default false), supports, public, allowed_widths. When class is omitted, the registry assigns a per-slug default subclass of Minimal_Use_Case (base Use_Case behavior only).

add_action(
'coverkit_init',
static function (): void {
\CoverKit\coverkit_register_use_case(
'my_packaging',
array(
'label' => __( 'Packaging shot', 'my-plugin' ),
'description' => __( 'Square catalog image from product data.', 'my-plugin' ),
'class' => \MyPlugin\Packaging_Use_Case::class,
)
);
},
5
);

Label-only registration (no custom PHP class):

\CoverKit\coverkit_register_use_case(
'catalog_thumb',
array(
'label' => __( 'Catalog thumbnail', 'my-plugin' ),
)
);
namespace MyPlugin;
use CoverKit\Use_Case;
final class Packaging_Use_Case extends Use_Case {
/**
* @return array<string, mixed>
*/
protected static function recommended_settings(): array {
return array(
'dimensions' => array( 'width' => 1080, 'height' => 1080 ),
'formats' => array( 'jpg', 'webp' ),
);
}
/**
* @return array<string, array<string, mixed>>
*/
protected static function use_case_settings_schema(): array {
return array(
'format' => array(
'type' => 'string',
'label' => __( 'Format', 'my-plugin' ),
'control' => 'select',
'default' => 'jpg',
'options' => array( 'jpg' => __( 'JPG', 'my-plugin' ) ),
),
);
}
/**
* @return array<string, array<string, mixed>>
*/
protected static function use_case_mapping_sources(): array {
return array(
'post_title' => array( 'required' => true ),
'site_logo' => array( 'recommended' => true ),
);
}
protected function init(): void {
// Optional: \add_action(), \add_filter(), …
}
}

The slug returned by get_slug() comes from the registry entry for your class (the $slug argument to coverkit_register_use_case()).

Boot once, resolve templates at output time

Section titled “Boot once, resolve templates at output time”

Use_Case_Registry::boot() instantiates each active slug once per request and calls maybe_init() (which runs init() at most once per class). Keep init() cheap: register WordPress hooks only. Resolve which templates are active inside those hook callbacks, not during boot.

PatternWhenAPI
First eligibleOne output per request (login background, Open Graph meta)Use_Case::find_active_template_id() or scan templates and apply custom eligibility (post type, archive context, etc.)
All activeOne output per active template (multiple dashboard widgets, admin panels)Use_Case::find_active_template_ids() and loop

Both helpers read published templates with active: true for the use case slug (ascending ID). Use_Case_Storage::find_active_published_templates() backs the list; results are cached per request. Third parties may adjust the list via coverkit_use_case_active_template_ids.

Install-wide singletons (single: true at registration) are enforced when assignments are saved; at most one template should be active site-wide for those slugs.

Example — register one dashboard widget per active template:

protected function init(): void {
\add_action( 'wp_dashboard_setup', array( $this, 'register_dashboard_widgets' ) );
}
public function register_dashboard_widgets(): void {
foreach ( static::find_active_template_ids() as $template_id ) {
$widget_id = 'my_use_case_' . $template_id;
\wp_add_dashboard_widget(
$widget_id,
$this->widget_title_for( $template_id ),
function () use ( $template_id ): void {
$this->render_widget( $template_id );
}
);
}
}

Mapping source catalog (editor field picker)

Section titled “Mapping source catalog (editor field picker)”

Use_Case::get_mapping_sources() builds the list of mappable data sources for the block editor.

  1. Base catalogUse_Case::default_mapping_sources() holds shared built-ins (post fields, site fields, featured image, taxonomies, etc.). Entries are not marked required here so each use case controls requirements.
  2. Per-class delta — Override use_case_mapping_sources() so entries shallow-merge onto an existing id: for each key, array_merge( base[id], delta[id] ) so the delta overrides individual keys (for example required, recommended, label) while keeping base keys such as formatter when the delta omits them.
  3. First-party pruneUse_Case::filter_declared_mapping_sources( $sources ) runs next (default: no-op). Subclasses override it to drop keys from the merged list without registering a WordPress filter when a use case needs a shorter picker.
  4. Public extension — unchanged: coverkit_use_case_mapping_sources and coverkit_use_case_{$slug}_mapping_sources still wrap the result for third-party plugins.

Resolver keys should match Field_Resolver::collect_builtin_raw(); use a 'field' entry in the source definition when the mapping id differs from the resolver key.

  • Class: CoverKit\Use_Cases\Sandbox_Use_Case (file: class-coverkit-sandbox-use-case.php).
  • Editor-only: registers no front-end hooks; exposes every built-in setting control and the full mapping catalog for testing and extension authors.
  • Recommended: 300×300 (square, cropped); JPG and WebP.
  • Mapping delta: post_title required; featured_image, post_link, post_excerpt, author, site_logo recommended.
  • Extensibility: demonstrates per-use-case field formatting via coverkit_use_case_sandbox_format_field_value.
  • Class: CoverKit\Use_Cases\Featured_Image_Use_Case.
  • Registered with 'public' => true so front-end image URLs use the same anonymous access rules as Open Graph (published, viewable posts only).
  • Recommended: canvas-native dimensions (no fixed crop in the output profile); formats png, jpg, gif, webp.
  • Mapping delta: featured_image recommended (original _thumbnail_id attachment is unchanged and can feed mappings).
  • Runtime: Replaces post_thumbnail_html and post_thumbnail_url on the front end when the post matches assignment post_type settings; classic editor meta box and block editor Summary panel show a CoverKit preview via REST (/featured-image/preview/... and /use-case/featured_image/...).
  • Extensibility: coverkit_featured_image_template_id, coverkit_featured_image_url, coverkit_featured_image_html_enabled.
  • Class: CoverKit\Use_Cases\Open_Graph_Image_Use_Case (file: class-coverkit-open-graph-image-use-case.php). Slug must stay aligned with REST and Renderer callers using the opengraph generation key.
  • Recommended: 1200×630 (1.91:1), formats include png, jpg, gif, webp.
  • Mapping delta: post_title required; post_excerpt, author, site_logo, featured_image recommended.
  • Runtime: On wp_head, prints one og:image block for the first eligible published template in ascending ID order. Eligibility uses assignment settings: non-empty post_type list for singular views, apply_front_page for the front page, apply_non_singular for archives/search (see class docblocks). Image URL uses the public use-case REST shape coverkit/v1/use-case/opengraph/{template_id}/{post_id}.{ext} ('public' => true in includes/use-cases/bootstrap.php).
  • Extensibility: coverkit_opengraph_meta_enabled, coverkit_opengraph_request_post_id, coverkit_opengraph_template_id. Third-party SEO plugin integration is deferred and should be added only inside this class when implemented (see init() docblock).

Per template, post meta _coverkit_use_cases (Use_Case_Storage::META_KEY) is an object map: use case id → assignment (active, settings, mappings, …). When assignments change, Use_Case_Storage::rebuild_loader_manifest() rebuilds coverkit_usecases so the registry can boot each active use case class once per request.

Optional summary meta _coverkit_active_use_cases (Use_Case_Storage::SUMMARY_META_KEY) stores a slug list for editor/debug reads.