HeadstartWP

repository·develop·Indexed 41 days ago

https://github.com/10up/headstartwp

A modern headless WordPress solution designed to bridge WordPress with frontend frameworks like Next.js. It includes a suite of tools such as @headstartwp/core for framework-agnostic components, @headstartwp/next for Next.js bindings, @headstartwp/block-primitives, and @headstartwp/epio-search for ElasticPress.io integration. The ecosystem also provides @10up/next-redis-cache-provider as a Redis-based replacement for the Next.js Incremental Cache Handler.

Tokens
90K
Snippets
255
Records
387
Agent score
52%

What's inside HeadstartWP

  1. Understand the HeadstartWP technology stack and principles

    develop

    HeadstartWP is built on a philosophy of simplicity and low maintenance. Key architectural decisions include:

    • Foundation: The framework uses Next.js as its core full-stack React framework. This allows developers to leverage the Next.js ecosystem and Vercel's maintenance instead of managing a custom foundation.
    • Complexity Reduction: The framework is designed to handle the 'wiring' between Next.js and WordPress, allowing engineers to focus on site features rather than integration plumbing.
    • Data Fetching: The framework currently prioritizes the WordPress REST API over WPGraphQL. This decision is made to avoid the additional complexity of managing GraphQL-specific requirements like caching, persisted queries, and cache-bursting in most standard headless use cases.
  2. How On-demand ISR revalidation works

    develop

    The revalidation process follows these steps:

    1. WordPress saves a post: A user saves or publishes content in WordPress.
    2. Plugin generates token: The WordPress plugin generates a secure JWT token.
    3. Plugin calls Next.js: The plugin makes an HTTP request to the configured revalidate endpoint (default /api/revalidate).
    4. Token verification: Next.js verifies the token using VerifyTokenFetchStrategy.
    5. Path revalidation: Next.js calls revalidatePath() on the verified path.
    6. Response: A success or error response is sent back to WordPress.

    Multi-site Path Construction

    For multisite installations, the handler automatically adjusts path construction to include the site slug:

    • Single site: /blog/my-post
    • Multi-site: /site-slug/blog/my-post
    • Multi-site with locale: /en/site-slug/blog/my-post
  3. Use `preview.usePostLinkForRedirect` for automatic routing

    develop

    The preview.usePostLinkForRedirect setting in headstartwp.config.js allows HeadstartWP to automatically determine the correct Next.js route by using the WordPress post permalink.

    This is highly effective when your Next.js route structure strictly follows your WordPress permalink structure (e.g., /news/category/post-name). If you use complex permalinks that include categories, this setting removes the need for manual getRedirectPath logic in your API route.

    Note on Drafts: Since draft posts often lack 'pretty' permalinks in WordPress, HeadstartWP provides a REST field _headless_wp_preview_link which returns a pretty permalink even for drafts. The previewRouteHandler uses this field to ensure seamless redirection.

    Implementation Tip: If you are overriding permalinks via a WordPress filter, ensure you provide a fallback for post_name so that draft posts can still generate a valid link.

    module.exports = {
      // ... other configs
      preview: {
        usePostLinkForRedirect: true,
      },
    };
  4. Configure queryPostOrPosts priority and route matching

    develop

    By default, queryPostOrPosts attempts to match a single post before attempting an archive query. You can change this behavior using params.priority and params.routeMatchStrategy.

    Use priority: 'archive' if you want the function to check for an archive match (like a category or tag page) before checking if the URL matches a specific post. This is useful for routes like /blog/[[...path]] where you might want the archive to take precedence over a post with a similar slug.

    export default async function BlogPage({ params }: HeadstartWPRoute) {
    	const { isSingle, isArchive, data } = await queryPostOrPosts({
    		routeParams: await params,
    		params: {
    			single: { postType: 'post' },
    			archive: { postType: 'post', perPage: 10 },
    			// Try archive first for this route
    			priority: 'archive',
    			routeMatchStrategy: 'archive',
    		},
    	});
    
    	// ...
    }
  5. Understand the basics of `theme.json`

    develop

    The theme.json file allows you to control WordPress blocks in both the editor and the frontend. It is structured into two main sections:

    1. settings: Used to define global options.
    2. styles: Used to define global styles or override/adjust settings at a block level.

    Values provided in theme.json are automatically converted into CSS custom properties following a fixed naming scheme, which are then available on both the frontend and in the editor.

  6. How Polylang integration works

    develop

    Once enabled, HeadstartWP automatically manages the lang attribute for all REST API calls made through the framework's data-fetching layer.

    Language Detection Flow:

    1. Route Parameter: The locale is extracted from the [lang] dynamic segment in the URL.
    2. Middleware: AppMiddleware handles locale detection and routing.
    3. API Calls: Data fetching functions automatically include the current locale in WordPress API requests.
    4. Fallback: If no locale is specified in the URL, the defaultLocale from headstartwp.config.js is used.

    URL Pattern Example:

    • https://mysite.com/en/ (English home page)
    • https://mysite.com/pt/blog/meu-post (Portuguese blog post)
  7. Understand the queryPosts return value

    develop

    The queryPosts function returns a Promise that resolves to an object containing data and config.

    data object

    • posts: An array of PostEntity objects.
    • queriedObject: (Optional) When fetching by category, tag, or author, this contains information about the queried term or author.
    • pageInfo: An object containing pagination metadata:
      • page: Current page number.
      • totalPages: Total number of pages available.
      • totalItems: Total number of items matching the query.
      • hasNextPage: Boolean indicating if a next page exists.
      • hasPreviousPage: Boolean indicating if a previous page exists.
  8. Understand block attribute serialization in HTML

    develop

    When HeadstartWP processes a block, it serializes the Gutenberg attributes into the HTML markup. This is what enables forwardBlockAttributes to work. The renderer looks for the data-wp-block attribute, which contains a JSON string of the block's attributes.

    Example HTML Output:

    <div 
    	class="wp-block-custom-hero" 
    	data-wp-block-name="custom/hero"
    	data-wp-block='{"title":"Welcome to Our Site","content":"This is the hero section","backgroundImage":{"url":"https://example.com/hero-bg.jpg","alt":"Hero background"},"buttonText":"Learn More","buttonUrl":"/about"}'
    >
    	<!-- Block content -->
    </div>

    When your React component is used within a BlocksRenderer with forwardBlockAttributes={true}, these JSON values are automatically parsed and passed into your component's block.attributes prop.

  9. How Feeds work in HeadstartWP

    develop

    By default, Feeds are proxied via Next.js rewrites. This allows you to access the feed directly through your front-end/Next.js URL.

    If the HeadstartWP plugin is enabled, the URLs contained within the feed XML will also be rewritten to use your front-end URLs instead of the WordPress backend URLs. This rewriting behavior is triggered by the presence of the ?rewrite_urls=1 query parameter. The framework automatically appends this parameter when accessing feeds through the Next.js proxy.

    {
        source: `${prefix}/feed`,
        destination: `${wpUrl}/feed/?rewrite_urls=1`,
    }
  10. Data fetching in Next.js App Router

    develop

    HeadstartWP uses modern async/await patterns for data fetching in the Next.js App Router. Instead of relying on React hooks (which are used in the Pages Router), the App Router leverages Server Components for efficient server-side fetching. The underlying logic is abstracted via AbstractFetchStrategy classes.

    Key features of the App Router data-fetching functions include:

    • Automatic extraction of URL segments from route parameters.
    • Support for WordPress pretty permalinks.
    • Full TypeScript support.
    • Integration with Next.js caching and revalidation mechanisms.
  11. How block styles are processed and delivered

    develop

    When block styles are enabled, HeadstartWP follows this lifecycle to optimize performance:

    1. Collects Global Styles: Includes the WordPress global stylesheet via wp_get_global_stylesheet().
    2. Processes Core Block Supports: Adds CSS for core block features and supports.
    3. Loads Individual Block Styles: Gathers CSS for each block type present on the page using their specific style handles.
    4. Combines and Delivers: Combines all gathered CSS into a single block_styles property within the REST API response.

    The resulting CSS is available in your headless frontend via post.content.block_styles, allowing you to render it inline or process it within React components. This ensures only the CSS for blocks actually used on a page is loaded.