Skip to main content

Overview

The WPPage interface represents a static page fetched from the WordPress CMS. It’s used for dynamic content pages that are managed in WordPress but rendered in the React application, providing flexibility for content updates without code deployments.

Type Definition

export interface WPPage {
  id: number;
  slug: string;
  title: string;
  content: string;
  excerpt: string;
  date: string;
  image: string;
}
Source: source/types.ts:45-52

Properties

id
number
required
Unique WordPress page ID from the CMS database. Used for identification and caching.
slug
string
required
URL-friendly page identifier. Matches the WordPress slug and is used for routing in the React app.
title
string
required
The page title, typically displayed as an H1 heading. HTML entities are stripped during mapping.
content
string
required
Full HTML content of the page. Contains rich text, images, and any WordPress block editor content.
excerpt
string
required
Short summary or description of the page. HTML is stripped for plain text use in meta tags.
date
string
required
Publication or last modified date in localized format (e.g., "3 feb. 2024").
image
string
required
URL of the featured image. May be an empty string if no featured image is set in WordPress.

Usage Examples

Fetching WordPress Pages

The primary use case is fetching pages from WordPress REST API:
import { WPPage } from '../types';

const WP_API_URL = 'https://cms.gobigagency.co/vencol/wp-json/wp/v2';

export async function fetchWPPageBySlug(slug: string): Promise<WPPage | null> {
  const res = await fetch(
    `${WP_API_URL}/pages?slug=${encodeURIComponent(slug)}&_embed`
  );

  if (!res.ok) {
    throw new Error(`WordPress API error: ${res.status}`);
  }

  const pages: WPPost[] = await res.json();
  if (pages.length === 0) return null;
  
  return mapWPPageToWPPage(pages[0]);
}
Source: source/lib/wordpress.ts:82-94

Mapping WordPress API Response

Converting WordPress REST API data to the WPPage interface:
import { WPPage } from '../types';

interface WPPost {
  id: number;
  date: string;
  slug: string;
  title: { rendered: string };
  excerpt: { rendered: string };
  content: { rendered: string };
  _embedded?: {
    'wp:featuredmedia'?: Array<{ source_url: string }>;
  };
}

function stripHtml(html: string): string {
  const doc = new DOMParser().parseFromString(html, 'text/html');
  return doc.body.textContent?.trim() || '';
}

function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString('es-ES', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  });
}

function mapWPPageToWPPage(page: WPPost): WPPage {
  const featuredImage =
    page._embedded?.['wp:featuredmedia']?.[0]?.source_url || '';

  return {
    id: page.id,
    slug: page.slug,
    title: stripHtml(page.title.rendered),
    content: page.content.rendered,
    excerpt: stripHtml(page.excerpt.rendered),
    date: formatDate(page.date),
    image: featuredImage,
  };
}
Source: source/lib/wordpress.ts:5-67

Rendering a WordPress Page

Using the WPPage data in a React component:
import React, { useState, useEffect } from 'react';
import { useParams } from 'react-router-dom';
import { WPPage } from '../types';
import { fetchWPPageBySlug } from '../lib/wordpress';

const PageDetail: React.FC = () => {
  const { slug } = useParams<{ slug: string }>();
  const [page, setPage] = useState<WPPage | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!slug) return;
    
    fetchWPPageBySlug(slug)
      .then(setPage)
      .catch(console.error)
      .finally(() => setLoading(false));
  }, [slug]);

  if (loading) return <div>Loading...</div>;
  if (!page) return <div>Page not found</div>;

  return (
    <article className="container mx-auto px-4 py-12">
      {page.image && (
        <img 
          src={page.image} 
          alt={page.title}
          className="w-full h-96 object-cover rounded-lg mb-8"
        />
      )}
      <h1 className="text-4xl font-bold mb-4">{page.title}</h1>
      <time className="text-gray-500 text-sm">{page.date}</time>
      <div 
        className="prose prose-lg mt-8"
        dangerouslySetInnerHTML={{ __html: page.content }}
      />
    </article>
  );
};
Source: source/pages/PageDetail.tsx

Comparison with BlogPost

While WPPage and BlogPost have similar structures, they serve different purposes:
PropertyWPPageBlogPost
PurposeStatic pages (About, Legal, etc.)Blog articles/posts
Category❌ No category field✅ Has category field
UsageSingle pages by slugLists and archives
Content TypeLong-form static contentTime-based articles
// BlogPost has category
interface BlogPost {
  // ... other fields
  category: string; // "Educativo", "Tecnología", etc.
}

// WPPage does not
interface WPPage {
  // ... other fields
  // No category field
}

API Integration Notes

The WPPage interface is designed to work with the WordPress REST API v2. Ensure your WordPress site has the REST API enabled and publicly accessible.

Required WordPress API Parameters

When fetching pages, use these query parameters:
  • slug - Filter by page slug
  • _embed - Include embedded data (featured media, authors, etc.)
const apiUrl = `${WP_API_URL}/pages?slug=${slug}&_embed`;
The image field may be empty if no featured image is set:
const featuredImage = 
  page._embedded?.['wp:featuredmedia']?.[0]?.source_url || '';

// In component, check before rendering
{page.image && (
  <img src={page.image} alt={page.title} />
)}

Security Considerations

The content field contains raw HTML from WordPress. Always sanitize or use dangerouslySetInnerHTML with caution. Ensure your WordPress installation is secure and only trusted users can edit pages.

Safe Rendering

// Safe: React handles HTML entities in title
<h1>{page.title}</h1>

// Requires caution: Raw HTML rendering
<div dangerouslySetInnerHTML={{ __html: page.content }} />

// Safe: Plain text excerpt
<p>{page.excerpt}</p>

Date Localization

Dates are formatted using Spanish locale by default:
function formatDate(dateString: string): string {
  const date = new Date(dateString);
  return date.toLocaleDateString('es-ES', {
    year: 'numeric',
    month: 'short',
    day: 'numeric',
  });
}
// Output: "3 feb. 2024"
To customize for different locales, modify the formatDate function.
  • BlogPost - Similar structure for blog posts with additional category field
  • Service - Another content type for product/service pages

TypeScript Notes

  • All properties are required (non-optional)
  • The image field is a string but may be empty ("")
  • The content field contains HTML strings, not React elements
  • Returns null from fetch function if page not found (handle in components)

Build docs developers (and LLMs) love