Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Spatie Content Api Laravel Package

spatie/spatie-content-api

Laravel/PHP package powering Spatie’s promotional-site content API. Fetch posts for a product or project (e.g., mailcoach) via a simple ContentApi facade and expose consistent, reusable content to your frontend or other services.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require spatie/content-api
    

    Publish the config file:

    php artisan vendor:publish --provider="Spatie\ContentApi\ContentApiServiceProvider" --tag="content-api-config"
    
  2. Define a Content Type: Create a migration for your content type (e.g., Product):

    php artisan make:migration create_products_table
    

    Add fields like title, description, slug, and published_at (timestamps). Run:

    php artisan migrate
    
  3. Register the Content Type: In config/content-api.php, add your content type under content_types:

    'products' => [
        'model' => \App\Models\Product::class,
        'fields' => [
            'title', 'description', 'slug', 'published_at',
        ],
        'sortable_fields' => ['title', 'published_at'],
        'filterable_fields' => ['title', 'published_at'],
    ],
    
  4. First API Request: Fetch all products via:

    GET /api/products
    

    Or filter/sort:

    GET /api/products?filter[title]=Laptop&sort=-published_at
    

First Use Case: CMS-Driven Product Pages

  • Use the API to fetch product data dynamically for promotional pages.
  • Example: Fetch a single product by slug:
    $product = \Spatie\ContentApi\Facades\ContentApi::get('products', 'laptop-pro');
    
  • Render the data in a Blade template or frontend framework.

Implementation Patterns

Workflows

1. Content Management

  • Create/Update Content: Use Laravel’s built-in HTTP methods or a frontend form to POST/PUT to /api/products. Example payload:

    {
        "title": "Premium Laptop",
        "description": "High-performance laptop...",
        "slug": "premium-laptop",
        "published_at": "2025-10-15T00:00:00"
    }
    

    Validate requests with Laravel’s validation or custom rules.

  • Soft Deletes: Enable soft deletes in your model (use \Illuminate\Database\Eloquent\SoftDeletes;). The API will automatically exclude soft-deleted records unless with_trashed is passed as a query parameter.

2. API Integration

  • Frontend Consumption: Fetch data in JavaScript (e.g., React/Vue) using axios or fetch:

    axios.get('/api/products?filter[slug]=laptop-pro')
         .then(response => console.log(response.data));
    

    Cache responses with Laravel’s cache middleware or a CDN.

  • GraphQL Layer: Wrap the API in a GraphQL schema (e.g., using spatie/laravel-graphql) for flexible queries:

    query {
      products(filter: { slug: "laptop-pro" }) {
        title
        description
      }
    }
    

3. Localization

  • Multi-Language Support: Extend the fields array in config/content-api.php to include localized fields:

    'products' => [
        'fields' => [
            'title_en', 'title_nl', 'description_en', 'description_nl',
        ],
        'localizable_fields' => ['title', 'description'],
    ],
    

    Use a package like spatie/laravel-translatable for seamless localization.

  • Route-Based Localization: Prefix routes with locale (e.g., /en/api/products) using middleware like spatie/laravel-localization.

4. Media Handling

  • Attach Media: Use Laravel’s spatie/laravel-medialibrary to attach images/videos to content models. Add a media field to your content type config:
    'products' => [
        'fields' => ['title', 'description', 'media'],
    ],
    
    The API will automatically serialize media URLs.

Integration Tips

Laravel Ecosystem

  • Events: Listen to Spatie\ContentApi\Events\ContentSaved or ContentDeleted to trigger side effects (e.g., notifications, analytics):

    \Event::listen(\Spatie\ContentApi\Events\ContentSaved::class, function ($event) {
        Log::info("Product saved: {$event->content->title}");
    });
    
  • Policies: Apply Laravel’s authorization to restrict API access:

    class ProductPolicy {
        public function update(User $user, Product $product) {
            return $user->isAdmin();
        }
    }
    
  • Scopes: Add custom query scopes to your model for advanced filtering:

    public function scopeFeatured($query) {
        return $query->where('is_featured', true);
    }
    

    Register the scope in config/content-api.php:

    'products' => [
        'scopes' => ['featured'],
    ],
    

Performance

  • Pagination: Use Laravel’s built-in pagination or customize via config/content-api.php:

    'pagination' => [
        'default_per_page' => 20,
    ],
    

    Access paginated results in your API responses.

  • Caching: Cache API responses globally or per-content-type:

    \Spatie\ContentApi\Facades\ContentApi::cacheFor(60); // Cache for 60 seconds
    

Gotchas and Tips

Pitfalls

1. Field Mismatches

  • Issue: Forgetting to update config/content-api.php when adding/removing fields in your migration.
  • Fix: Run php artisan content-api:generate-config to auto-generate the config based on your model’s fillable fields.
  • Tip: Use a seeder to populate test data and validate the API response structure.

2. Soft Deletes Confusion

  • Issue: Soft-deleted records appearing in API responses when not intended.
  • Fix: Explicitly exclude soft-deleted records in queries:
    \Spatie\ContentApi\Facades\ContentApi::get('products', null, ['with_trashed' => false]);
    
    Or set with_trashed to false in config/content-api.php as the default.

3. Mass Assignment Risks

  • Issue: Unauthorized mass assignment vulnerabilities if fillable is not strictly defined.
  • Fix: Always define fillable in your model and validate incoming requests:
    protected $fillable = ['title', 'description', 'slug'];
    
    Use Laravel’s AuthorizesRequests trait to gate sensitive fields.

4. Route Caching Conflicts

  • Issue: Route caching (php artisan route:cache) may break dynamic API routes.
  • Fix: Exclude the content API routes from caching by prefixing them with a unique key or using route middleware to bypass caching.

Debugging

1. API Response Validation

  • Tool: Use Postman or Laravel’s dd() to inspect raw responses:
    Route::get('/debug-products', function () {
        return \Spatie\ContentApi\Facades\ContentApi::get('products');
    });
    
  • Tip: Enable Laravel’s query logging to debug Eloquent queries:
    DB_LOG_QUERIES=true
    

2. Event Debugging

  • Tool: Temporarily log events to identify when content is saved/deleted:
    \Event::listen(\Spatie\ContentApi\Events\ContentSaved::class, function ($event) {
        \Log::channel('single')->info('Content saved', ['content' => $event->content]);
    });
    

3. Middleware Issues

  • Issue: API routes not being processed by middleware (e.g., auth, CORS).
  • Fix: Ensure the ContentApiServiceProvider registers middleware correctly. Add custom middleware to the $middleware array in the provider if needed.

Tips

1. Testing

  • Unit Tests: Test content retrieval, filtering, and sorting:
    public function test_get_product_by_slug() {
        $product = Product::factory()->create(['slug' => 'test-slug']);
        $response = $this->getJson('/api/products/test-slug');
        $response->assertOk()->assertJson(['title' => $product->title]);
    }
    
  • Feature Tests: Test API endpoints with tests/Feature/ContentApiTest.php.

2. Customization

  • Extend the API: Create a custom facade or service to wrap ContentApi for project-specific logic:
    class CustomContentApi {
        public function getFeaturedProducts() {
            return \Spatie\ContentApi\Facades\ContentApi::get('products', null, [
                'scopes' => ['featured'],
                'limit'
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport