Skip to content

Blueprint-Specific createLabel() Support for Collections and Taxonomies #1448

@joshdaugherty

Description

@joshdaugherty

Statamic\Entries\Collection::createLabel() and Statamic\Taxonomies\Taxonomy::createLabel() currently support a single translation key per collection/taxonomy, but not per blueprint. In real-world editorial workflows, one collection/taxonomy often contains multiple blueprint types, and a generic "Create Entry" / "Create Term" label is less clear than context-specific labels (e.g., "Create News Release Post", "Create Video Post", etc.).

Problem

  • Current behavior only resolves:
    • Collection: one key per collection handle
    • Taxonomy: one key per taxonomy handle
  • Missing behavior: no native blueprint-specific label resolution.
  • Result: users see generic create labels when creating entries/terms for specific blueprints, reducing clarity in multi-blueprint setups.

Requested Enhancement

Update createLabel() in both classes to support a blueprint-aware lookup before existing fallbacks:

  1. If a blueprint context is present (from the current CP request), attempt blueprint-specific key.
  2. If not found, use existing collection/taxonomy-level key.
  3. If still not found, use current generic fallback label.

Proposed implementation for both methods

Statamic\Entries\Collection::createLabel()

    public function createLabel()
    {
        // CHANGED: `messages` becomes `statamic::messages` for consistency with `Taxonomy::createLabel()`
        $key = "statamic::messages.{$this->handle()}_collection_create_entry";

        // NEW: Store the generic fallback once to avoid duplicate translation calls
        $fallbackLabel = __('Create Entry');

        // NEW: Read optional blueprint context from the CP request
        $blueprint = request()->query('blueprint');

        // NEW: Attempt blueprint-specific translation before legacy base behavior.
        // Check whether a blueprint was requested
        if (! empty($blueprint)) {
            // Build the blueprint-specific translation key
            $blueprintKey = "{$key}.{$blueprint}";

            // Resolve the blueprint-specific translation
            $blueprintTranslation = __($blueprintKey);

            // Check if the blueprint translation exists
            if ($blueprintTranslation !== $blueprintKey) {
                // Return the blueprint-specific label
                return $blueprintTranslation;
            }
        }

        $translation = __($key);

        // NEW: Guard non-string translation values before applying original logic
        // Check whether the resolved translation value is a string
        if (! \is_string($translation)) {
            // Return the generic fallback label for non-string configuration values
            return $fallbackLabel;
        }

        if ($translation === $key) {
            // CHANGED: Use the variable instead
            return $fallbackLabel;
        }

        return $translation;
    }

Statamic\Taxonomies\Taxonomy::createLabel()

    public function createLabel()
    {
        $key = "statamic::messages.{$this->handle()}_taxonomy_create_term";

        // NEW: Store the generic fallback once to avoid duplicate translation calls
        $fallbackLabel = __('Create Term');

        // NEW: Read optional blueprint context from the CP request
        $blueprint = request()->query('blueprint');

        // NEW: Attempt blueprint-specific translation before legacy base behavior.
        // Check whether a blueprint was requested
        if (! empty($blueprint)) {
            // Build the blueprint-specific translation key
            $blueprintKey = "{$key}.{$blueprint}";

            // Resolve the blueprint-specific translation
            $blueprintTranslation = __($blueprintKey);

            // Check if the blueprint translation exists
            if ($blueprintTranslation !== $blueprintKey) {
                // Return the blueprint-specific label
                return $blueprintTranslation;
            }
        }

        $translation = __($key);

        // NEW: Guard non-string translation values before applying original logic
        // Check whether the resolved translation value is a string
        if (! \is_string($translation)) {
            // Return the generic fallback label for non-string configuration values
            return $fallbackLabel;
        }

        if ($translation === $key) {
            // CHANGED: Use the variable instead
            return $fallbackLabel;
        }

        return $translation;
    }

This approach keeps existing behavior, adds blueprint-specific support, and handles array-only translation maps without warnings or invalid return types.

Proposed Translation Key Pattern

  • Collection

    • Base: statamic::messages.{collection}_collection_create_entry
    • Blueprint-specific: statamic::messages.{collection}_collection_create_entry.{blueprint}
  • Taxonomy

    • Base: statamic::messages.{taxonomy}_taxonomy_create_term
    • Blueprint-specific: statamic::messages.{taxonomy}_taxonomy_create_term.{blueprint}

Example

For post collection with news_release blueprint:

  • statamic::messages.post_collection_create_entry.news_release = "Create News Release Post"
  • fallback: statamic::messages.post_collection_create_entry = "Create Post"
  • fallback: "Create Entry"

For post_tag taxonomy with clinical blueprint:

  • statamic::messages.post_tag_taxonomy_create_term.clinical = "Create Clinical Tag"
  • fallback: statamic::messages.post_tag_taxonomy_create_term = "Create Tag"
  • fallback: "Create Term"

Concrete language file examples

These are practical examples of how projects currently configure labels for different scenarios.

Scenario A: Collection-level override only

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_collection_create_entry' => 'Create Post',
];

Scenario B: Collection + blueprint-specific overrides

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_collection_create_entry' => 'Create Post',
    'post_collection_create_entry.news_release' => 'Create News Release Post',
    'post_collection_create_entry.video' => 'Create Video Post',
];

Scenario C: Collection with no collection-level fallback (array-only blueprint labels)

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_collection_create_entry' => [
        'news_release' => 'Create News Release Post',
        'video' => 'Create Video Post',
    ],
];

Expected behavior:

  • blueprint=news_release => Create News Release Post
  • blueprint=video => Create Video Post
  • blueprint=post (missing key) => generic fallback Create Entry
  • no blueprint query param => generic fallback Create Entry

Scenario D: Taxonomy-level override only

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_tag_taxonomy_create_term' => 'Create Tag',
];

Scenario E: Taxonomy + blueprint-specific overrides

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_tag_taxonomy_create_term' => 'Create Tag',
    'post_tag_taxonomy_create_term.clinical' => 'Create Clinical Tag',
    'post_tag_taxonomy_create_term.research' => 'Create Research Tag',
];

Scenario F: Taxonomy with no taxonomy-level fallback (array-only blueprint labels)

lang/vendor/statamic/en/messages.php

<?php

return [
    'post_tag_taxonomy_create_term' => [
        'clinical' => 'Create Clinical Tag',
        'research' => 'Create Research Tag',
    ],
];

Expected behavior:

  • blueprint=clinical => Create Clinical Tag
  • blueprint=research => Create Research Tag
  • blueprint=general (missing key) => generic fallback Create Term
  • no blueprint query param => generic fallback Create Term

Expected resolution behavior across scenarios

  • If {base}.{blueprint} exists, return that.
  • Else if {base} exists, return that.
  • Else return the generic fallback (Create Entry / Create Term).
  • For array-only setups (no string {base} value), missing or absent blueprint should also fall back to the generic label.

Benefits

  • Better author/editor UX in multi-blueprint structures.
  • Backward-compatible fallback behavior.
  • Leverages existing translation architecture without requiring UI configuration changes.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions