Roots Discourse

Detach front-end and use WP Headless

Hi there,

For a new project I want to try out a headless wordpress setup as described in this article and dettach the site’s front-end with the backend. I only want to use Wordpress for it’s REST API and retrieve data to use in a React front-end.

Ideally I would like to continue using Trellis for local development, remote server provisioning and deploying my site etc.

So first of all I created a blank and stripped down wordpress theme for just setting up my custom post types, acf, wordpress hooks etc.

Initially I left the Trellis config to default for setting up Worpdress.
In bedrock’s web/index.php I set WP_USE_THEMES to false:

define('WP_USE_THEMES', false);

Now I succesfully tested my API endpoints:
http://example.test/wp-json/wp/v2/posts/1
http://example.test/wp-json/acf/v3/posts/1

Now I’m struggling how to use a separate frontend folder in Bedrock’s web root, because http://example.test/ will obviously still load web/index.php.

I was thinking I could just change the wp_home address to http://example.test/wp/ and use the endpoints like this in order to use a dettached frontend in the web root:
http://example.test/wp/wp-json/wp/v2/posts/1
http://example.test/wp/wp-json/acf/v3/posts/1

But even after re-provisioning these result in Nginx 500 Internal Server Errors (the backend itself works fine by the way). Normal page permalinks also result in a 500 Internal Server Error with this setup.

After some research I found this topic suggesting I should edit the nginx.conf and add these lines:

location ^~ /wp {
    root /var/www/example.com;
    index index.php index.html index.htm;
    try_files $uri $uri/ /wp/index.php;

    location ~ \.php {
        fastcgi_split_path_info ^(.*\.php)(.*)$;
        include fastcgi_params;
        fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        fastcgi_param PATH_INFO $fastcgi_path_info;
        fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
        fastcgi_pass 127.0.0.1:9000;
    }
}

But I was wundering where I should add this in the ansible playbook or if anyone has any other suggestions how this setup can be achieved with the least possible adjustment to the Trellis setup?

Any tips are welcome, thanks!

1 Like

I would think you have two options:

  1. Use a WordPress theme which just loads your React files
  2. Use an index.html which loads your React files

There should not be a lot of NGINX configuration needed. Just make sure index.html comes before index.php, and put the index.html file in the web folder.

None of that is tested, but if you’re just kicking off JavaScript, no need to overthink it.

2 Likes

Here’s another more up-to-date version of a headless WP + React project. You can probably take some cues from how they handled things.

2 Likes

Thanks! I’ll have a closer look at this one!

If you do need to make changes to the Nginx conf, you can probably achieve it in a better way via Nginx includes.

Ah it can be so easy sometimes :slight_smile:

Jup, this wordpress-site.conf.child works:

{% extends 'roles/wordpress-setup/templates/wordpress-site.conf.j2' %}

  {% block server_basic -%}
  root  {{ www_root }}/{{ item.key }}/{{ item.value.current_path | default('current') }}/web;
  index index.htm index.html index.php;
  add_header Fastcgi-Cache $upstream_cache_status;

  # Specify a charset
  charset utf-8;

  # Set the max body size equal to PHP's max POST size.
  client_max_body_size {{ php_post_max_size | default('25m') | lower }};

  {% if env == 'development' -%}
  # https://www.nginx.com/resources/wiki/start/topics/tutorials/config_pitfalls/#virtualbox
  sendfile off;

  {% endif -%}
  {% endblock -%}

http://example.test/ loads my index.html, the wp-admin works fine and all the API endpoints are working.

Thanks!

2 Likes

One last thing though, I want to have a separate folder in the web root for the front-end react build files, how can I invisibly redirect my index.html to let’s say: /web/front/build/?

I know you can do it like this:

<meta http-equiv="refresh" content="0; url=/front/build/" />

but that will change the url into: http://example.test/front/build/

I was looking at these nginx options:

location = / {
    root /front/build;
}

or

location = / {
   return 301 /front/build;
}

but they both don’t work or change the url?
Any suggestions? Thanks!

Trellis has this by default:

  {% block location_primary -%}
  location / {
    try_files $uri $uri/ /index.php?$args;
  }
  {% endblock %}

You can just customize that (via your child template) to point to index.html I think. You could even try using $document_root in its place. Maybe we could make that change by default so if someone customizes root, it’s picked up here too.

1 Like

Or in this case, point to /front/build/index.html right?

  {% block location_primary -%}
  location / {
    try_files $uri $uri/ /front/build/index.html?$args;
  }
  {% endblock %}

That doesn’t work unfortunately (backend works, but api endpoints also go to /front/build/).
I also tried symlinking the index.html to /front/build/index.html but that’s not working either I’m afraid…

1 Like

I got it!
On every react-app build, I just copy the build’s folder content to the web root with rsync:

"scripts": {
    "build": "react-scripts build",
    "postbuild": "rsync -r build/ ../."
  }
3 Likes

There should be a simpler way of doing this via the Nginx config but glad you solved it regardless :+1: