Display notifications that appear on the front end to provide feedback or information to the user.
ska-theme includes a template part for rendering Toasts, which can be enabled from ska-theme -> General -> Toasts. The template part is set up to use the skaToast
Alpine.js module.
// Available configuration when using `x-data="skaToast"` on an element.
interface ToastConfig {
/** Maximum amount of Toasts visible at once. */
max?: number
}
// Toast structure.
interface Toast {
id?: string | number
content: string
type?: 'default' | 'info' | 'success' | 'warning' | 'error' | string
}
// Properties available when using `x-data="skaToast"` on an element.
interface ToastModule {
/** Add and show a toast. */
add: (toast: Toast | Toast['content']) => void
/** Show a toast. */
show: (id: Toast['id']) => void
/** Hide a toast. */
hide: (id: Toast['id']) => void
/** Remove all toasts. */
clear: () => void
}
Adding a toast
Ensure that rendering of the template part that handles showing toasts is enabled from ska-theme -> General -> Toast.
JavaScript
The global window.ska_theme
object includes a function for adding a toast. The function can accept a string with toast content or an object with the content
property and additional details about the toast, such as type
or id
.
// Using the global function
window.ska_theme.toast('Toast content.')
// With additional details
window.ska_theme.toast({
content: 'Toast content.',
type: 'info',
})
// Dispatching the event manually
window.dispatchEvent(new CustomEvent('ska-toast', {
detail: {
content: 'Toast content.',
},
}))
// Toast with details
window.ska_theme.toast({
id: 'toast-1',
content: 'Toast content.',
type: 'info',
})
// Hide toast by ID
window.ska_theme.hideToast('toast-1')
// Hide all toasts
window.ska_theme.clearToasts()
Alpine.js
In the block editor it’s easiest to add toasts by adding HTML attributes to blocks. A toast can be triggered by using the ska_theme.toast
function from earlier or by using Alpine’s $dispatch
magic.
/** Using the global function */
<button x-data x-on:click="ska_theme.toast('Toast content.')">Show toast</button>
// Add toast
ska_theme.toast({id: 'toast-1', content: 'Toast content.', type: 'info'})
// Hide toast
ska_theme.hideToast('toast-1')
// Hide all toasts
ska_theme.clearToasts()
/** Using Alpine.js $dispatch */
<button x-data x-on:click="$dispatch('ska-toast', 'Toast content.')">Show toast</button>
// Add toast
$dispatch('ska-toast', {content: 'Toast content.', type: 'success', id: 'toast-id'})
// Hide toast
$dispatch('ska-hide-toast', 'toast-id')
// Hide all toasts
$dispatch('ska-clear-toasts')
PHP
A toast can also be added with PHP to leave users some feedback when something was done server-side.
ska_theme()->get('toast')->add('Toast content.');
ska_theme()->get('toast')->add([
'content' => 'Invalid nonce.',
'type' => 'error',
]);
add_action('wp_body_open', function() {
if(!isset($_POST['email'])) {
return;
}
if(subscribe_to_newsletter(sanitize_email(wp_unslash($_POST['email'])))) {
ska_theme()->get('toast')->add([
'content' => esc_html__('You have subscribed to the newsletter!', 'your-textdomain'),
'type' => 'success',
]);
} else {
ska_theme()->get('toast')->add([
'content' => sprintf(
esc_html__('Something went %1$shorribly%2$s wrong.', 'your-textdomain'),
'<strong>',
'</strong>'
),
'type' => 'error',
]);
}
});
Examples
Default toast
<!-- wp:ska/text {"skaBlocks":{"p":[{"id":"ska-theme\u002d\u002dbutton","isStatic":true}],"t":1744868963},"skaBlocksAs":{"customElement":"","element":"button"},"skaBlocksAttributes":{"record":{"x-data":"","x-on:click":"$dispatch('ska-toast', 'Toast content.')"}},"skaBlocksVariation":"ska-theme\u002d\u002dbutton"} -->
<button x-data="" x-on:click="$dispatch('ska-toast', 'Toast content.')" class="wp-block-ska-text ska-text">Default toast</button>
<!-- /wp:ska/text -->
Detailed toast
<!-- wp:ska/text {"skaBlocks":{"p":[{"id":"ska-theme\u002d\u002dbutton","isStatic":true}],"t":1744868963},"skaBlocksAs":{"customElement":"","element":"button"},"skaBlocksAttributes":{"record":{"x-data":"","x-on:click":"$dispatch('ska-toast', {id: 'toast', content: 'Toast content.', type: 'info'})"}},"skaBlocksVariation":"ska-theme\u002d\u002dbutton"} -->
<button x-data="" x-on:click="$dispatch('ska-toast', {id: 'toast', content: 'Toast content.', type: 'info'})" class="wp-block-ska-text ska-text">Detailed toast</button>
<!-- /wp:ska/text -->
Remote request
A button that attempts to fetch data from a REST endpoint and displays a success toast with the result or an error toast on failure (includes a setTimeout
for demo purposes only).
<!-- wp:ska/element {"skaBlocks":{"cx":"gap-2.5","css":".gap-2\\.5{gap:var(\u002d\u002dspacing-2_5)}","t":1744868963,"p":[{"id":"ska-theme\u002d\u002dbutton","isStatic":true}]},"skaBlocksAppender":{"type":"hidden"},"skaBlocksAs":{"customElement":"","element":"button"},"skaBlocksAttributes":{"record":{"x-data":"{loading: false}","x-on:fetch":"fetch('/docs/wp-json/wp/v2/posts?per_page=1').then(r =\u003e r.json()).then(p =\u003e p[0].title.rendered).then(title =\u003e $dispatch('success', title)).catch(e =\u003e $dispatch('error')).finally(() =\u003e loading = false)","x-on:success":"$dispatch('ska-toast', {content: `The latest post on this site is titled: \u003cstrong\u003e${$event.detail}\u003c/strong\u003e`, type: 'success'})","x-on:error":"$dispatch('ska-toast', {content: `Failed fetching the latest post.`, type: 'error'})","x-on:click":"loading = true; setTimeout(() =\u003e $dispatch('fetch'), 2000)",":class":"{loading}",":disabled":"loading"}},"skaBlocksSelectors":[],"skaBlocksVariation":"ska-theme\u002d\u002dicon-button","skaBlocksGap":{"v":{"$":{"@":"2.5"}}},"className":"loading"} -->
<button x-data="{loading: false}" x-on:fetch="fetch('/docs/wp-json/wp/v2/posts?per_page=1').then(r => r.json()).then(p => p[0].title.rendered).then(title => $dispatch('success', title)).catch(e => $dispatch('error')).finally(() => loading = false)" x-on:success="$dispatch('ska-toast', {content: `The latest post on this site is titled: <strong>${$event.detail}</strong>`, type: 'success'})" x-on:error="$dispatch('ska-toast', {content: `Failed fetching the latest post.`, type: 'error'})" x-on:click="loading = true; setTimeout(() => $dispatch('fetch'), 2000)" :class="{loading}" :disabled="loading" class="gap-2.5 wp-block-ska-element loading"><!-- wp:ska/text -->
<span class="wp-block-ska-text ska-text">Fetch the latest post title</span>
<!-- /wp:ska/text -->
<!-- wp:ska/image {"mode":"svg","svg":"\u003csvg fill=\u0022currentColor\u0022 xmlns=\u0022http://www.w3.org/2000/svg\u0022 viewBox=\u00220 0 512 512\u0022\u003e\u003c!\u002d\u002d! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. \u002d\u002d\u003e\u003cpath d=\u0022M470.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 256 265.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160zm-352 160l160-160c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L210.7 256 73.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z\u0022/\u003e\u003c/svg\u003e","collection":"font-awesome-6","icon":"solid/angles-right","wrap":false,"sanitize":false,"skaBlocks":{"cx":"w-4 h-auto text-current","css":".w-4{width:var(\u002d\u002dspacing-4)}.h-auto{height:auto}.text-current{color:currentColor}","t":1744868963},"skaBlocksWidth":{"v":{"$":{"@":"4"}}},"skaBlocksHeight":{"v":{"$":{"@":"auto"}}},"skaBlocksTextColor":{"v":{"$":{"@":"current"}}}} -->
<svg aria-hidden="true" class="w-4 h-auto text-current wp-block-ska-image" fill="currentColor" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc. --><path d="M470.6 278.6c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L402.7 256 265.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0l160-160zm-352 160l160-160c12.5-12.5 12.5-32.8 0-45.3l-160-160c-12.5-12.5-32.8-12.5-45.3 0s-12.5 32.8 0 45.3L210.7 256 73.4 393.4c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0z"></path></svg>
<!-- /wp:ska/image --></button>
<!-- /wp:ska/element -->
<button
x-data="{loading: false}"
x-on:fetch="fetch('/docs/wp-json/wp/v2/posts?per_page=1')
.then(response => response.json())
.then(post => post[0].title.rendered)
.then(title => $dispatch('success', title))
.catch(e => $dispatch('error'))
.finally(() => loading = false)"
x-on:success="$dispatch('ska-toast', {content: `The latest post on this site is titled: <strong>${$event.detail}</strong>`, type: 'success'})"
x-on:error="$dispatch('ska-toast', {content: `Failed fetching the latest post.`, type: 'error'})"
x-on:click="loading = true; $dispatch('fetch')"
:class="{loading}"
:disabled="loading"
>
...
</button>