webhouse.appwebhouse.appdocs

Read @webhouse/cms content from a Laravel application. Helper class, routes, Blade templates.

Setup

Place your Laravel project and @webhouse/cms content side by side:

my-project/
  cms.config.ts      # Content model
  content/           # JSON documents (read by Laravel)
  public/uploads/    # Media files (served by Laravel)
  app/               # Your Laravel app
  resources/views/   # Blade templates

Helper class

Create app/Services/Webhouse.php:

php
<?php

namespace App\Services;

use Illuminate\Support\Facades\File;
use Illuminate\Support\Collection;

class Webhouse
{
    public static function contentDir(): string
    {
        return base_path('content');
    }

    /**
     * List all published documents in a collection.
     *
     * @param  string  $collection  e.g. 'posts'
     * @param  string|null  $locale  e.g. 'en' — null means all locales
     * @return Collection<int, array>
     */
    public static function collection(string $collection, ?string $locale = null): Collection
    {
        $dir = self::contentDir() . '/' . $collection;
        if (!File::isDirectory($dir)) {
            return collect();
        }

        return collect(File::files($dir))
            ->filter(fn($f) => $f->getExtension() === 'json')
            ->map(fn($f) => json_decode(File::get($f->getPathname()), true))
            ->filter(fn($d) => ($d['status'] ?? null) === 'published')
            ->when($locale, fn($c) => $c->filter(fn($d) => ($d['locale'] ?? 'en') === $locale))
            ->sortByDesc(fn($d) => $d['data']['date'] ?? '')
            ->values();
    }

    /**
     * Load a single document by slug.
     */
    public static function document(string $collection, string $slug): ?array
    {
        $path = self::contentDir() . "/{$collection}/{$slug}.json";
        if (!File::exists($path)) return null;
        $doc = json_decode(File::get($path), true);
        return ($doc['status'] ?? null) === 'published' ? $doc : null;
    }
}

Routes

php
// routes/web.php
use App\Services\Webhouse;
use Illuminate\Support\Facades\Route;

Route::get('/', function () {
    $posts = Webhouse::collection('posts', 'en');
    return view('home', ['posts' => $posts]);
});

Route::get('/blog/{slug}', function (string $slug) {
    $post = Webhouse::document('posts', $slug);
    abort_unless($post, 404);
    return view('post', ['post' => $post]);
});

Blade template

blade
{{-- resources/views/post.blade.php --}}
@extends('layouts.app')

@section('content')
  <article>
    <h1>{{ $post['data']['title'] }}</h1>
    <time>{{ $post['data']['date'] ?? '' }}</time>
    <div class="prose">
      {!! \Illuminate\Support\Str::markdown($post['data']['content'] ?? '') !!}
    </div>
    @foreach (($post['data']['tags'] ?? []) as $tag)
      <a href="/tags/{{ $tag }}" class="tag">#{{ $tag }}</a>
    @endforeach
  </article>
@endsection

Serving uploaded media

@webhouse/cms stores uploaded media in public/uploads/. Laravel already serves the public/ directory, so /uploads/my-image.jpg just works.

i18n: reading both locales

php
// Get all Danish posts
$daPosts = Webhouse::collection('posts', 'da');

// Get all English posts
$enPosts = Webhouse::collection('posts', 'en');

// Find the translation of a specific post
$post = Webhouse::document('posts', 'hello-world');
$translationGroup = $post['translationGroup'] ?? null;
$translation = Webhouse::collection('posts')
    ->firstWhere(fn($d) => ($d['translationGroup'] ?? null) === $translationGroup && ($d['locale'] ?? null) !== $post['locale']);

Caching

For production, cache parsed JSON:

php
use Illuminate\Support\Facades\Cache;

public static function collection(string $collection, ?string $locale = null): Collection
{
    return Cache::remember("webhouse:{$collection}:{$locale}", 60, function () use ($collection, $locale) {
        // ... same logic as before
    });
}

Clear the cache when content changes — either via a file watcher or a CMS admin webhook.

Next steps

Tags:FrameworksFilesystem Adapter
Previous
Consume from Java (Spring Boot)
Next
Consume from Django (Python)
JSON API →Edit on GitHub →