Blocks are the key err.. building block of your pages. Every Storyblok component is transformed into a Block class. The class they become is determined by the component’s name - if you have a matching Block class that will be used, for example a component called cat-images
transforms into App\Storyblok\Pages\CatImages
if available. Blocks should extend Riclep\Storyblok\Block
or App\Storyblok\DefaultBlock
.
<?php
namespace App\Storyblok\Blocks;
use Riclep\Storyblok\Block;
class CatImages extends Block
{
}
Sometimes you may want to run some code when a Block is created. To do this implement an init()
method on your block. This is run after any built-in transformations outlined below and is free to modify the Block and it’s contents as required.
Blocks borrow some concepts from Laravel’s Eloquent models to make using them feel familiar such as creating accessors or casting variables to dates, but we don’t stop there, we also have a bunch of helpful features for Storyblok content - automatically transforming markdown fields, apply typographical fixes and flourishes or returning rendered HTML - we want to help make building websites enjoyable.
Sometimes it’s useful to know the parent and ancestors of the current Block. Every Block has a _componentPath
property which is an array of the names of every Storyblok component passed through to reach the current point. There are several methods to help you work with this informtion.
// Returns the current component’s name
$currentComponent->component(); // 'current-component'
// Returns the current path
$currentComponent->componentPath(); // ['root-component', 'ancestor-component', 'parent-component', 'current-component']
// Checks if a compontent has a particular child
$parentComponent->hasChildComponent('current-component'); // true
$parentComponent->hasChildComponent('something-else'); // false
// Returns the component name ‘x’ generations ago
$currentComponent->getAncestorComponent(2); // 'ancestor-component'
// Checks if this has a certain parent
$currentComponent->isChildOf('parent'); // true
// Checks if this has a certain ancestor
$currentComponent->isAncestorOf('ancestor-component'); // true
Wouldn’t it be great to be able to create CSS classes when working in Blade that help you style nested Blocks? Don’t worry, we have you covered.
When using Storyblok’s Date/Time field you’ll probably want to convert it into something more handy to use in PHP. Simply define a $dates
property on your Block containing an array of field names and we’ll convert them to Carbon objects.
protected $dates = ['release_date'];
Storyblok includes Markdown fields (with an optional visual editor that’s perfect for clients!) and we make it super easy to convert them to HTML. Just add a $markdown
property containing an array of field names and, hey presto, we magically create an HTML version thanks to the power of CommonMark. We keep your original field untouched should you wish to do anything else with it and create a duplicate suffixed with _html
.
// creates a new content item called $interesting_story_html
protected $markdown = ['interesting_story'];
Need even more power than Markdown? Use the Rich Text fieldtype in Storyblok. To convert it to HTML include a $richtext
property on your Block. This will created a duplicate field suffixed by _html
containing the processed content.
// creates a new content item called $i_am_rich_html
protected $richtext = ['i_am_rich'];
{warning} The package doesn’t currently support components inside richtext fields.
You often want to wrap content from textareas in paragraph tags to allow better control of the formatting. This is really simple to do, just add a $autoParagraphs
property containing an array of the fields to convert. This will add new attributes to your block appended with _html
and leave the original content untouched.
// creates a new content item called $textarea_content_html
protected $autoParagraphs = ['textarea_content'];
Just like with Laravel’s models sometimes you want to manipulate the data each time you use it so to quote Taylor Otwell in the Laravel docs (only we use proper quote marks!) ‘To define an accessor, create a getFooAttribute
method on your Block where Foo
is the “studly” cased name of the field you wish to access.’ When calling $kitten->first_name
the accessor will be used and applying any transformations you specified.
<?php
namespace App;
use Riclep\Storyblok\Block;
class KittenBlock extends Block
{
/**
* Get the kitten’s first name.
*
* @return string
*/
public function getFirstNameAttribute()
{
return ucfirst($this->content['first_name']);
}
}
You’re not limited to only transforming existing fields, you can also create new content fields, although regular methods on your Block may be more favourable in some cases. A basic example to return a Kitten’s full name.
<?php
namespace App;
use Riclep\Storyblok\Block;
class KittenBlock extends Block
{
/**
* Get the kitten’s first name.
*
* @return string
*/
public function getFullNameAttribute()
{
return ucfirst($this->content['first_name']) . ' ' . ucfirst($this->content['surname']);
}
}
And a more complex example: you have a component in Storyblok that allows the user to enter text and choose a background colour using the Colorpicker component. You want to ensure there is enough contrast between the text and background colours and you want to do this automatically. Here we use the ColorContrast package to work out if the user selected colour is light or dark and return a different string accordingly which can be used for styling with CSS.
<?php
namespace App\Storyblok;
use ColorContrast\ColorContrast;
use Riclep\Storyblok\Block;
class ServiceBlock extends Block
{
# creates text_class content attribute containing the contrasting class name
public function getTextClassAttribute() {
$contrast = new ColorContrast();
$complimentary = $contrast->complimentaryTheme($this->content['colour']->color);
return $complimentary === ColorContrast::LIGHT ? 'light-text' : 'dark-text';
}
}
Or perhaps you want to transform an image using Storyblok’s CDN, although a method might make more sense here so you can pass the desired dimensions in to it.
<?php
namespace App\Storyblok;
use Riclep\Storyblok\Block;
class ServiceBlock extends Block
{
# $block->image
# this simply transforms the existing content field called image
public function getImageAttribute()
{
return str_replace('//a.storyblok.com', '//img2.storyblok.com/filters:quality(80)', $this->image);
}
# $block->small_image
# it’s a tiny version
public function getSmallImageAttribute()
{
return str_replace('//a.storyblok.com', '//img2.storyblok.com/50x0/filters:quality(40)', $this->image);
}
# $block->large_image
# but this one is large and will eat your mobile data
public function getLargeImageAttribute()
{
return str_replace('//a.storyblok.com', '//img2.storyblok.com/5000x0/filters:quality(100)', $this->image);
}
}
{info} Storyblok also have a Cloudinary app that provides more powerful image manipulation.
One of Storyblok’s most powerful features is its visual editor. This lets you click text and images within your page and Storyblok will load the correct content in the editing panel allowing you to make changes quickly. There is no need to manually navigate the nested components that make up your page.
It does this by searching for comments injected into your HTML. To add them simply call the editableBridge()
method in your Blade views just before the opening tag of the block you wish to make editable.
{!! $story->editableBridge() !!}
<section>
<h1 class="t-1">{{ $story->title }}</h1>
<p class="t-2">{{ $story->introduction }}</p>
</section>
Don’t worry, these comments are only added when viewing your website within the Storyblok editor, your HTML is left clean and pure the rest of the time.
{warning} If you are having problems getting this live preview to work check the trouble shooting page.