Overview
The Custom Pages API (subset of db.cms) enables creation and management of dynamic pages with a flexible section-based architecture. Each page consists of multiple sections that can be reordered and configured.
Core Methods
These are the primary methods from db.cms used for page management:
getPages
Retrieves all custom pages.
db.cms.getPages(): CustomPage[]
Array of all custom pages (published and draft)
const pages = db.cms.getPages();
const published = pages.filter(p => p.status === 'Published');
const drafts = pages.filter(p => p.status === 'Draft');
getPageBySlug
Retrieves a single page by its URL slug.
db.cms.getPageBySlug(slug: string): CustomPage | undefined
URL-friendly slug (e.g., “quienes-somos”)
The matching page, or undefined if not found
const page = db.cms.getPageBySlug('quienes-somos');
if (page) {
console.log(page.title);
}
savePage
Creates or updates a page.
db.cms.savePage(page: CustomPage): CustomPage[]
Complete page object (creates if new id, updates if existing)
deletePage
Deletes a page by ID.
db.cms.deletePage(id: string): CustomPage[]
Page Structure
CustomPage Interface
interface CustomPage {
id: string;
slug: string;
title: string;
status: 'Published' | 'Draft';
sections: PageSection[];
seo: SEOConfig;
}
Section Types
Pages are built from reusable section components:
Hero Section
Large header with image and CTA.
{
id: 's_hero',
type: 'Hero',
order: 0,
content: {
title: 'Quiénes Somos',
subtitle: 'Una comunidad global',
imageUrl: 'https://images.unsplash.com/photo-...',
ctaText: 'Ver Sedes',
ctaLink: '/about/locations'
}
}
Text Section
Markdown or HTML text content.
{
id: 's_text_1',
type: 'Text',
order: 1,
content: {
text: '## Un legado de sabiduría\n\nFundada hace más de 80 años...'
}
}
Stats Section
Key statistics display.
{
id: 's_stats',
type: 'Stats',
order: 2,
content: {
items: [
{ label: 'Año de Fundación', value: '1937', icon: 'Calendar' },
{ label: 'Países', value: '20+', icon: 'Globe' }
]
}
}
CTA Section
Call-to-action block.
{
id: 's_cta',
type: 'CTA',
order: 3,
content: {
title: 'Nuestra Misión',
text: 'Fomentar el desenvolvimiento espiritual...',
buttonText: 'Saber más',
buttonLink: '/about'
}
}
Timeline Section
Chronological timeline display.
{
id: 's_timeline',
type: 'Timeline',
order: 4,
content: {}
}
Cards Section
Grid of cards.
{
id: 's_cards',
type: 'Cards',
order: 5,
content: {
items: [
{ title: 'Card 1', description: 'Desc...', icon: 'Star' }
]
}
}
Gallery Section
Image gallery.
{
id: 's_gallery',
type: 'Gallery',
order: 6,
content: {
images: [
{ url: 'https://...', alt: 'Image 1' }
]
}
}
ResourcesGrid Section
Grid of downloadable resources.
{
id: 's_resources',
type: 'ResourcesGrid',
order: 7,
content: {}
}
EventsCalendar Section
Upcoming events calendar.
{
id: 's_calendar',
type: 'EventsCalendar',
order: 8,
content: {}
}
MethodPillars Section
CAFH method pillars display.
{
id: 's_pillars',
type: 'MethodPillars',
order: 9,
content: {}
}
Complete Examples
Creating a New Page
const newPage: CustomPage = {
id: `p_${Date.now()}`,
title: 'Nuestra Historia',
slug: 'nuestra-historia',
status: 'Draft',
sections: [
{
id: 's_hero',
type: 'Hero',
order: 0,
content: {
title: 'Nuestra Historia',
subtitle: 'Un recorrido por nuestros hitos',
imageUrl: 'https://images.unsplash.com/photo-...'
}
},
{
id: 's_text_1',
type: 'Text',
order: 1,
content: {
text: '## Nuestros Inicios\n\nEn 1937...'
}
},
{
id: 's_timeline',
type: 'Timeline',
order: 2,
content: {}
}
],
seo: {
title: 'Nuestra Historia | Cafh',
description: 'Conoce la historia de Cafh',
keywords: ['historia', 'cafh', 'fundación']
}
};
db.cms.savePage(newPage);
const landingPage: CustomPage = {
id: `p_${Date.now()}`,
title: 'Únete a Cafh',
slug: 'unete',
status: 'Published',
sections: [
{
id: 's_hero',
type: 'Hero',
order: 0,
content: {
title: 'Únete a Cafh',
subtitle: 'Comienza tu camino de crecimiento espiritual',
imageUrl: 'https://...',
ctaText: 'Registrarse',
ctaLink: '/login'
}
},
{
id: 's_stats',
type: 'Stats',
order: 1,
content: {
items: [
{ label: 'Miembros activos', value: '5,000+', icon: 'Users' },
{ label: 'Países', value: '20+', icon: 'Globe' },
{ label: 'Años de historia', value: '85+', icon: 'Calendar' }
]
}
},
{
id: 's_cards',
type: 'Cards',
order: 2,
content: {
items: [
{
title: 'Meditación',
description: 'Práctica diaria guiada',
icon: 'Heart'
},
{
title: 'Retiros',
description: 'Experiencias transformadoras',
icon: 'Mountain'
},
{
title: 'Comunidad',
description: 'Conexión con otros buscadores',
icon: 'Users'
}
]
}
},
{
id: 's_cta',
type: 'CTA',
order: 3,
content: {
title: '¿Listo para comenzar?',
text: 'Únete a miles de personas en su camino espiritual',
buttonText: 'Crear Cuenta',
buttonLink: '/login'
}
}
],
seo: {
title: 'Únete a Cafh | Comunidad Espiritual',
description: 'Comienza tu camino de crecimiento espiritual con Cafh',
keywords: ['cafh', 'únete', 'registro', 'meditación', 'comunidad']
}
};
db.cms.savePage(landingPage);
Updating a Page
const page = db.cms.getPageBySlug('quienes-somos');
if (page) {
// Update hero title
const heroSection = page.sections.find(s => s.type === 'Hero');
if (heroSection) {
heroSection.content.title = 'Nuevo Título';
}
// Add new section
page.sections.push({
id: `s_${Date.now()}`,
type: 'CTA',
order: page.sections.length,
content: {
title: 'Contáctanos',
text: '¿Tienes preguntas?',
buttonText: 'Contacto',
buttonLink: '/contact'
}
});
// Save
db.cms.savePage(page);
}
Reordering Sections
const page = db.cms.getPageBySlug('quienes-somos');
if (page) {
// Move section from index 2 to index 0
const [section] = page.sections.splice(2, 1);
page.sections.unshift(section);
// Update order numbers
page.sections.forEach((section, index) => {
section.order = index;
});
db.cms.savePage(page);
}
Page Rendering
Dynamic Page Component
const DynamicPageView: React.FC<{ slug: string }> = ({ slug }) => {
const page = db.cms.getPageBySlug(slug);
if (!page || page.status !== 'Published') {
return <NotFound />;
}
const sortedSections = [...page.sections].sort((a, b) => a.order - b.order);
return (
<div>
<Helmet>
<title>{page.seo.title}</title>
<meta name="description" content={page.seo.description} />
<meta name="keywords" content={page.seo.keywords.join(', ')} />
</Helmet>
{sortedSections.map(section => (
<SectionRenderer key={section.id} section={section} />
))}
</div>
);
};
Section Renderer
const SectionRenderer: React.FC<{ section: PageSection }> = ({ section }) => {
switch (section.type) {
case 'Hero':
return <HeroSection {...section.content} />;
case 'Text':
return <TextSection {...section.content} />;
case 'Stats':
return <StatsSection {...section.content} />;
case 'CTA':
return <CTASection {...section.content} />;
case 'Timeline':
return <TimelineSection />;
case 'Cards':
return <CardsSection {...section.content} />;
case 'Gallery':
return <GallerySection {...section.content} />;
case 'ResourcesGrid':
return <ResourcesGridSection />;
case 'EventsCalendar':
return <EventsCalendarSection />;
case 'MethodPillars':
return <MethodPillarsSection />;
default:
return null;
}
};
Default Pages
The system includes default pages:
- quienes-somos - About page
- el-metodo - Method page
- biblioteca-recursos - Resources library
- actividades-retiros - Activities and retreats
- nuestra-historia - History subpage
- mision-y-vision - Mission and vision
Storage Key
- Key:
cafh_custom_pages_v1
- Location:
localStorage