diff --git a/blog/2026-03-20-storyblok-adapters.mdx b/blog/2026-03-20-storyblok-adapters.mdx new file mode 100644 index 0000000..225a354 --- /dev/null +++ b/blog/2026-03-20-storyblok-adapters.mdx @@ -0,0 +1,37 @@ +--- +title: Storyblok Adapter Setup and Usage +authors: [jannik] +tags: [storyblok, symfony] +--- + +The Storyblok docs now include a complete guide for the adapter-based setup. + +## New Documentation + +- [Adapters guide][1] with setup, configuration and usage. +- Dedicated docs for [Content API][5], [Management API][6], [ID Slug Mapper][7], and [Request Validator][8]. +- New docs for [Backend Edit URL Helper][9] and [Definitions Synced Event][10]. +- New [Asset Proxy][12] section with setup/configuration and usage details. +- New [More Features][13] section for miscellaneous mostly-internal helper features. + +## Updated Existing Pages + +- [Storyblok installation page][2] now reflects the adapter-based flow. +- [CLI docs][3] now describe adapter-scoped commands and include the post-sync `StoryblokDefinitionsSyncedEvent` hook. +- [Webhook docs][4] now use `AppStoryblokAdapter` examples. +- [Storyblok index][2] now links to the new Asset Proxy section and includes an events overview. +- `More Features` was moved to the bottom of the Storyblok sidebar order. + + +[1]: /docs/php/symfony/storyblok/adapters +[2]: /docs/php/symfony/storyblok +[3]: /docs/php/symfony/storyblok/cli +[4]: /docs/php/symfony/storyblok/webhook +[5]: /docs/php/symfony/storyblok/api/content-api +[6]: /docs/php/symfony/storyblok/api/management-api +[7]: /docs/php/symfony/storyblok/more-features/id-slug-mapper +[8]: /docs/php/symfony/storyblok/more-features/request-validator +[9]: /docs/php/symfony/storyblok/more-features/backend-edit-url-helper +[10]: /docs/php/symfony/storyblok/definitions-synced-event +[12]: /docs/php/symfony/storyblok/asset-proxy +[13]: /docs/php/symfony/storyblok/more-features diff --git a/docs/php/symfony/storyblok/adapters.mdx b/docs/php/symfony/storyblok/adapters.mdx new file mode 100644 index 0000000..3d01e94 --- /dev/null +++ b/docs/php/symfony/storyblok/adapters.mdx @@ -0,0 +1,171 @@ +--- +sidebar_position: -1 +--- + +# Adapters + +The Storyblok bundle uses adapters to connect to one or multiple Storyblok spaces. +Each adapter is meant to connect to a single Storyblok space, configured via `StoryblokConfig`. + + +## Setup + +Create one adapter class per Storyblok space: + +```php title="src/Storyblok/Adapter/AppStoryblokAdapter.php" +contentApi +``` + +### Management API + +[Management API docs](./api/management-api) + +Manage your Storyblok space via the Management API, for example when syncing component definitions. + +```php +$appStoryblok->managementApi +``` + +### ID Slug Mapper + +[ID Slug Mapper docs](./more-features/id-slug-mapper) + +Resolve between Story IDs and slugs using the content API. + +```php +$appStoryblok->idSlugMapper +``` + +### Request Validator + +[Request Validator docs](./more-features/request-validator) + +Validate incoming webhook requests against your adapter webhook configuration. + +```php +$appStoryblok->requestValidator +``` + + + +## Usage + +If you know which Storyblok adapter you want to use, you can inject it directly: + +```php +function example (AppStoryblokAdapter $storyblok) +{ + $storyblok->... +} +``` + +Sometimes you need to fetch the storyblok depending on a dynamic value, so you need to use the `StoryblokAdapterRegistry` for that: + +```php +function example (StoryblokAdapterRegistry $registry) +{ + $registry->getByKey("app"); + $registry->getBySpaceId("123456"); +} +``` + +[snail]: /docs/php/symfony/snail/ diff --git a/docs/php/symfony/storyblok/api/content-api.mdx b/docs/php/symfony/storyblok/api/content-api.mdx new file mode 100644 index 0000000..dee3a21 --- /dev/null +++ b/docs/php/symfony/storyblok/api/content-api.mdx @@ -0,0 +1,83 @@ +# Content API + +The Content API is available on the adapter as: + +```php +$appStoryblok->contentApi +``` + +Use it to fetch and hydrate Storyblok content for the configured adapter space. + +## Main Methods + +### `fetchSingleStory()` + +Fetches a single story by slug, id or uuid. + +```php +$appStoryblok->contentApi->fetchSingleStory("home"); +``` + +### `fetchStories()` + +Fetches stories for a specific story class. + +```php +$appStoryblok->contentApi->fetchStories(PageStory::class, "pages/*"); +``` + +### `fetchAllStories()` + +Fetches all stories (optionally filtered by slug pattern). + +```php +$appStoryblok->contentApi->fetchAllStories("pages/*"); +``` + +### `getSpaceInfo()` + +Returns metadata for the current Storyblok space. + +```php +$appStoryblok->contentApi->getSpaceInfo(); +``` + +### `fetchDatasourceEntries()` + +Fetches datasource entries from the Content API. + +```php +$appStoryblok->contentApi->fetchDatasourceEntries("countries"); +``` + +### `fetchFoldersInPath()` + +Fetches folders below a slug prefix. + +```php +$appStoryblok->contentApi->fetchFoldersInPath("pages"); +``` + +### `fetchFolderTitleMap()` + +Fetches a map of local folder URL to folder title. + +```php +$appStoryblok->contentApi->fetchFolderTitleMap("pages"); +``` + +### `fetchAllLinks()` + +Fetches all Storyblok links. + +```php +$appStoryblok->contentApi->fetchAllLinks(); +``` + +### `fetchSignedAssetUrl()` + +Fetches signed asset data for private assets. + +```php +$appStoryblok->contentApi->fetchSignedAssetUrl("https://a.storyblok.com/f/..."); +``` diff --git a/docs/php/symfony/storyblok/api/index.mdx b/docs/php/symfony/storyblok/api/index.mdx new file mode 100644 index 0000000..63a16ec --- /dev/null +++ b/docs/php/symfony/storyblok/api/index.mdx @@ -0,0 +1,89 @@ +# API + +Besides the [content api] and [management api], it is recommended to add a storyblok API, which is a wrapper for the content api and helps with purpose-built fetch methods. + +This way all your knowledge about the structure and types of your Storyblok space are encapsulated in one place. + + +```php +use Symfony\Component\DependencyInjection\Attribute\Exclude; + +#[Exclude] +class AppStoryblokApi +{ + public function __construct ( + private readonly ContentApi $contentApi, + ) {} + + /** + * @return NewsStory[] + */ + public function fetchNews (string $pageTree, string $locale) + { + return $this->contentApi->fetchStories( + storyType: NewsStory::class, + slug: \sprintf("%s/%s/news/*", $pageTree, $locale), + version: $version, + ); + } +} +``` + +Wire it up in your adapter: + +```php +class AppStoryblokAdapter +{ + public readonly AppStoryblokApi $api; + + public function __construct (...) + { + $this->api = new AppStoryblokApi($this->contentApi); + } +``` + +And use it like this: + +```php +$appStoryblok->api->fetchNews("website", "de-de") +``` + +## Caching + +If your API client is caching, you need to reset the cache regularly. As the API is not a service itself but just wrapped inside the adapter, you need to forward the call. + +First mark your adapter as resettable: + +```php +use Symfony\Contracts\Service\ResetInterface; + +class AppStoryblokAdapter extends AbstractStoryblokAdapter implements ResetInterface +{ + public readonly AppStoryblokApi $api; + + public function reset () + { + $this->api->reset(); + } +} +``` + +Then implement the cache reset in your API client: + +```php +use Symfony\Contracts\Service\ResetInterface; + +class AppStoryblokApi implements ResetInterface +{ + public function reset () + { + $this->cache = []; + } +} +``` + + + + +[content api]: ./content-api +[management api]: ./management-api diff --git a/docs/php/symfony/storyblok/api/management-api.mdx b/docs/php/symfony/storyblok/api/management-api.mdx new file mode 100644 index 0000000..71612af --- /dev/null +++ b/docs/php/symfony/storyblok/api/management-api.mdx @@ -0,0 +1,136 @@ +# Management API + +The Management API is available on the adapter as: + +```php +$appStoryblok->managementApi +``` + +Use it for write operations and administration tasks in the configured Storyblok space. + +## Main Methods + +### `syncComponent()` + +Creates or updates a component definition. + +```php +$appStoryblok->managementApi->syncComponent($componentConfig); +``` + +### `getOrCreatedComponentGroupUuid()` + +Resolves or creates a component group uuid. + +```php +$appStoryblok->managementApi->getOrCreatedComponentGroupUuid("Content"); +``` + +### `fetchAllRegisteredComponents()` + +Returns all component keys currently registered in the space. + +```php +$appStoryblok->managementApi->fetchAllRegisteredComponents(); +``` + +### `fetchComponentDefinitions()` + +Fetches all component definitions. + +```php +$appStoryblok->managementApi->fetchComponentDefinitions(); +``` + +### `syncDatasourceEntries()` + +Syncs datasource entries from your local mapping. + +```php +$appStoryblok->managementApi->syncDatasourceEntries("countries", $values); +``` + +### `fetchDatasourceEntries()` + +Fetches datasource entries via the Management API. + +```php +$appStoryblok->managementApi->fetchDatasourceEntries("countries"); +``` + +### `fetchAllAssets()` + +Fetches metadata of all assets. + +```php +$appStoryblok->managementApi->fetchAllAssets(); +``` + +### `updateAsset()` + +Updates an asset by id. + +```php +$appStoryblok->managementApi->updateAsset($assetId, $payload); +``` + +### `fetchAssetFolders()` + +Fetches the full asset folder tree. + +```php +$appStoryblok->managementApi->fetchAssetFolders(); +``` + +### `fetchAssetData()` + +Fetches metadata for a specific asset id. + +```php +$appStoryblok->managementApi->fetchAssetData($assetId); +``` + +### `exportTranslationsXmlFile()` + +Exports the translation XML for a story. + +```php +$appStoryblok->managementApi->exportTranslationsXmlFile($storyId); +``` + +### `importTranslationsXmlFile()` + +Imports translation XML for a story. + +```php +$appStoryblok->managementApi->importTranslationsXmlFile($storyId, $xmlContent); +``` + +### `fetchStory()` + +Fetches a raw management API story payload by story id. + +```php +$appStoryblok->managementApi->fetchStory($storyId); +``` + +### `updateStory()` + +Updates a story by story id. + +```php +$appStoryblok->managementApi->updateStory($storyId, $storyJson); +``` + +### `sendRequest()` + +Low-level method to send arbitrary requests to the Storyblok Management API. + +```php +$appStoryblok->managementApi->sendRequest("components"); +``` + +## Deprecated + +`fetchFolderTitleMap()` and `fetchFoldersInPath()` are deprecated in `ManagementApi`. +Use the Content API equivalents instead. diff --git a/docs/php/symfony/storyblok/asset-proxy/index.mdx b/docs/php/symfony/storyblok/asset-proxy/index.mdx new file mode 100644 index 0000000..f820495 --- /dev/null +++ b/docs/php/symfony/storyblok/asset-proxy/index.mdx @@ -0,0 +1,17 @@ +# Asset Proxy + +The Storyblok Asset Proxy lets your application serve Storyblok assets through your own app URL. + +Instead of directly serving `https://a.storyblok.com/...`, the URL is rewritten to your app, signed, and cached on disk. + +## What This Means for Your Application + +- Asset URLs are served from your application domain. +- Asset files are cached locally in `var/storyblok/assets` by default. +- Replaced and deleted assets are automatically invalidated when asset webhooks are enabled. +- Proxy URLs are signed, so only valid generated URLs are accepted. + +## Pages + +- [Setup and Configuration](./setup-and-configuration) +- [Usage](./usage) diff --git a/docs/php/symfony/storyblok/asset-proxy/setup-and-configuration.mdx b/docs/php/symfony/storyblok/asset-proxy/setup-and-configuration.mdx new file mode 100644 index 0000000..9cb4c49 --- /dev/null +++ b/docs/php/symfony/storyblok/asset-proxy/setup-and-configuration.mdx @@ -0,0 +1,55 @@ +--- +sidebar_position: 10 +--- + +# Setup and Configuration + +## Routing + +Load the bundle routes so the asset proxy endpoint is available: + +```yaml title="config/routes/storyblok.yaml" +storyblok: + prefix: /storyblok/ + resource: "@TorrStoryblokBundle/config/routes.yaml" +``` + +The proxy route is: + +```txt +/storyblok/asset/{spaceId}/{path} +``` + +## Storage Path + +By default, proxied files are stored in: + +```txt +%kernel.project_dir%/var/storyblok/assets +``` + +You can override this path via service configuration: + +```yaml title="config/services.yaml" +services: + Torr\Storyblok\Assets\Proxy\AssetProxy: + arguments: + $storagePath: "%kernel.project_dir%/var/custom-storyblok-assets" +``` + +## Webhook Integration for Cache Invalidation + +Asset proxy cache invalidation is triggered by asset webhooks: + +- `AssetReplaced` +- `AssetDeleted` + +So make sure your Storyblok webhook is configured and asset events are enabled. + +## Clearing the Proxy Cache + +Clear all cached proxy files: + +```bash +bin/console storyblok:assets:clear-proxy-storage +``` diff --git a/docs/php/symfony/storyblok/asset-proxy/usage.mdx b/docs/php/symfony/storyblok/asset-proxy/usage.mdx new file mode 100644 index 0000000..30165d5 --- /dev/null +++ b/docs/php/symfony/storyblok/asset-proxy/usage.mdx @@ -0,0 +1,42 @@ +--- +sidebar_position: 20 +--- + +# Usage + +## Rewriting Asset URLs + +Use `AssetProxyUrlGenerator` to rewrite Storyblok asset URLs to signed proxy URLs: + +```php +$assetProxyUrlGenerator->rewriteAssetUrl($storyblokAssetUrl); +``` + +If the URL is not a Storyblok asset URL, it is returned unchanged. + +## Request Flow + +1. Your app generates a signed proxy URL. +2. The request hits `/storyblok/asset/{spaceId}/{path}`. +3. The signature is validated. +4. If the file is not cached, it is downloaded from Storyblok and stored locally. +5. The cached file is streamed to the response. + +If the URL signature is invalid, the proxy returns `404`. + +## Download Behavior + +You can force file download by adding `download` as query parameter: + +```txt +?download=1 +``` + +Without it, files are returned as inline responses. + +## Application Impact + +- First request for an asset path is slower (cache miss + download). +- Following requests are faster (local file hit). +- Disk usage grows with cached assets. +- Webhook invalidation keeps replaced/deleted assets fresh. diff --git a/docs/php/symfony/storyblok/cli.mdx b/docs/php/symfony/storyblok/cli.mdx index af3c677..db0054e 100644 --- a/docs/php/symfony/storyblok/cli.mdx +++ b/docs/php/symfony/storyblok/cli.mdx @@ -1,7 +1,3 @@ ---- -sidebar_position: 20 ---- - # CLI To integrate your local definitions with Storyblok, you need to push your config to their API. @@ -13,11 +9,26 @@ Call the command via: bin/console storyblok:* ``` -## `storyblok:components:overview` +## Adapter Scope + +All commands accept optional adapter keys. +If no key is passed, all adapters are used. + +```bash +bin/console storyblok:debug +bin/console storyblok:debug main +bin/console storyblok:debug main marketing +``` + + +## `storyblok:debug` -Renders an overview of all locally registered components, their names and components + stories. +Renders debug details for your configured adapter(s): -It also renders a list of all components configured in Storyblok that don't match a local definition. +- Adapter key and Storyblok space metadata +- Components used in each adapter +- Unknown components in the space +- Component library and asset proxy stats :::tip If you have manually managed components in Storyblok, you can ignore them in this overview. @@ -26,10 +37,22 @@ However, renamed components are not automatically removed in Storyblok, so this ::: +## `storyblok:definitions:validate` + +Validates local component definitions for the selected adapter(s). + + ## `storyblok:definitions:sync` -Pushes your local component definitions to Storyblok. +Pushes local component definitions to Storyblok for the selected adapter(s). By default, you are asked to confirm to sync the structure. You can pass `--force` to automatically confirm the command. This can be used to automate your deployment. + +:::caution +`--force` is only allowed in production. +::: + +On successful sync, the bundle dispatches `StoryblokDefinitionsSyncedEvent`. +See [Definitions Synced Event](./definitions-synced-event) for listener setup. diff --git a/docs/php/symfony/storyblok/components/index.mdx b/docs/php/symfony/storyblok/components/index.mdx index 7d5b504..50e29b5 100644 --- a/docs/php/symfony/storyblok/components/index.mdx +++ b/docs/php/symfony/storyblok/components/index.mdx @@ -1,7 +1,3 @@ ---- -sidebar_position: 10 ---- - # Components Storyblok works and looks like a virtual filesystem. You can have folders and documents inside of them. diff --git a/docs/php/symfony/storyblok/components/recommended-directory-structure.mdx b/docs/php/symfony/storyblok/components/recommended-directory-structure.mdx index ca97290..df18346 100644 --- a/docs/php/symfony/storyblok/components/recommended-directory-structure.mdx +++ b/docs/php/symfony/storyblok/components/recommended-directory-structure.mdx @@ -7,6 +7,7 @@ sidebar_position: 30 ```text src/ └─ Storyblok/ + ├─ Adapter/ ├─ Api/ ├─ Component/ │ ├─ Block/ diff --git a/docs/php/symfony/storyblok/definitions-synced-event.mdx b/docs/php/symfony/storyblok/definitions-synced-event.mdx new file mode 100644 index 0000000..70fa956 --- /dev/null +++ b/docs/php/symfony/storyblok/definitions-synced-event.mdx @@ -0,0 +1,29 @@ +# Definitions Synced Event + +After a successful `storyblok:definitions:sync`, the bundle dispatches `StoryblokDefinitionsSyncedEvent`. + +## Event Data + +The event provides: + +- `io`: `TorrStyle` instance used by the sync command. +- `adapter`: the adapter that was synced. + +## Listener Example + +```php +use Symfony\Component\EventDispatcher\Attribute\AsEventListener; +use Torr\Storyblok\Event\StoryblokDefinitionsSyncedEvent; + +#[AsEventListener] +public function onDefinitionsSynced (StoryblokDefinitionsSyncedEvent $event) : void +{ + $event->io->writeln("Run post-sync work..."); + $event->adapter->managementApi; +} +``` + +## Notes + +- If multiple adapters are synced in one command run, one event is dispatched per adapter. +- The event is only dispatched on successful sync. diff --git a/docs/php/symfony/storyblok/image-focus.mdx b/docs/php/symfony/storyblok/image-focus.mdx index b890dc3..9ddf3a5 100644 --- a/docs/php/symfony/storyblok/image-focus.mdx +++ b/docs/php/symfony/storyblok/image-focus.mdx @@ -1,7 +1,3 @@ ---- -sidebar_position: 100 ---- - # Image Focus In Storyblok, you can set a focus point in a image. diff --git a/docs/php/symfony/storyblok/index.mdx b/docs/php/symfony/storyblok/index.mdx index ff8922b..3220ab2 100644 --- a/docs/php/symfony/storyblok/index.mdx +++ b/docs/php/symfony/storyblok/index.mdx @@ -18,31 +18,6 @@ This bundle provides helpers for ## Installation -You need to define various environment variables: - -```dotenv -# your space id as number -STORYBLOK_SPACE_ID= - -# your management token -STORYBLOK_MANAGEMENT_TOKEN= - -# your content token – with `preview` scope -STORYBLOK_CONTENT_TOKEN= -``` - -Then add the base config in `config/packages/storyblok.yaml`: - -```yaml -storyblok: - space_id: "%env(STORYBLOK_SPACE_ID)%" - management_token: "%env(STORYBLOK_MANAGEMENT_TOKEN)%" - content_token: "%env(STORYBLOK_CONTENT_TOKEN)%" -``` - - -Then install the package: - ```shell composer require 21torr/storyblok ``` @@ -52,38 +27,30 @@ If you are using Symfony Flex you are all set.
Manual configuration - You need to define various environment variables: + Load the routing: + + ```yaml title="config/routes/storyblok.yaml" + storyblok: + prefix: /storyblok/ + resource: '@TorrStoryblokBundle/config/routes.yaml' + ``` +
- ```dotenv title=".env" - # your space id as number - STORYBLOK_SPACE_ID= +## Adapter Setup - # your management token - STORYBLOK_MANAGEMENT_TOKEN= +The bundle is adapter-based. +You create one adapter per Storyblok space and configure each adapter with its own `StoryblokConfig`. - # your content token – with `preview` scope - STORYBLOK_CONTENT_TOKEN= +Continue with the [adapter guide](./adapters) for setup, usage and configuration details. - # the secret to validate webhooks - STORYBLOK_WEBHOOK_SECRET= - ``` +## Additional Helpers - Then add the base config: +- [Asset Proxy](./asset-proxy) +- [More Features](./more-features) - ```yaml title="config/packages/storyblok.yaml" - storyblok: - space_id: "%env(int:STORYBLOK_SPACE_ID)%" - management_token: "%env(STORYBLOK_MANAGEMENT_TOKEN)%" - content_token: "%env(STORYBLOK_CONTENT_TOKEN)%" - webhook: - secret: "%env(STORYBLOK_WEBHOOK_SECRET)%" - ``` +## Events Overview - and load the routing: +The Storyblok bundle dispatches these events: - ```yaml title="config/routes/storyblok.yaml" - storyblok: - prefix: /storyblok/ - resource: '@TorrStoryblokBundle/config/routes.yaml' - ``` - +- `StoryblokWebhookEvent` for incoming Storyblok webhooks ([Webhook docs](./webhook)). +- `StoryblokDefinitionsSyncedEvent` after successful component sync ([Definitions Synced Event](./definitions-synced-event)). diff --git a/docs/php/symfony/storyblok/more-features/backend-edit-url-helper.mdx b/docs/php/symfony/storyblok/more-features/backend-edit-url-helper.mdx new file mode 100644 index 0000000..1bd709e --- /dev/null +++ b/docs/php/symfony/storyblok/more-features/backend-edit-url-helper.mdx @@ -0,0 +1,23 @@ +# Backend Edit URL Helper + +`StoryblokBackendUrlGenerator` generates Storyblok backend edit links. + +## Usage + +Inject the helper: + +```php +StoryblokBackendUrlGenerator $backendUrlGenerator +``` + +Generate edit URL by story object: + +```php +$backendUrlGenerator->generateStoryEditUrl($story); +``` + +Generate edit URL by story id and space id: + +```php +$backendUrlGenerator->generateStoryEditUrlById(123456, "98765"); +``` diff --git a/docs/php/symfony/storyblok/more-features/id-slug-mapper.mdx b/docs/php/symfony/storyblok/more-features/id-slug-mapper.mdx new file mode 100644 index 0000000..6924eec --- /dev/null +++ b/docs/php/symfony/storyblok/more-features/id-slug-mapper.mdx @@ -0,0 +1,24 @@ +# ID Slug Mapper + +The ID Slug Mapper is available on the adapter as: + +```php +$appStoryblok->idSlugMapper +``` + +Use it to resolve a full slug from a Storyblok id or uuid. + +## Main Method + +### `getFullSlugById()` + +Returns the full slug for the given story id or uuid. +If the id is unknown, it returns `null`. + +```php +$appStoryblok->idSlugMapper->getFullSlugById("123456789"); +``` + +```php +$appStoryblok->idSlugMapper->getFullSlugById("95c8d1da-0f48-41f9-a376-c7bb8f72f23f"); +``` diff --git a/docs/php/symfony/storyblok/more-features/index.mdx b/docs/php/symfony/storyblok/more-features/index.mdx new file mode 100644 index 0000000..8cddde9 --- /dev/null +++ b/docs/php/symfony/storyblok/more-features/index.mdx @@ -0,0 +1,13 @@ +--- +sidebar_position: 1000 +--- + +# More Features + +These are miscellaneous Storyblok bundle features that are mainly used internally. + +In special cases, they can be used to implement custom requirements in your application. + +- [Backend Edit URL Helper](./backend-edit-url-helper) +- [Request Validator](./request-validator) +- [ID Slug Mapper](./id-slug-mapper) diff --git a/docs/php/symfony/storyblok/more-features/request-validator.mdx b/docs/php/symfony/storyblok/more-features/request-validator.mdx new file mode 100644 index 0000000..b69ceaa --- /dev/null +++ b/docs/php/symfony/storyblok/more-features/request-validator.mdx @@ -0,0 +1,24 @@ +# Request Validator + +The request validator is available on the adapter as: + +```php +$appStoryblok->requestValidator +``` + +Use it to validate incoming Storyblok webhook requests for the configured adapter. + +## Main Method + +### `isValidRequest()` + +Validates the request based on your adapter webhook config: + +- webhook signature (`webhook-signature`) for paid plans +- optional URL secret fallback for unpaid plans (`allowUrlWebhookSecret`) + +```php +$appStoryblok->requestValidator->isValidRequest($request, $urlSecret); +``` + +If both signature and URL secret are present at the same time, validation fails. diff --git a/docs/php/symfony/storyblok/webhook.mdx b/docs/php/symfony/storyblok/webhook.mdx index 9fe73ae..f313fc9 100644 --- a/docs/php/symfony/storyblok/webhook.mdx +++ b/docs/php/symfony/storyblok/webhook.mdx @@ -4,10 +4,10 @@ The Storyblok bundle automatically integrates in to all webhooks that are sent f ## Installation -After setting up the bundle routes[^1], you need to configure the webhook URL in Storyblok: +After setting up the bundle routes[^1] and your Storyblok adapter[^2], configure the webhook URL in Storyblok: ```txt -https://.../storyblok/webhook +https://.../storyblok/webhook/ ``` @@ -19,10 +19,32 @@ You should always use webhook secrets to secure your webhook endpoints. The webh On paid plans, you can use the native **Webhooks Secret** feature. Configure the webhook secret in Storyblok and in your bundle: -```yaml title="config/packages/storyblok.yaml" -storyblok: - webhook: - secret: "%env(STORYBLOK_WEBHOOK_SECRET)%" +```php +/my-secret ``` :::danger @@ -127,3 +149,4 @@ Make sure to include useful information in the response, as you can then debug y [^1]: Follow the [installation guide](./#installation). You can see the details about setting up the routing if you open the "manual installation" section. +[^2]: See [adapter setup](./adapters#setup).