Build Phases

Phase 0 — WordPress Setup

Do these steps before writing any Next.js code.

Set Permalinks — Do This First

Go to Settings → Permalinks, select Post name (/%postname%/), click Save.

!

Without Post name permalinks, the REST API returns 404 for everything. Always set this first.

Test the REST API

Open your browser and visit these URLs. You should see a JSON array:

https://yourdomain.com/wp-json/wp/v2/posts
https://yourdomain.com/wp-json/wp/v2/pages

Install Required Plugins

Go to Plugins → Add New and install these:

PluginSearch For
Headless ModeHeadless Mode WP Engine
Advanced Custom FieldsAdvanced Custom Fields
Contact Form 7Contact Form 7
JWT AuthenticationJWT Authentication for WP REST API
Yoast SEOYoast SEO

Register Custom Post Types (CPTs)

Add to functions.php for any content beyond standard Posts:

function register_projects_cpt() {
    register_post_type('projects', array(
        'labels'       => array('name' => 'Projects', 'singular_name' => 'Project'),
        'public'       => true,
        'has_archive'  => true,
        'show_in_rest' => true,      // CRITICAL: enables REST API
        'rest_base'    => 'projects',
        'supports'     => array('title', 'editor', 'thumbnail', 'excerpt', 'custom-fields'),
    ));
}
add_action('init', 'register_projects_cpt');
!

show_in_rest => true is mandatory. Without it, your CPT will be invisible to the REST API.

Add ACF Fields

Go to Custom Fields → Add New, create fields, set Location to your CPT. In field group settings, enable "Show in REST API". Test with:

https://yourdomain.com/wp-json/wp/v2/projects?_embed&per_page=1
// Look for: "acf": { "your_field": "value" }

Configure CORS Headers

Add to functions.php so your Next.js frontend can fetch from WordPress:

function add_cors_headers() {
    header("Access-Control-Allow-Origin: https://yourdomain.com");
    header("Access-Control-Allow-Methods: GET, POST, OPTIONS");
    header("Access-Control-Allow-Headers: Content-Type, Authorization");
    if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') {
        status_header(200); exit();
    }
}
add_action('init', 'add_cors_headers');
TIP

During local development, temporarily change https://yourdomain.com to * to allow all origins. Lock it down before going live.

PreviousPrerequisitesNextPhase 1 — Next.js Scaffold