Skip to content

Repository files navigation

πŸ‘€ Laravel Persona

Tests Latest Release License

Elegant, customizable public profiles for Laravel applications.

Laravel Persona gives an Eloquent user model profile pages, unique public usernames, display names, headlines, mottos, biographies, avatars, banners, social links, custom links, visibility controls, publishing, view tracking, profile comments, completeness scoring, badges, and convenient model helpers.

$profile = $user->createPersona([
    'display_name' => 'Nick',
    'headline' => 'Laravel Package Builder',
    'motto' => 'Build useful things.',
    'bio' => 'Building useful Laravel packages.',
    'location' => 'Kansas',
    'is_public' => true,
    'published_at' => now(),
]);

$url = $user->personaUrl();
$score = $user->personaCompletenessScore();

πŸ“‹ Supported Versions

Package version PHP Laravel / Illuminate
Current ^8.2 ^12.0 || ^13.0

Composer resolves the compatible Illuminate packages for the consuming Laravel application.

πŸš€ Installation

Install Persona:

composer require eloquent-works/persona

Publish the configuration and migrations:

php artisan persona:install

Run the migrations:

php artisan migrate

Add HasPersona to the application user model:

<?php

namespace App\Models;

use EloquentWorks\Persona\Traits\HasPersona;
use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable
{
    use HasPersona;
}

See Installation for publishing options and setup guidance.

✨ Features

  • Public or private user profiles
  • Slug-based public usernames and route model binding
  • Configurable username-change tokens
  • Reserved-name, format, length, and uniqueness checks
  • Display names, headlines, mottos, biographies, and locations
  • Avatar and banner URLs through Laravel filesystems
  • Website URLs, social links, and custom links
  • Publishing and configurable visibility requirements
  • Public, published, and visible query scopes
  • Profile view counters
  • Profile comments with replies, approval, pinning, editing, and deletion
  • Profile completeness scoring
  • Custom profile badge awarding
  • Lifecycle events for creation, updates, publishing, unpublishing, and views
  • Publishable views and customizable public routes
  • Configurable models, tables, field limits, feature flags, and storage
  • PHPUnit, PHPStan/Larastan, Laravel Pint, and Composer quality scripts

πŸš€ Quick Start

Create a profile

$profile = $user->createPersona([
    'display_name' => 'Nick',
    'headline' => 'Laravel Package Builder',
    'motto' => 'Build useful things.',
    'bio' => 'Building useful Laravel packages.',
    'location' => 'Kansas',
    'website_url' => 'https://example.com',
    'is_public' => true,
    'published_at' => now(),
]);

Read or update the profile

$profile = $user->persona;

$user->hasPersona();

$user->updatePersona([
    'headline' => 'Open-source Laravel Developer',
]);

Register the public profile route

Persona does not register public routes automatically.

use Illuminate\Support\Facades\Route;

Route::persona();

The default route format is:

/@{persona}

Generate URLs

$profile->url();
$profile->avatarUrl();
$profile->bannerUrl();

$user->personaUrl();

πŸ‘οΈ Visibility and Publishing

$profile->isVisible();

$publicProfiles = Persona::public()->get();
$publishedProfiles = Persona::published()->get();
$visibleProfiles = Persona::visible()->get();

Visibility follows:

config('persona.visibility.require_published_at');

When require_published_at is disabled, a public profile may be visible without a publication timestamp. When enabled, the profile must be public and have a past published_at value.

Private profile responses

By default, Persona preserves its historical behavior and returns 404 for profiles that are not publicly visible:

'visibility' => [
    'private_profile_response' => '404',
],

Applications may instead render a privacy-safe placeholder:

'visibility' => [
    'private_profile_response' => 'view',
],

The default private view displays:

This profile is private. This user has chosen to keep their profile private.

The private placeholder intentionally receives no Persona model and no user model. This prevents customized placeholder views from accidentally exposing private profile fields.

Customize the view with:

'views' => [
    'private' => 'profiles.private',
],

Authenticated profile owners may view their own private profile by default. Disable that behavior with:

'visibility' => [
    'owner_can_view_private' => false,
],

🏷️ Username Tokens

Persona uses the profile slug as its public username.

$profile->usernameTokens();
$profile->canChangeUsername();
$profile->nextUsernameTokenAt();
$profile->usernameIsAvailable('signal-nick');
$profile->changeUsername('signal-nick');

Use the helpers on the user model:

$user->personaUsernameTokens();
$user->canChangePersonaUsername();
$user->changePersonaUsername('signal-nick');

An administrative change can skip token spending:

$profile->changeUsername(
    'signal-nick',
    spendToken: false,
);

Persona normalizes the username and applies the configured length, regular expression, reserved-name, uniqueness, and token rules.

πŸ“Š Completeness

Refresh the profile's completeness score directly:

$score = $profile->refreshCompleteness();

Or through the user model:

$score = $user->personaCompletenessScore();

The user helper returns 0 when no Persona profile exists.

See Completeness and Badges.

πŸ… Badges

Award a badge directly through the profile:

$badge = $profile->awardBadge(
    'package-builder',
    [
        'label' => 'Package Builder',
        'description' => 'Published a Laravel package.',
    ],
    $user,
);

Or use the user-model helper:

$badge = $user->awardPersonaBadge(
    'package-builder',
    [
        'label' => 'Package Builder',
    ],
);

The helper returns null when the user does not have a Persona profile.

πŸ’¬ Profile Comments

$comment = $profile->addComment(
    $user,
    'Great profile.',
);

$reply = $comment->addReply(
    $otherUser,
    'Thank you.',
);

Moderate and edit comments:

$comment->approve();
$comment->unapprove();

$comment->pin();
$comment->unpin();

$comment->edit('Updated comment.');
$comment->delete();

Retrieve common comment groups:

$profile->approvedComments()->get();
$profile->pinnedComments()->get();

PersonaComment::topLevel()->approved()->get();
PersonaComment::repliesOnly()->get();
PersonaComment::pinned()->get();

Persona provides the model API. The consuming application remains responsible for routes, request validation, authorization, rate limiting, spam controls, and guest identity handling.

See Profile Comments.

πŸ“£ Events

Persona can dispatch:

  • PersonaCreated
  • PersonaUpdated
  • PersonaPublished
  • PersonaUnpublished
  • PersonaViewed

Disable lifecycle events globally:

'dispatch_events' => false,

See Events.

βš™οΈ Configuration

Publish the configuration file:

php artisan vendor:publish --tag=persona-config

Major configuration groups include:

return [
    'tables' => [],
    'models' => [],
    'routes' => [],
    'usernames' => [],
    'views' => [],
    'storage' => [],
    'slugs' => [],
    'fields' => [],
    'comments' => [],
    'visibility' => [],
    'links' => [],
    'features' => [],
    'dispatch_events' => true,
];

See Configuration for the complete reference.

βœ… Quality Checks

Run all package checks:

composer quality

Or run them separately:

composer format
composer format:test
composer analyse
composer test

Validate Composer metadata before a release:

composer validate --strict

The quality pipeline should complete with zero formatting, PHPStan, or PHPUnit failures.

See Testing and Quality.

πŸ“š Documentation

πŸ” Security

Treat every public profile field, URL, link, comment, metadata value, and badge attribute as user-generated or administrator-generated content.

Validate URLs, escape rendered values, authorize profile and comment changes, rate-limit public write endpoints, and avoid exposing private profiles through search, sitemaps, APIs, or public routes.

Security vulnerabilities should be reported privately according to SECURITY.md.

🀝 Contributing

See CONTRIBUTING.md and CODE_OF_CONDUCT.md.

πŸ™ Credits

Built by Eloquent Works.

πŸ“„ License

Laravel Persona is open-source software licensed under the MIT License.

About

Laravel Persona gives your users elegant public profiles with slugs, bios, avatars, links, visibility, and profile pages.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

Contributors

Languages