.claude/skills/klytos-admin-notices/SKILL.md
Guide for displaying admin notices in Klytos CMS. Use when showing success, error, warning, or info messages to admin users, implementing flash messages after form submissions, creating persistent warnings that survive page loads, adding conditional notices that auto-hide when conditions change, or handling notice dismissal via AJAX. Also trigger when working with the NoticeManager, transient notices, or the notice.before_render filter.
npx skillsauth add joseconti/klytos klytos-admin-noticesInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Use this reference when you need to display messages to admin users. Klytos provides two types of notices:
strip_tags().success, error, warning, info to control the visual style.true shows an X button (AJAX dismiss for persistent). false means no close button.addEventListener, never onclick.admin.footer hook with the proper nonce.Shown once on the current page load. Survive a single POST-redirect-GET cycle via the session.
klytos_add_notice( string $message, string $type = 'info', bool $dismissible = true ): void
| Parameter | Type | Default | Description |
|---------------|--------|---------|------------------------------------------|
| $message | string | -- | Plain text message (HTML stripped) |
| $type | string | 'info' | 'success', 'error', 'warning', 'info' |
| $dismissible | bool | true | Whether user can close with X button |
// Success message after saving settings.
klytos_add_notice( __( 'settings.saved' ), 'success' );
// Error that cannot be dismissed.
klytos_add_notice( __( 'settings.save_failed' ), 'error', false );
// Info notice.
klytos_add_notice( 'Plugin activated successfully.', 'info' );
// Warning.
klytos_add_notice( 'This action cannot be undone.', 'warning' );
// In your admin page handler (e.g., plugins/my-plugin/admin/settings.php):
if ( $_SERVER['REQUEST_METHOD'] === 'POST' && klytos_verify_csrf() ) {
$result = save_my_settings( $_POST );
if ( $result ) {
klytos_add_notice( __( 'myplugin.settings_saved' ), 'success' );
} else {
klytos_add_notice( __( 'myplugin.settings_failed' ), 'error' );
}
// Redirect to avoid form resubmission -- notice survives the redirect.
header( 'Location: ' . $_SERVER['REQUEST_URI'] );
exit;
}
Stored in the notices collection. Survive across page loads and sessions. Can be dismissed per-user (via session) or removed programmatically.
klytos_add_persistent_notice(
string $id,
string $message,
string $type = 'info',
bool $dismissible = true,
array $options = []
): array
| Parameter | Type | Default | Description |
|---------------|--------|---------|----------------------------------------------|
| $id | string | -- | Unique identifier (slug format) |
| $message | string | -- | Plain text message |
| $type | string | 'info' | 'success', 'error', 'warning', 'info' |
| $dismissible | bool | true | Whether user can close with X button |
| $options | array | [] | Optional: context, condition_hook |
| Key | Type | Default | Description |
|-----------------|--------|---------|-------------------------------------------------------------|
| context | string | '' | Only show on this admin page (e.g., 'dashboard', 'settings'). Empty = all pages. |
| condition_hook | string | '' | Filter hook name. Notice only renders when the filter returns true. |
| ads | bool | true | Whether the notice is advertising. true = advertising (default), false = system/non-advertising. |
ads Field (Advertising vs System Notices)Every persistent notice has an ads field that defaults to true. This means any notice not explicitly marked as ads => false is considered advertising.
ads => true (default): Advertising notice. Can be hidden globally via Settings > Notices.ads => false: System/non-advertising notice. Always visible regardless of the ads toggle.Users can disable advertising notices in Settings > Notices > Show advertising notices. When disabled, only ads => false notices are rendered. Transient/flash notices are always shown regardless of this setting.
// Plugin advertising notice (default ads=true, can be hidden by user).
klytos_add_persistent_notice( 'my-promo', 'Try our premium features!', 'info', true );
// System notice (always visible).
klytos_add_persistent_notice( 'config-warning', 'Missing API key.', 'warning', true, [
'ads' => false,
] );
condition_hook PatternThis is the key innovation. A persistent notice declares a filter hook name. At render time, the Notice API calls klytos_apply_filters( $condition_hook, true ). If it returns false, the notice is silently skipped -- no code needs to delete it.
// Register a conditional persistent notice.
klytos_add_persistent_notice( 'ssl-missing', 'Your site is not using HTTPS.', 'error', false, [
'condition_hook' => 'notice.condition.ssl_missing',
] );
// Register the condition filter.
klytos_add_filter( 'notice.condition.ssl_missing', function ( bool $show ): bool {
return ! isset( $_SERVER['HTTPS'] ) || $_SERVER['HTTPS'] !== 'on';
} );
// Notice auto-hides when HTTPS is enabled -- no code needs to remove it.
klytos_add_persistent_notice() is idempotent by ID. Calling it multiple times with the same ID updates the existing notice instead of creating duplicates. Safe to call on every page load.
// Simple persistent notice (all pages, dismissible).
klytos_add_persistent_notice( 'welcome', 'Welcome to Klytos! Start by creating your first page.', 'info' );
// Page-specific, non-dismissible.
klytos_add_persistent_notice( 'no-pages', 'No pages published yet.', 'warning', false, [
'context' => 'dashboard',
] );
// Conditional: only shows when a config value is missing.
klytos_add_persistent_notice( 'missing-email', 'Please configure your email settings.', 'warning', true, [
'context' => 'settings',
'condition_hook' => 'notice.condition.missing_email',
] );
klytos_add_filter( 'notice.condition.missing_email', function ( bool $show ): bool {
$config = klytos_app()->getSiteConfig()->get();
return empty( $config['email_from'] ?? '' );
} );
klytos_dismiss_notice( string $id ): void
Dismisses a persistent notice for the current user session. The notice stays in storage but won't render for this user until the session expires.
Dismissible notices render an X button. Clicking it:
POST to /admin/api/notices.php with action=dismiss and the notice id.No plugin code needed -- this is handled automatically.
klytos_get_notices( string $currentPage = '' ): array
Returns all notices that should be rendered on the current page. Handles transient, session flash, and persistent notices. Filters by context, condition hooks, and dismiss state.
For advanced use cases, access the NoticeManager directly:
$manager = klytos_app()->getNoticeManager();
// Create a persistent notice with full control.
$manager->create( [
'id' => 'my-notice',
'message' => 'Custom notice text.',
'type' => 'warning',
'dismissible' => true,
'context' => 'dashboard',
'condition_hook' => 'notice.condition.my_custom',
'ads' => false, // System notice, always visible.
] );
// Delete a persistent notice from storage entirely.
$manager->delete( 'my-notice' );
// List all persistent notices.
$notices = $manager->list();
// Ensure a system notice exists (idempotent create/update).
$manager->ensureSystemNotice( 'sys-check', [
'message' => 'System check warning.',
'type' => 'error',
'dismissible' => false,
] );
| Hook | Fired When | Arguments |
|--------------------|----------------------------------|------------------|
| notice.created | Persistent notice created | array $notice |
| notice.dismissed | Notice dismissed | string $id |
| notice.deleted | Persistent notice deleted | string $id |
| notice.render.before | Before rendering notices | array $notices |
| notice.render.after | After rendering notices | array $notices |
| Hook | Purpose | Arguments |
|------------------------|-------------------------------------------|------------------------------|
| notice.transient.add | Modify transient notice before queuing | array $notice |
| notice.before_render | Add/remove/reorder notices before render | array $notices, string $page |
| notice.render_html | Customize per-notice HTML output | string $html, array $notice |
| {condition_hook} | Control conditional persistent notices | bool $show |
klytos_add_filter( 'notice.before_render', function ( array $notices, string $page ): array {
if ( $page === 'settings' ) {
$notices[] = [
'id' => 'plugin-tip',
'message' => 'Tip: Configure your social media links below.',
'type' => 'info',
'dismissible' => true,
'persistent' => false,
];
}
return $notices;
} );
Notices use the existing Klytos alert component classes:
| Class | Purpose |
|---------------------|-----------------------------------|
| .alert | Base alert styling |
| .alert-success | Green (success tokens) |
| .alert-error | Red (error tokens) |
| .alert-warning | Amber (warning tokens) |
| .alert-info | Blue (info tokens) |
| .alert-dismissible| Flex layout with space for X btn |
| .alert-close | The X dismiss button |
Colors come from --klytos-{type}-subtle (background), --klytos-{type}-text (text), defined in klytos-tokens.css.
URL: /admin/api/notices.php
| Method | Action | Parameters | Description |
|--------|---------------|------------|----------------------------------|
| GET | -- | ?page= | List renderable notices |
| POST | dismiss | id | Dismiss a persistent notice |
| POST | dismiss-all | -- | Dismiss all dismissible notices |
Requires authentication and CSRF token.
The admin Settings page includes a Notices section where site owners can:
notices.show_ads site config). When unchecked, all notices with ads => true are hidden.// Read the ads toggle.
$showAds = klytos_config( 'notices.show_ads' ); // default: true
// Set programmatically.
klytos_set_config( 'notices', ['show_ads' => false] );
// Flash notice (shown once).
klytos_add_notice( 'Settings saved!', 'success' );
// Persistent notice (survives page loads, advertising by default).
klytos_add_persistent_notice( 'my-warning', 'Check your config.', 'warning' );
// Non-advertising persistent notice (always visible).
klytos_add_persistent_notice( 'sys-check', 'System check required.', 'error', true, [
'ads' => false,
] );
// Conditional persistent (auto-hides when condition is false).
klytos_add_persistent_notice( 'check-ssl', 'HTTPS not enabled.', 'error', false, [
'condition_hook' => 'notice.condition.no_ssl',
'ads' => false,
] );
klytos_add_filter( 'notice.condition.no_ssl', fn( bool $show ) => ! is_ssl() );
// Dismiss programmatically.
klytos_dismiss_notice( 'my-warning' );
// Delete from storage.
klytos_app()->getNoticeManager()->delete( 'my-warning' );
development
Guide for working with dates, times, and timezones in Klytos CMS. Use when formatting dates, converting timezones, scheduling actions with timestamps, displaying local time, working with UTC storage, building timezone selectors, or using any klytos_date/klytos_gmdate/klytos_timezone functions.
tools
Guide for developing and extending the Klytos web terminal. Use when modifying terminal commands, adding terminal commands from plugins, fixing terminal bugs, extending the pseudo-terminal, working with TerminalExecutor class, registering custom permissions, adding custom category labels, or managing terminal UI and security.
development
--- name: klytos-site-builder description: Guide for building a complete website from scratch with Klytos CMS. Use when creating a new site, configuring a site after installation, setting up design/content/SEO/navigation, or when the user pastes the post-install prompt. Covers 9 phases: discovery, design reference, global config, theme, content structure, templates, content creation, additional features, and launch. --- # Klytos Site Builder ## Overview The Site Builder is a conversational AI
development
Use when creating or editing page content in Klytos CMS. Ensures every page has proper SEO structure, HTML semantics, meta tags, structured data, accessibility for maximum search engine visibility. Apply when writing page titles, descriptions, content, headings, images, internal links, JSON-LD schema, or following the SEO checklist before publishing pages.