Building a CMS Integration Plugin
A CMS integration plugin allows you to automatically synchronize your Vendure product catalog with an external Content Management System.
This is done in a way that establishes Vendure as the source of truth for the ecommerce's data.
This guide demonstrates how to build a production-ready CMS integration plugin. The principles covered here are designed to be CMS-agnostic, however we do have working examples for various platforms.
Platfroms covered in the guide:
Working Example Repository
This guide provides a high-level overview of building a CMS integration plugin. For complete implementations, refer to working examples repository
The code examples in this guide are simplified for educational purposes. The actual implementations contain additional features like error handling, retry logic, and performance optimizations.
Prerequisites
- Node.js 20+ with npm package manager
- An existing Vendure project created with the Vendure create command
- An access key to a CMS platform that provides an API
Core Concepts
This plugin leverages several key Vendure concepts:
- EventBus: Provides real-time notifications when entities are created, updated, or deleted.
- Job Queues: Ensures that synchronization tasks are performed reliably and asynchronously, with retries on failure.
- Plugin API: The foundation for extending Vendure with custom capabilities.
How It Works
The CMS integration follows a simple event-driven flow:
This ensures reliable, asynchronous synchronization with built-in retry capabilities.
Plugin Structure and Types
First, let's use the Vendure CLI to scaffold the basic plugin structure:
This command will create the basic plugin structure. Next, we'll generate the required services:
Now we start by defining the main plugin class, its services, and the configuration types.
Plugin Definition
The CmsPlugin class registers the necessary services (CmsSyncService, CmsSpecificService) and sets up any Admin API extensions.
Configuration Types
The plugin's configuration options are defined in a types.ts file.
Create this file in your plugin directory to define the interfaces. These options will be passed to the plugin from your vendure-config.ts.
This would be created for you automatically when you run the CLI command npx vendure add
Event-Driven Synchronization
The plugin uses Vendure's EventBus to capture changes in real-time.
In the onModuleInit lifecycle hook, we create job queues and subscribe to entity events.
Creating Job Queues and Subscribing to Events
You can also scaffold job queue handlers using the CLI:
This creates a productSyncQueue in the CmsSyncService. The service will be responsible for setting up the queues and processing the jobs. It will expose public methods to trigger new jobs.
Next, in the CmsPlugin, we subscribe to the EventBus and call the new service method to add a job to the queue whenever a relevant event occurs.
Implementing the Sync Logic
The sync logic is split into two services: a generic service to fetch data, and a specific service to communicate with the CMS.
CmsSyncService orchestrates the synchronization logic. It acts as the bridge between Vendure's internal systems and your CMS platform, handling data fetching, relationship resolution, and error management.
Separating orchestration logic from CMS-specific API calls allows for better testability and maintainability. The sync service handles Vendure-specific operations while CMS services focus on API communication.
Core Responsibilities
The sync service handles several critical functions:
- Entity Data Fetching: Retrieves complete entity data with necessary relations
- Translation Management: Handles Vendure's multi-language support
- Relationship Resolution: Manages complex entity relationships
- Error Handling: Provides consistent error handling and logging
Service Structure and Dependencies
The service follows Vendure's dependency injection pattern and requires several core Vendure services:
Product Synchronization
Product sync demonstrates the complete workflow from job processing to CMS communication:
Relationship Handling
The service includes methods to resolve entity relationships. For example, finding collections that contain a specific variant:
The service can also includes syncVariantToCms() and syncCollectionToCms() methods that follow the same pattern as the product sync shown above.
These implementations are omitted from this guide for brevity, but they handle their respective entity types with similar data fetching, relationship resolution, and error handling patterns.
The complete implementations can be found in the working example repositories.
This sync service provides the foundation for handling all Vendure-specific complexity while delegating CMS API communication to specialized services.
Platform specific setup
The complete, production-ready Storyblok implementation can be found in the Storyblok integration example. Refer to it for a minimal working implementation.
Setting up Storyblok Space
1. Create a Storyblok Account and Space
- Sign up at storyblok.com if you don't have an account
- Create a new Space (equivalent to a project in Storyblok)
- Choose a suitable plan based on your needs
2. Get Your API Credentials
- Navigate to Settings → Access Tokens in your Storyblok space
- Create a new Management API Token with write permissions
- Note down your Space ID (found in Settings → General)
3. Configure Environment Variables
Add these variables to your .env file:
The Storyblok Service
StoryblokService handles all Storyblok-specific operations including API communication, content type management, and data transformation. Key features include:
- Content Type Management: Automatically creates Vendure-specific content types (components) in Storyblok
- Story Management: CRUD operations for stories representing products, variants, and collections
- Relationship Handling: Manages references between products, variants, and collections
Basic Service Structure
The service follows Vendure's standard dependency injection pattern and implements OnApplicationBootstrap to ensure Storyblok is properly configured before handling sync operations.
Making API Requests
All Storyblok API communication is centralized through a single method that handles authentication, error handling, and response parsing. This approach ensures consistent behavior across all operations.
Data Transformation
Transformation methods convert Vendure entities into the format expected by Storyblok's API. The content object structure must match the component schema defined in Storyblok.
Relationship Handling
One of the most important aspects of CMS integration is maintaining relationships between entities. Products have variants, variants belong to collections, and these relationships need to be reflected in the CMS. Storyblok uses story UUIDs to create references between content pieces.
- Finding Related Entities
First, we need methods to query the Vendure database for related entities:
- Batch Story Lookups
We can also use batch lookups to find multiple stories at once:
- Building Relationships
Finally, we combine database queries with CMS lookups to build relationships:
CRUD Operations
These methods handle the basic Create, Read, Update, and Delete operations for stories in Storyblok. They follow REST API conventions and leverage the centralized request method for consistent behavior.
Final Plugin Configuration
This setup provides a complete Storyblok CMS integration that automatically creates the necessary content types and syncs your Vendure catalog with structured content in Storyblok.
The complete implementations can be found in the working example repositories.
Admin API Integration
To allow for manual synchronization through graphQL mutations, we can extend the Admin API with new mutations. Let's use the CLI to generate the API extensions:
Extending the GraphQL API
Implementing the Resolver
The resolver for these mutations re-uses the existing CmsSyncService to add a job to the queue.
Final Configuration
Finally, add the plugin to your vendure-config.ts file with the appropriate configuration for your chosen CMS platform.
Refer to the platform-specific configuration examples in the tabs above for the exact environment variables and options needed for your chosen CMS.
For complete, production-ready implementations, see the working examples: