This section provides a comprehensive guide for migrating from an existing web-builder setup to the Erxes CMS when working with Next.js applications.
Migrating from a web-builder setup to Erxes CMS involves updating your configuration and queries to work with the Erxes GraphQL API. This guide will help you transition your existing Next.js application to use Erxes CMS for content management.
Before starting the migration process, ensure you have:
Update your environment variables to point to the erxes CMS domain and use the Client Portal token.
/** @type {import('next').NextConfig} */
const nextConfig = {
env: {
ERXES_API_URL: "https://[your-domain].next.erxes.io",
ERXES_APP_TOKEN: "YOUR_CLIENT_PORTAL_TOKEN",
},
};
module.exports = nextConfig;
When working with CMS APIs, erxes requires the token to be sent using the x-app-token header.
import { ApolloClient, InMemoryCache, createHttpLink } from "@apollo/client";
import { setContext } from "@apollo/client/link/context";
const httpLink = createHttpLink({
uri: `${process.env.ERXES_API_URL}/gateway/graphql`,
});
const authLink = setContext((_, { headers }) => ({
headers: {
...headers,
"x-app-token": process.env.ERXES_APP_TOKEN,
},
}));
export const apolloClient = new ApolloClient({
link: authLink.concat(httpLink),
cache: new InMemoryCache(),
});
Use cpPostList to fetch CMS posts.
import { gql } from "@apollo/client";
export const cmsPostList = gql`
query PostList(
$type: String
$featured: Boolean
$categoryIds: [String]
$searchValue: String
$status: PostStatus
$tagIds: [String]
$sortField: String
$sortDirection: String
) {
cpPostList(
featured: $featured
type: $type
categoryIds: $categoryIds
searchValue: $searchValue
status: $status
tagIds: $tagIds
sortField: $sortField
sortDirection: $sortDirection
) {
totalCount
posts {
_id
title
content
excerpt
featured
status
createdAt
updatedAt
thumbnail {
url
}
categories {
_id
name
}
images {
url
type
name
}
}
}
}
`;
Use cpPostDetail to fetch a specific post by slug or ID.
export const cmsPostDetail = gql`
query PostDetail($slug: String, $id: String) {
cpPostDetail(slug: $slug, _id: $id) {
_id
title
content
excerpt
featured
status
createdAt
updatedAt
thumbnail {
url
}
categories {
_id
name
}
images {
url
type
name
}
author {
... on User {
_id
email
}
... on ClientPortalUser {
fullName
firstName
lastName
}
}
}
}
`;
import { useQuery } from "@apollo/client";
import { cmsPostList } from "@/graphql/queries";
export default function BlogPage() {
const { data, loading, error } = useQuery(cmsPostList, {
variables: {
categoryIds: ["c-exNoBpJp4WUd1fgUB9m"],
status: "published",
},
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error loading posts</div>;
const posts = data?.cpPostList?.posts || [];
return (
<div>
<h1>Blog Posts</h1>
{posts.map(post => (
<article key={post._id}>
<h2>{post.title}</h2>
<p>{post.excerpt}</p>
<span>Published: {new Date(post.createdAt).toLocaleDateString()}</span>
</article>
))}
</div>
);
}
"use client";
import { useQuery } from "@apollo/client";
import { cmsPostDetail } from "@/graphql/queries";
export default function PostPage({ params }) {
const { data, loading, error } = useQuery(cmsPostDetail, {
variables: {
slug: params.slug,
},
});
if (loading) return <div>Loading...</div>;
if (error) return <div>Error loading post</div>;
const post = data?.cpPostDetail;
return (
<article>
<h1>{post.title}</h1>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
<div>By: {post.author.fullName || post.author.email}</div>
</article>
);
}
categoryIds must be an array of stringsIf you're migrating from the existing cmsPosts query, update your queries:
Before:
import { gql } from "@apollo/client";
export const cmsPosts = gql`
query CmsPosts($clientPortalId: String, $featured: Boolean, $type: String, $categoryId: String, $searchValue: String, $status: PostStatus, $page: Int, $perPage: Int, $tagIds: [String], $sortField: String, $sortDirection: String, $language: String) {
cmsPosts(clientPortalId: $clientPortalId, featured: $featured, type: $type, categoryId: $categoryId, searchValue: $searchValue, status: $status, page: $page, perPage: $perPage, tagIds: $tagIds, sortField: $sortField, sortDirection: $sortDirection, language: $language) {
_id
title
content
// ... other fields
}
}
`;
After:
import { gql } from "@apollo/client";
export const cmsPostList = gql`
query PostList(
$type: String
$featured: Boolean
$categoryIds: [String]
$searchValue: String
$status: PostStatus
$tagIds: [String]
$sortField: String
$sortDirection: String
) {
cpPostList(
featured: $featured
type: $type
categoryIds: $categoryIds
searchValue: $searchValue
status: $status
tagIds: $tagIds
sortField: $sortField
sortDirection: $sortDirection
) {
totalCount
posts {
_id
title
content
// ... other fields
}
}
}
`;
cmsPosts → cpPostListcategoryId → categoryIds (array format)posts fieldtotalCount for paginationcategoryId → categoryIds)ERXES_API_URLERXES_APP_TOKENThis guide is fully compatible with MDX-based documentation systems such as next-mdx-remote, contentlayer, or custom doc portals.
Edit this page