Skip to content

Flash Messages in Slim 4 Framework

Flash messages are short-lived messages that provide user feedback after form submissions or actions (such as item deletion, form validation errors, etc.).

  • How it works? When a user logs in, registers, or updates their profile, you redirect them to another page and show a message like “Login successful!” or “Profile updated!”
  • Flash messages are stored in the session, survive one redirect, and then might automatically disappear.

Common use cases:

  • Success: “Login successful!” or “Profile updated!”
  • Error: “Invalid password” or “Email already exists”
  • Info: “Check your email for verification link”
  • Warning: “Your session will expire in 5 minutes”

The FlashMessage class is a wrapper class that will help us manage flash messages in our application by providing a clean API for managing messages.

This class needs to be created in the app/Helpers/FlashMessage.php file.

<?php
namespace App\Helpers;
class FlashMessage
{
private const FLASH_KEY = 'flash_messages';
/**
* Add a success message.
*/
public static function success(string $message): void
{
self::add('success', $message);
}
/**
* Add an error message.
*/
public static function error(string $message): void
{
self::add('error', $message);
}
/**
* Add an info message.
*/
public static function info(string $message): void
{
self::add('info', $message);
}
/**
* Add a warning message.
*/
public static function warning(string $message): void
{
self::add('warning', $message);
}
/**
* Add a flash message of any type.
*/
public static function add(string $type, string $message): void
{
if (!isset($_SESSION[self::FLASH_KEY])) {
$_SESSION[self::FLASH_KEY] = [];
}
$_SESSION[self::FLASH_KEY][] = [
'type' => $type,
'message' => $message
];
}
/**
* Get all flash messages and clear them.
*/
public static function get(): array
{
$messages = $_SESSION[self::FLASH_KEY] ?? [];
unset($_SESSION[self::FLASH_KEY]);
return $messages;
}
/**
* Check if there are any flash messages.
*/
public static function has(): bool
{
return !empty($_SESSION[self::FLASH_KEY]);
}
/**
* Clear all flash messages without retrieving them.
*/
public static function clear(): void
{
unset($_SESSION[self::FLASH_KEY]);
}
/**
* Render all flash messages as Bootstrap alerts.
*/
public static function render(bool $dismissible = true): string
{
$messages = self::get();
if (empty($messages)) {
return '';
}
$bootstrapTypes = [
'success' => 'success',
'error' => 'danger',
'info' => 'info',
'warning' => 'warning'
];
$html = '';
foreach ($messages as $flash) {
$type = $bootstrapTypes[$flash['type']] ?? 'info';
$message = htmlspecialchars($flash['message']);
if ($dismissible) {
$html .= <<<HTML
<div class="alert alert-{$type} alert-dismissible fade show" role="alert">
{$message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>
HTML;
} else {
$html .= <<<HTML
<div class="alert alert-{$type}" role="alert">
{$message}
</div>
HTML;
}
}
return $html;
}
}

Here is a list of the methods available in the FlashMessage class.

MethodDescription
FlashMessage::success($msg)Add a success message
FlashMessage::error($msg)Add an error message (displays as Bootstrap alert-danger)
FlashMessage::info($msg)Add an info message
FlashMessage::warning($msg)Add a warning message
FlashMessage::add($type, $msg)Add a custom message type
FlashMessage::render($dismissible)Display all messages as Bootstrap alerts (dismissible by default)
FlashMessage::get()Retrieve and clear all messages (auto-cleanup)
FlashMessage::has()Check if messages exist
FlashMessage::clear()Clear all messages without retrieving them

Using the FlashMessage::add($type, $message) method

Section titled “Using the FlashMessage::add($type, $message) method”

To set a flash message, we can use the FlashMessage::add($type, $message) method.

This method takes two parameters:

  • $type: The type of message to add. This can be success, error, info, or warning.
  • $message: The message to add.
Setting flash messages in routes using the FlashMessage::add($type, $message) method
FlashMessage::add('success', 'Login successful! Welcome back.');
FlashMessage::add('error', 'Invalid password. Please try again.');
FlashMessage::add('info', 'Check your email for verification link.');
FlashMessage::add('warning', 'Your session will expire in 5 minutes.');
// redirect to the dashboard (or any other view).
return $response->withHeader('Location', '/dashboard')->withStatus(302);

Using the FlashMessage class’s proxy methods

Section titled “Using the FlashMessage class’s proxy methods”

Or any of the other methods like success($message), error($message), info($message), warning($message) as shown in the example below.

Setting flash messages in routes using the FlashMessage class's proxy methods
use App\Helpers\FlashMessage;
// After successful login, we add a success message and redirect to the dashboard.
$app->post('/login', function ($request, $response) {
// ... validate credentials ...
FlashMessage::success('Login successful! Welcome back.');
return $response->withHeader('Location', '/dashboard')->withStatus(302);
});
// After registration fails, we add an error message and redirect to the registration page.
$app->post('/register', function ($request, $response) {
// ... validation fails ...
FlashMessage::error('Email already exists. Please use a different email.');
return $response->withHeader('Location', '/register')->withStatus(302);
});
// Multiple types can be added to the same message. We add a success message and an info message and redirect to the profile page.
$app->post('/update-profile', function ($request, $response) {
FlashMessage::success('Profile updated successfully!');
FlashMessage::info('Changes will appear within 24 hours.');
return $response->withHeader('Location', '/profile')->withStatus(302);
});

The simplest way to display flash messages in your views is to use the FlashMessage::render() method.

Example: Displaying flash messages in views using the FlashMessage::render() method
<?= App\Helpers\FlashMessage::render() ?>

That’s it! This will automatically:

  • Retrieve and display all flash messages
  • Map types to Bootstrap classes (erroralert-danger)
  • Create dismissible alerts with close buttons
  • Clear messages after display
  • HTML-escape messages for security

Non-dismissible alerts:

Example: Displaying non-dismissible flash messages in views
<?= App\Helpers\FlashMessage::render(false) ?>

or:

Check if messages exist and display them
<?php if (FlashMessage::has()): ?>
<?php echo FlashMessage::render(); ?>
<?php endif; ?>

If you need custom styling, you can manually render:

<?php
use App\Helpers\FlashMessage;
$messages = FlashMessage::get();
$bootstrapTypes = [
'success' => 'success',
'error' => 'danger',
'info' => 'info',
'warning' => 'warning'
];
?>
<?php foreach ($messages as $flash): ?>
<?php $type = $bootstrapTypes[$flash['type']] ?? 'info'; ?>
<div class="alert alert-<?= $type ?>" role="alert">
<?= htmlspecialchars($flash['message']) ?>
</div>
<?php endforeach; ?>

The following are some common patterns for using flash messages in your application.

$app->post('/contact', function ($request, $response) {
$data = $request->getParsedBody();
if (empty($data['email'])) {
FlashMessage::error('Email is required.');
return $response->withHeader('Location', '/contact')->withStatus(302);
}
if (empty($data['message'])) {
FlashMessage::error('Message cannot be empty.');
return $response->withHeader('Location', '/contact')->withStatus(302);
}
// Process form...
FlashMessage::success('Message sent successfully!');
return $response->withHeader('Location', '/')->withStatus(302);
});

// Create
$app->post('/products', function ($request, $response) {
// ... create product ...
FlashMessage::success('Product created successfully!');
return $response->withHeader('Location', '/products')->withStatus(302);
});
// Update
$app->put('/products/{id}', function ($request, $response, $args) {
// ... update product ...
FlashMessage::info('Product updated.');
return $response->withHeader('Location', '/products')->withStatus(302);
});
// Delete
$app->delete('/products/{id}', function ($request, $response, $args) {
// ... delete product ...
FlashMessage::warning('Product deleted.');
return $response->withHeader('Location', '/products')->withStatus(302);
});

$app->post('/checkout/step-1', function ($request, $response) {
// ... save shipping info ...
FlashMessage::success('Shipping information saved.');
return $response->withHeader('Location', '/checkout/step-2')->withStatus(302);
});
$app->post('/checkout/step-2', function ($request, $response) {
// ... save payment info ...
FlashMessage::success('Payment method saved.');
return $response->withHeader('Location', '/checkout/confirm')->withStatus(302);
});

// ✅ Good - redirect after flash message
FlashMessage::success('Saved!');
return $response->withHeader('Location', '/dashboard')->withStatus(302);
// ❌ Bad - no redirect (message won't display properly)
FlashMessage::success('Saved!');
return $response->getBody()->write('Done');

// ✅ Good - clear message types
FlashMessage::success('Account created successfully!');
FlashMessage::error('Password is too weak.');
FlashMessage::warning('Trial period ending soon.');
FlashMessage::info('New features available.');
// ❌ Bad - wrong type
FlashMessage::success('Error: Login failed!'); // Should be error()

// ✅ Good - concise and clear
FlashMessage::success('Profile updated!');
FlashMessage::error('Invalid email address.');
// ❌ Bad - too verbose
FlashMessage::success('Your profile has been successfully updated and all changes have been saved to the database.');

Setting messages in routes:

use App\Helpers\FlashMessage;
FlashMessage::success('Success message');
FlashMessage::error('Error message');
FlashMessage::info('Info message');
FlashMessage::warning('Warning message');
FlashMessage::add('custom', 'Custom type message');

Displaying in views (Recommended):

<?= App\Helpers\FlashMessage::render() ?> // Dismissible alerts
<?= App\Helpers\FlashMessage::render(false) ?> // Non-dismissible

Other methods:

// Check if messages exist
if (FlashMessage::has()) {
// Messages available
}
// Get messages manually (auto-clears)
$messages = FlashMessage::get();
// Clear without retrieving
FlashMessage::clear();

  • ✅ Flash messages are one-time, temporary messages
  • FlashMessage class provides clean API for managing messages
  • ✅ Four built-in types: success, error, info, warning
  • ✅ Use FlashMessage::render() for one-line display in views
  • ✅ Messages auto-clear after display
  • ✅ Always redirect after setting flash messages
  • ✅ Bootstrap uses alert-danger for error messages (not alert-error)