Contensio logo

API filter hooks

Filter hooks that let plugins modify the public JSON API response — add fields, remove data, or reshape the output.

Since 1.4.0

These filter hooks run inside the public JSON API (/api/v1/content/…). Use them to add custom fields, remove sensitive data, or reshape the response — without touching core or subclassing the API controller.

See the JSON API reference for the full endpoint documentation.


contensio/api/content-item

Type: Filter
Since: 1.4.0
Source: ContentApiController::formatContent()

Runs on every item in the API response — both the paginated list (GET /api/v1/content/{type}) and the single-entry endpoint (GET /api/v1/content/{type}/{slug}).

The filter receives the fully assembled array for one entry and the corresponding Content model. Return the array — modified or unchanged.

Signature

add_filter('contensio/api/content-item', function (array $data, Content $content): array {
    // modify $data
    return $data;
}, priority: 10);

Arguments

# Name Type Description
1 $data array The default response array for this entry (see shape below).
2 $content Content The full Eloquent model with relations.

Default response shape

[
    'id'               => int,
    'status'           => string,        // 'published'
    'published_at'     => string|null,   // ISO 8601
    'created_at'       => string,        // ISO 8601
    'author'           => ['id' => int, 'name' => string] | null,
    'title'            => string|null,
    'slug'             => string|null,
    'excerpt'          => string|null,
    'meta_title'       => string|null,
    'meta_description' => string|null,
    'featured_image'   => [
        'url'       => string,
        'thumbnail' => string,
        'medium'    => string,
    ] | null,
    'terms'            => [
        ['id' => int, 'name' => string, 'slug' => string],
        // ...
    ],
]

Example — add a custom field to every response

use Contensio\Models\Content;

add_filter('contensio/api/content-item', function (array $data, Content $content): array {
    $data['reading_time'] = max(1, (int) ceil(
        str_word_count(strip_tags($data['excerpt'] ?? '')) / 200
    ));
    return $data;
});

Example — expose a custom field value

add_filter('contensio/api/content-item', function (array $data, Content $content): array {
    $data['price'] = $content->field('price');
    return $data;
});

Example — strip a field for unauthenticated consumers

add_filter('contensio/api/content-item', function (array $data, Content $content): array {
    if (! request()->hasHeader('X-Api-Key')) {
        unset($data['meta_title'], $data['meta_description']);
    }
    return $data;
});

Example — add a sponsored badge based on taxonomy

add_filter('contensio/api/content-item', function (array $data, Content $content): array {
    $isSponsor = $content->terms->contains(fn ($t) =>
        $t->translations->first()?->slug === 'sponsored'
    );
    $data['sponsored'] = $isSponsor;
    return $data;
});

Notes

  • Always return the array. A filter that returns null replaces the entire item with null in the response.
  • The filter runs on every item in a list response — keep callbacks fast. Cache expensive lookups if needed.
  • The $content model has translations, author, terms, featuredImage, and fieldValues eager-loaded. Accessing any other relation will trigger an additional query per item.
  • Multiple plugins can register for this filter. They run in priority order, each receiving the output of the previous. The final array is what the API returns.

See also