Use Relationship Blocks
Pull data from any Eloquent model — Latest Posts, Team Members, Products — and display it on a page using the Relationship block. You configure it once, and editors curate the content from the admin without touching code again.
Step 1: Register a Query Source
Before you can use the block, tell Kompass which models are available.
- Allow-list the model in
config/kompass.php:php'query_source_models' => [ 'posts' => \Secondnetwork\Kompass\Models\Post::class, 'team' => \App\Models\TeamMember::class, ], - Navigate to Admin > Query Sources.
- Click Add Source and select your model. Configure the sorting and the Item View (the Blade component that renders each record).
Step 2: Add the Relationship Block
- Open a page in the Block Editor.
- Add a Relationship block.
- In the block's settings panel, select your Source (e.g., "Posts").
Step 3: Choose a Mode
You can display items in two ways:
- Automatic: Show the "Latest 5 items" based on a sort field (e.g.,
created_at). Perfect for blog feeds or news that should always reflect the newest records. - Manual: Hand-pick specific records from a search list and drag them into your preferred order. Ideal when the order matters — team hierarchies, featured products, or curated collections.
Step 4: Create the Item View
Each record in the list is rendered using a small Blade component. If you set the "Item View" to relations.post-card, create the file at resources/views/components/relations/post-card.blade.php.
@props(['record', 'url' => null])
<div class="border p-4 rounded shadow">
@if($record->thumbnails)
<x-image :id="$record->thumbnails" class="w-full h-32 object-cover" />
@endif
<h3 class="font-bold mt-2">{{ $record->title }}</h3>
<a href="{{ $url }}" class="text-blue-600 underline">Read More</a>
</div>Item View Naming
The relations.post-card identifier maps to the relations/post-card Blade component path. Use dot notation when configuring the Item View in the admin.
Step 5: Render on the Frontend
Ensure your page template renders the blocks. The Relationship block automatically loops through the records and renders your post-card component for each one.
Example: A Team Members Section
Let's put it all together with a real-world case — a "Meet the Team" grid on an "About Us" page, driven by a custom TeamMember model. This is the complete end-to-end path: migration, model, allow-list, source, and item view.
1. Create the migration
php artisan make:migration create_team_members_tableSchema::create('team_members', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->unsignedBigInteger('photo')->nullable(); // medialibrary file id
$table->string('role')->nullable();
$table->string('phone')->nullable();
$table->string('email')->nullable();
$table->text('description')->nullable();
$table->integer('order')->default(0);
$table->boolean('is_active')->default(true);
$table->timestamps();
});2. Create the model
Add an active scope so the source can filter out hidden members, and a relation to resolve the Media Library photo.
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Secondnetwork\Kompass\Models\File;
use Illuminate\Database\Eloquent\Builder;
class TeamMember extends Model
{
protected $guarded = [];
public function photoFile()
{
return $this->belongsTo(File::class, 'photo');
}
public function scopeActive(Builder $query): void
{
$query->where('is_active', true);
}
}3. Allow-list the model
As in Step 1, register the model in config/kompass.php:
'query_source_models' => [
'teams' => \App\Models\TeamMember::class,
],4. Create the source
Under Admin → Query sources, click Add and configure:
| Field | Value |
|---|---|
| Label | Team |
| Key | team |
| Model | teams |
| Display fields | name, role |
| Order fields | order, name |
| Scope | active |
| Item view | relations.team |
| Wrapper class | grid gap-8 sm:grid-cols-2 lg:grid-cols-3 |
The Wrapper class wraps the whole list, so a single Tailwind grid here turns your cards into a responsive layout. The Scope maps to the active scope you defined on the model.
5. Create the item view
resources/views/components/relations/team.blade.php:
@props(['record', 'url' => null, 'modelKey' => null])
<div class="card bg-base-100 text-center p-6">
@if ($record->photo)
<x-image :id="$record->photo" class="w-32 h-32 rounded-full mx-auto object-cover" />
@endif
<h3 class="mt-4 text-lg font-semibold">{{ $record->name }}</h3>
@if ($record->role)
<p class="text-sm text-primary">{{ $record->role }}</p>
@endif
@if ($record->description)
<p class="mt-2 text-sm text-base-content/70">{{ $record->description }}</p>
@endif
</div>6. Add the block and curate the team
Open your "About Us" page and add a Relationship block. Set the Source to Team. Now pick a mode:
- Automatic — Order by
orderand let the grid stay in sync with the database. - Manual — Search for members, click (+) to select them, and drag the handles (⋮⋮) to arrange them by hierarchy (e.g., CEO first).
Save the page and you have a responsive team grid that editors can update at any time, without touching code.
Manual mode is best for teams
Manual mode gives you absolute control over who appears and in what order — ideal for board members, departments, or project-specific team pages.
Need a backend screen where editors can add and edit those members in the first place? See Build a Backend Table View.