Building an Interactive CLI Dashboard with Laravel Prompts
Managing a file-based blog involves creating files, formatting dates, and managing frontmatter. While I can do this manually in VS Code, having a CLI tool makes it feel like a real CMS.
Laravel recently introduced Laravel Prompts, a package that makes building CLI forms beautiful and easy. Let's build a php artisan blog:manage command.
Setting the Stage
We want a command that allows us to:
- Create a new post.
- List recent drafts.
- Publish a draft.
The Command
First, generate the command:
php artisan make:command ManageBlog
Implementation
We will use select, text, confirm, and multiselect from the Laravel\Prompts namespace.
<?php
namespace App\Console\Commands;
use Illuminate\Console\Command;
use Illuminate\Support\Str;
use Carbon\Carbon;
use function Laravel\Prompts\select;
use function Laravel\Prompts\text;
use function Laravel\Prompts\confirm;
use function Laravel\Prompts\multiselect;
use function Laravel\Prompts\info;
class ManageBlog extends Command
{
protected $signature = 'blog:manage';
protected $description = 'Interactive blog management dashboard';
public function handle()
{
$action = select(
label: 'What would you like to do?',
options: [
'create' => 'Create a new post',
'view' => 'View drafts',
'exit' => 'Exit',
]
);
match ($action) {
'create' => $this->createPost(),
'view' => $this->viewDrafts(),
'exit' => $this->info('Goodbye!'),
};
}
protected function createPost()
{
$title = text('Post Title', required: true, placeholder: 'My Awesome Post');
$slug = text(
label: 'Slug',
default: Str::slug($title),
validate: fn (string $value) => match (true) {
strlen($value) < 3 => 'The slug must be at least 3 characters.',
default => null
}
);
$tags = multiselect(
label: 'Select Tags',
options: ['laravel', 'php', 'javascript', 'css', 'devops', 'testing'],
scroll: 5
);
$isDraft = confirm('Save as draft?', default: false);
$date = Carbon::now()->format('Y-m-d');
$filename = "{$date}-{$slug}.md";
$path = base_path("content/posts/" . Carbon::now()->format('Y'));
// Ensure directory exists
if (!is_dir($path)) {
mkdir($path, 0755, true);
}
$content = <<<EOT
---
title: "{$title}"
date: {$date}
description: ""
tags: {$this->formatTags($tags)}
draft: {$this->boolToString($isDraft)}
---
Write your content here...
EOT;
file_put_contents("$path/$filename", $content);
info("Post created at: $path/$filename");
}
protected function formatTags(array $tags): string
{
return '["' . implode('", "', $tags) . '"]';
}
protected function boolToString(bool $val): string
{
return $val ? 'true' : 'false';
}
protected function viewDrafts()
{
// Implementation for scanning standard directory for `draft: true`
info("Feature coming soon...");
}
}
Why Laravel Prompts?
1. Validation
Validation happens inline. You don't have to submit the form to see you made a mistake.
2. Searchable Selects
If you have 50 tags, multiselect allows you to type to filter them. This is a massive UI improvement over standard CLI inputs.
3. Consistency
The UI matches Laravel's installer and other ecosystem tools, making your custom internal tools feel "official".
Next Steps
You could expand this to:
- Run a grammar checker on the file content.
- Automatically open the new file in VS Code using
exec("code $path"). - Generate an AI summary using an LLM API for the description field.
CLI tools don't have to be ugly arguments. With Prompts, they can be a delight to use.