Skip to main content

Connecting a Custom CMS

This guide provides a complete step-by-step walkthrough for creating a custom CMS integration for your Archibald application.

Step 1: Create a Custom CMSProvider (Server-Side)

The first step is to create a class that will communicate with your CMS on the server. This class must extend the abstract CMSProvider class.

  • Location: It's best practice to keep your integration code in a separate directory, e.g., integrations/custom-cms/server/provider.ts.
// integrations/custom-cms/server/provider.ts
import { CMSProvider, Page, DefaultResponse } from '@archibald/cms';

export class CustomCMSProvider extends CMSProvider {
constructor(private config: { apiUrl: string }) {
super();
}

public async getPage(options: { path: string }): Promise<DefaultResponse<Page | null>> {
try {
// 1. Fetch raw data from your CMS
const response = await fetch(`${this.config.apiUrl}/pages?path=${options.path}`);
if (!response.ok) {
throw new Error(`CMS Error: ${response.statusText}`);
}
const rawData = await response.json();

// 2. Transform the raw data into the Archibald Page format
const transformedData = this.transformPageData(rawData);

return {
data: transformedData,
error: null,
};
} catch (error) {
return {
data: null,
error: { message: error.message, code: 500 },
};
}
}

private transformPageData(data: any): Page {
// This is a critical step. You must map the data structure
// from your CMS to the `Page` interface required by Archibald.
// For complex transformations, this is where you would typically employ a data mapper.
return {
uid: data.id,
title: data.title,
template: data.templateName,
slots: data.slots.map(slot => ({
position: slot.position,
components: slot.components.map(component => ({
uid: component.id,
typeCode: component.type,
properties: component.properties,
})),
})),
};
}

// You would also implement getPreviewContext here if your CMS supports it
public async getPreviewContext(options: any): Promise<DefaultResponse<any | null>> {
// ... implementation
return { data: null, error: null };
}
}

Step 2: Create a Custom CMSAdapter (Client-Side)

The adapter lives on the client-side but doesn't talk to the CMS directly. It talks to your Archibald backend. In many simple cases, it may not need any custom logic.

  • Location: integrations/custom-cms/client/adapter.ts
// integrations/custom-cms/client/adapter.ts
import { CMSAdapter } from '@archibald/cms';

export class CustomCMSAdapter extends CMSAdapter {
// You can add custom client-side logic here. For example, you might
// override getPreviewWrapperComponent() to provide a React component
// that injects a preview script for your specific CMS.
}

Step 3: Configure the CMSModule (Server-Side)

Now, tell Archibald's server to use your new provider. This is done in the initModules method of your main Server class.

// src/shop/server/module/server.tsx
import { CMSModule } from '@archibald/cms';
import { CustomCMSProvider } from 'integrations/custom-cms/server/provider';
import { CoreServer } from '@archibald/server';

class Server extends CoreServer {
public async initModules() {
// Get your CMS config from environment variables or a config file
const { customCmsConfig } = this.configService.get();

await this.registerModules([
new CMSModule({
provider: new CustomCMSProvider({ apiUrl: customCmsConfig.apiUrl })
}),
// ... other modules
]);
}
}

Step 4: Configure the CMSClient (Client-Side)

On the client, configure the CMSClient to use your new MyCMSAdapter.

  • Location: src/shop/client/api/creators/cms.ts
// src/shop/client/api/creators/cms.ts
import { CMSClient } from '@archibald/cms';
import { CustomCMSAdapter } from 'integrations/custom-cms/client/adapter';
import { api } from 'shop/client/api';

export default new CMSClient({
adapter: CustomCMSAdapter,
api
});

Step 5: Provide the CMSClient to Your App

Finally, use the ProviderComposer in your main App component to make the CMSClient available to all hooks like usePage.

// src/shop/client/components/App.tsx
import { CMSClientProvider } from '@archibald/cms';
import { provider, ProviderComposer } from '@archibald/core';
import CMSClient from 'shop/client/api/creators/cms';

function App() {
return (
<ProviderComposer
providers={[
provider(CMSClientProvider, { client: CMSClient }),
// ... other providers like Auth, Analytics, etc.
]}
>
<AppLayout>
<AppRoutes />
</AppLayout>
</ProviderComposer>
);
}

With these steps, your Archibald application is now fully connected to your custom CMS.