Storyblok PHP Client
This is the official Storyblok PHP client to easily access the Content Delivery API and Management API.
🚀 Usage
With the Storyblok PHP client you can integrate two kinds of Storyblok APIs:
- Management API: typically used for managing data, like creating data, blocks, settings etc.
- Content Delivery API: typically used for retrieving data, for example when you want to build your public Web application.
In this README file you will find information for using the Storyblok PHP client, like:
- Installing Storyblok PHP client
- Using the Management API
- Using the Content Delivery API
- Retrieving Draft or Published content
- Managing cache
- Resolve Relations and Links
Installing the Storyblok PHP client
You can install the Storyblok PHP Client via composer. Storyblok's PHP client requires PHP version 7.3 to 8.2. The suggestion is to use an actively supported version of PHP (8.1 and 8.2).
If you want to install the stable release of Storyblok PHP client you can launch:
composer require storyblok/php-client
If you want to install the current development release, you can add the version dev-master
:
composer require storyblok/php-client dev-master
For executing the command above, you need to have composer installed on your development environment. If you need to install Composer, you can follow the official Composer documentation:
- Install Composer on GNU Linux / Unix / macOS
- Install Composer on Windows
We suggest using the latest version of PHP.
Management API
The Storyblok\ManagementClient instance
Now we are going to see how to initialize the Storyblok Management Client for the Management API](https://www.storyblok.com/docs/api/management) with your Personal OAuth Token.
The Personal OAuth token is taken from the "My Account" section. This token is used for read and write operations.
The class for using the Management API is the Storyblok\ManagementClient
class. When you are going to instance a new ManagementClient
object you can use the Personal OAuth Token as a parameter.
<?php
// Require composer autoload
require 'vendor/autoload.php';
// Use the Storyblok\ManagementClient class
use Storyblok\ManagementClient;
// Use the ManagementClient class
$managementClient = new ManagementClient('your-storyblok-oauth-token');
Now, you have the ManagementClient
object ($managementClient
), you can start to manage your Storyblok data.
Retrieve data, get() method
If you need to retrieve data, you have to perform an HTTP request with the GET
method.
The ManagementClient provides a get()
method for performing the HTTP request.
The mandatory parameter is the path of the API ( for example spaces/<yourSpaceId/stories
). The path defines which endpoint you want to use.
For retrieving a list of Stories:
$spaceId = 'YOUR_SPACE_ID';
$result = $managementClient->get('spaces/' . $spaceId . '/stories')->getBody();
print_r($result['stories']);
With getBody()
method you can access the body response, and then access the '
stories'` key, to access the story list.
Create data, post() method
If you need to create data, you have to perform an HTTP request with the POST
method.
The ManagementClient provides a post()
method for performing the HTTP request.
The mandatory parameter is the path of the API ( for example spaces/<yourSpaceId/stories/
), and the Story payload.
For creating a new story:
$spaceId = 'YOUR_SPACE_ID';
$story = [
"name" => "New Page",
"slug" => "page-1",
"content" => [
"component" => "page",
"body" => []
]
];
$result = $managementClient->post(
'spaces/' . $spaceId . '/stories/',
[ 'space' => $story ]
)->getBody();
print_r($result);
Update data, put() method
If you need to update data, you have to perform an HTTP request with PUT
method.
The ManagementClient provides a put()
method for performing the HTTP request.
The mandatory parameter is the path of the API ( for example spaces/<yourSpaceId/stories/<storyId>
), and the Story payload.
For updating the story:
$spaceId = 'YOUR_SPACE_ID';
$storyId= 'theStoryId';
$story = [
"name" => "Update Home Page"
];
$result = $managementClient->put(
'spaces/' . $spaceId . '/stories/' . $storyId,
[ 'space' => $story ]
)->getBody();
print_r($result);
Delete data, delete() method
If you need to delete data, you have to perform an HTTP request with the DELETE
method.
The ManagementClient provides a delete()
method for performing the HTTP request.
The mandatory parameter is the path of the API, defining also the identifier of the entry you want to delete ( for example spaces/<yourSpaceId/stories/<storyId>
).
For deleting a story:
$spaceId = 'YOUR_SPACE_ID';
$storyId = 'YOUR_STORY_ID';
$result = $managementClient->delete('spaces/' . $spaceId . '/stories/' . $storyId)->getbody();
print_r($result);
Content Delivery API
The Storyblok\Client instance
Now we are going to see how to initialize the Storyblok Client class for consuming the Content Delivery API V2, with the Access Token. You can retrieve the access token from the "Settings > Access Tokens" tab (in your space, in Stroyblok UI).
<?php
// Require composer autoload
require 'vendor/autoload.php';
// Use the Storyblok\Client class
use Storyblok\Client;
// Use the Client class
$client = new Client('your-storyblok-draft-token');
If you want to use an alias to refer to the Storyblok\Client
class, you can use the use ... as ...
statement:
require 'vendor/autoload.php';
use Storyblok\Client as StoryblokClient;
// Use the Storyblok\Client class via alias
$client = new StoryblokClient('your-storyblok-draft-token');
Using spaces created in the US region
When you create a Space, you can select the region: EU or US.
If you want to access a Space created in US region, you need to define the apiRegion
parameter with 'us' value (or 'US'):
use Storyblok\Client;
$client = new Client(
apiKey: 'your-storyblok-draft-token',
apiRegion: 'us'
);
If you are still using PHP 7.x, you have to use the old notation (without named arguments):
use Storyblok\Client;
$client = new Client(
'your-storyblok-draft-token',
null,
'v2',
false,
'us'
);
Now you have the Storyblok\Client
instance you can start consuming data.
Load a Story by slug
require 'vendor/autoload.php';
use Storyblok\Client as StoryblokClient; // you can use also an alias
$client = new StoryblokClient('your-storyblok-private-token');
$data = $client->getStoryBySlug('home')->getBody();
// access to the body response...
print_r($data["story"]);
echo $data["cv"] . PHP_EOL;
print_r($data["rels"]);
print_r($data["links"]);
Load a Story by UUID
require 'vendor/autoload.php';
use Storyblok\Client as StoryblokClient; // you can use also an alias
$client = new StoryblokClient('your-storyblok-private-token');
$client->getStoryByUuid('0c092d14-5cd4-477e-922c-c7f8e330aaea');
$data = $client->getBody();
The structure of the data returned by the getBody()
of the getStoryByUuid()
method, has the same structure of the getStoryBySlug()
so: story
, cv
, rels
, links
.
Load a list of Stories
If you need to retrieve a list of stories you can use the getStories()
method.
You can use the parameter to filter the stories.
For example, if you want to retrieve all entries from a specific folder you can use starts_with
option in this way:
$client = new \Storyblok\Client('your-storyblok-private-token');
// Get all Stories from the article folder
$client->getStories(['starts_with' => 'article']);
$data = $client->getBody();
print_r($data["stories"]);
echo $data["cv"] . PHP_EOL;
print_r($data["rels"]);
print_r($data["links"]);
Under the hood, the starts_with
option, filters entries by full_slug
.
Load all entries
Because the response from Storyblok API could be paginated, you should walk through all the pages to collect all the entries.
The Storyblok PHP Client provides you a helper named getAll()
for retrieving all the entries.
Under the hood, the getAll()
method performs all the API call according to the pagination data (total, per page etc).
Example, retrieving all stories:
$client = new Client('your-storyblok-private-token');
$options = $client->getApiParameters();
$options['per_page'] = 3;
$stories = $client->getAll('stories/', $options);
If you want to retrieve the array of the responses for each call:
$client = new Client('your-storyblok-private-token');
$options = $client->getApiParameters();
$options['per_page'] = 3;
$response = $client->getAll('stories/', $options, true);
Load a list of datasource entries
With the Storyblok\Client
you have also the getDatasourceEntries()
method for retrieving the list of key/values of the datasource:
$client = new \Storyblok\Client('your-storyblok-private-token');
// Get category entries from datasource
$client->getDatasourceEntries('categories');
// will return as ['name']['value'] Array for easy access
$nameValueArray = $client->getAsNameValueArray();
// instead, if you want to retrieve the whole response, you can use getBody() method:
$data = $client->getBody();
If you want to receive also the dimension values besides the default values in one datasource entry you can use the option dimension when you call getDatasourceEntries() method. You could use dimensions for example when you are using datasource for storing a list of values and you want a translation for the values. In this case, you should create one dimension for each language.
$client = new \Storyblok\Client('your-storyblok-private-token');
// Get product entries with dimension 'de-at'
$client->getDatasourceEntries('products', ['dimension'=> 'de-at']);
// show the dimension values:
foreach ($client->getBody()['datasource_entries'] as $key => $value) {
echo $value['dimension_value'] . PHP_EOL;
}
Load a list of tags
$client = new \Storyblok\Client('your-storyblok-private-token');
// Get all Tags
$client->getTags();
// will return the whole response
$data = $client->getBody();
// will return as ['tagName1', 'tagName2'] Array for easy access
$stringArray = $client->getAsStringArray();
Access to the Responses Headers
When you perform a request to Content Delivery API, you can access the headers of the HTTP response.
For example, after you call the getStories()
method (for retrieving a list of stories) you can access to the HTTP response headers via getHeaders()
method:
$client = new \Storyblok\Client('your-storyblok-private-token');
$result = $client->getStories();
$headersData = $client->getHeaders();
print_r($headersData);
Retrieving Draft or Published content
In a Web application where the query string is available, the content delivery client checks automatically the GET parameters:
_storyblok
to get the draft version of a specific story_storyblok_published
to clear the cache.
If you want to override this "default" behavior, or you are in a non-web context (for example you are implementing a command line tool), to retrieve the draft content (for example a not yet published story) you have to use the editMode()
method.
If you want to retrieve the published content (for example a published story) you have to use the editMode(false)
method with false
parameter.
require 'vendor/autoload.php';
use Storyblok\Client as StoryblokClient; // you can use also an alias
$client = new StoryblokClient('your-storyblok-private-token');
$client->editMode(); // forcing draft mode
$data = $client->getStoryBySlug('home')->getBody();
// access to the body response...
print_r($data["story"]);
echo $data["cv"] . PHP_EOL;
print_r($data["rels"]);
print_r($data["links"]);
Managing cache
When you perform an API request you can use the caching mechanism provided by the Storyblok PHP client.
When you initialize the Storyblok\Client
you can set the cache provider.
For example, using the setCache()
method you can define the provider (for example filesystem) and an array of options. In case you are using the filesystem as storage of cache items, you can set the path with path
option:
$client = new \Storyblok\Client('your-storyblok-private-token');
$client->setCache('filesystem', [ 'path' => 'cache']);
$result = $client->getStories();
print_r($result);
You can set a TTL value for the cache via default_lifetime
option.
$client = new \Storyblok\Client('your-storyblok-private-token');
$client->setCache('filesystem',
[
'path' => 'cache',
'default_lifetime' => 3600
]);
$result = $client->getStories();
print_r($result);
The caching mechanism uses under the hood the Symfony Cache package. So, you can use the Adapter supported the Symfony Cache. For example, for using a MySql database as cache storage, you can setup the connection via the PHP PDO class:
$client = new \Storyblok\Client('your-storyblok-private-token');
$pdo = new PDO('mysql:host=127.0.0.1;dbname=db_php-client;charset=utf8mb4;', "root");
$client->setCache('mysql', ['pdo' => $pdo]);
$result = $client->getStories();
print_r($result);
Clearing the cache (Optionally if using setCache)
In order to flush the cache when the user clicks publish, you need to listen to the published event in javascript or define a webhook in the space settings that clears the cache on your server.
<script type="text/javascript" src="//app.storyblok.com/f/storyblok-latest.js"></script>
<script type="text/javascript">
storyblok.init()
storyblok.on('published', function() {
$.ajax({
url: '/clear.php'
})
})
</script>
In clear.php:
$client = new \Storyblok\Client('your-storyblok-private-token');
$client->setCache('filesystem', array('path' => 'cache'));
// Flush the whole cache when a story has been published
$client->flushCache();
// Or empty the cache for one specific item only
$client->deleteCacheBySlug('home');
Generate a navigation tree
$tree = $client->editMode()->getLinks()->getAsTree();
echo '<ul>';
foreach ($tree as $item) {
echo '<li>' . $item['item']['name'];
if (!empty($item['children'])) {
echo '<ul>';
foreach ($item['children'] as $item2) {
echo '<li>' . $item2['item']['name'] . '</li>';
}
echo '</ul>';
}
echo '</li>';
}
echo '</ul>';
Nginx SSI - Server Side Includes
Use the following script if you have Nginx SSI enabled and experience issues with printing the _editable html comments directly to manually parse the Storyblok HTML editable comments: https://gist.github.com/DominikAngerer/ca61d41bae3afcc646cfee286579ad36
Relationships and Links Resolving
In order to resolve relations you can use the resolveRelations
method of the client passing a comma separated list of fields:
$client = new \Storyblok\Client('your-storyblok-private-token');
$client->resolveRelations('component_name1.field_name1,component_name2.field_name2')
$client->getStoryBySlug('home');
Another example:
use Storyblok\Client;
$client = new Client('your-storyblok-private-token');
$client->resolveRelations('popular-articles.articles');
$result = $client->getStoryBySlug("home")->getBody();
In order to resolve links, you can use the resolveLinks
method passing the specific type of resolving you want to perform among url
, story
or link
:
$client = new \Storyblok\Client('your-storyblok-private-token');
$client->resolveLinks('url')
$client->getStoryBySlug('home');
When using the CDN API V1, you can't resolve relationships of resolved entries and the resolved entries are injected in the field of the relationship. The same happens with links resolving.
When using the CDN API V2 you can resolve also nested relationships in the resolved entries (just 2 levels deep), but the resolved entries are not injected in the fields, they are inserted in an array called rels
which is in the root object. The resolved links will be placed in an array called links
.
In case you are using the API V2, to keep a consistent behaviour with the API V1, this client will inject the resolved entries and links inside the fields for you.
Code Quality
The package includes tools for tests and code formatting:
- PestPHP
- PHP CS Fixer To execute the code quality suite you can use:
composer run all-check
that executes:
- vendor/bin/php-cs-fixer fix
- vendor/bin/pest
🔗 Related Links
- Storyblok & PHP on GitHub: Check all of our PHP open source repos;
- Storyblok PHP Richtext Renderer: This package allows you to get an HTML string from the richtext field of Storyblok;
- Storyblok Laravel Tutorial : Add a Headless CMS to Laravel in 5 minutes.
ℹ️ More Resources
Support
-
Bugs or Feature Requests? Submit an issue;
-
Do you have questions about Storyblok or do you need help? Join our Discord Community.
Contributing
Please see our contributing guidelines and our code of conduct. This project use semantic-release for generate new versions by using commit messages and we use the Angular Convention to naming the commits. Check this question about it in semantic-release FAQ.
License
This repository is published under the MIT license.