The platform that runs https://www.threemammals.com/.
George uses Wordpress as a CMS. It pushes messages out of Wordpress when changes happen using the Pushy plugin. The messages are placed on a RabbitMQ topic and ingested via a NodeJs process into a Postgres database. When the messages are ingested the Wordpress post_content is parsed into a React tree before saving. There is a GraphQL API over the Postgres database. When the ingest process finishes another message is published to RabbitMQ saying the work is done. Another NodeJS process listens to this message and statically generates the website. Finally NGINX is running over the top of Wordpress, the GraphQL API and the website itself.
Why not??? For reals though...my place of work has a headless Wordpress / React solution that calls the Wordpress "REST" APIs. We struggle with this because the APIs are not very performant and this has lead to some very complex caching and cache invalidation rules / processes. We have often talked about pushing the data out of Wordpress and storing it in a read optimised way (Please note maybe Postgres isnt this, its just to experiment). This would enable us in theory to look up everything on an index and get rid of our complex caching.
I set out to build the barebones of this platform for the https://threemammals.com website to see what is and isn't possible!!!
George supports creating, editing and deleting posts. It is very basic. The posts will appear on a /blog path.
The website itself is statically generated using https://github.com/react-static/react-static but any react renderer would do.
When the render process runs it uses GraphQL to load the React tree of a given post from the API. It then swaps out name strings for React component functions in memory. It throws the resulting tree to React render and away we go.
One of the cool things about react-static is that it supports incremental builds unlike Gatsby so we only build the article that has changed. Rather than the whole site! Unless we want to of course :)
- Node 10
- Docker
- Mac (only tested mac, definitely won't work on Windows, probably works on various Linux distributions)
-
Clone this repository
-
Before you do anything create a self signed certificate for localhost and put it in
package/serve/certs/live/localhost
. If you don't know how to do this Google should help. -
npm run bootstrap
-
npm run lerna -- --scope=@george/wordpress install-pushy --stream
to install Pushy into Wordpress plugins. -
Make changes, git add and commit
-
We can publish containers to either ECR or ACR by default. You can switch which repo you are using by editing
./packages/scripts/publish.sh
to point at./packages/scripts/publish-azure.sh
or./packages/scripts/publish-azure.sh
. -
Depending on your chosen container registry set the following environmental variables.
- Azure
export GEORGE_ACR_LOGIN_NAME=XXX export GEORGE_ACR_URL=XXX.azurecr.io export GEORGE_ACR_USERNAME=XXX export GEORGE_ACR_PASSWORD=XXX
- AWS
export GEORGE_ECR_URL=032803037394.dkr.ecr.eu-west-1.amazonaws.com export GEORGE_AWS_REGION=eu-west-1
-
We publish npm packages scoped @george to a private repository using .npmrc via a process where we write an environmental variable called
GEORGE_NPMRC
into .npmrc and then delete it afterwards. This means in order to publish you need to setexport GEORGE_NPMRC="registry=https://registry.npmjs.org/\r\n@george:XXXXXXXXX"
Where XXXXXXXXX is your details for the private repository. The value needs to be escaped.
-
npm run build
-
Run locally via docker compose
npm run start-dev
-
Setup wordpress:
- Go to https://localhost/admin/wp-admin/install.php
- Install WP & Login
- Go to Plugins and Activate Pushy
- Go to Settings > Pushy Options and tick AMQPPublisher and enter rabbit as the location click Save Changes.
- Go to Settings > Permalinks and tick plain then save Changes.
-
Check database migrations have worked
- Go to http://localhost:8080 and login using the postgres details from docker-compose.yml
- Check there is a table called posts in the database george.
-
Check GraphQL is working
- Go to https://localhost/api and verify GraphQL UI loads
- Make a request to https://localhost/api with the content below
{ posts { title } }
-
Check the website is working
- Go to https://localhost/ and you should see the ThreeMammals homepage.
- Click on Blog in the menu there should be no posts in the list.
- Go to Wordpress and edit a post, click Update / Publish.
- Go to https://localhost/blog/ and refresh the page for 30 seconds and the post should appear.
- If it doesn't check the logs for the render container. There is probably something wrong. Work out what it is or raise a GitHub issue.
- If it appears you are all good George is working.
-
Set the following environmental variables
export GEORGE_POSTGRES_USER=example export GOERGE_POSTGRES_PASSWORD=george export GOERGE_POSTGRES_HOST=localhost
-
lerna run --scope=@george/data migrate-up --stream
to migrate up. -
lerna run --scope=@george/data migrate-down --stream
to migrate down.
Set these locally if you are doing any kind of debugging etc outside of docker-compose.
export FQDN_OR_IP=localhost
export GEORGE_PUBLIC_API_URL=http://localhost:4000/
export INTERNAL_SITE_ROOL=https://localhost/
export WORDPRESS_SITE_ROOT=https://localhost/
export GEORGE_SITE_ROOT=https://localhost/
export GEORGE_RABBITMQ_URL=amqp://localhost
export GEORGE_DATABASE_HOST=localhost
export GEORGE_API_URL=http://localhost:4000/
I have a separate repository with a production docker-compose.yml and NGINX config.
I mount the config on the serve container like so..
volumes:
- /home/azureuser/default.conf:/etc/nginx/conf.d/default.conf
These files contain all my https://www.threemammals.com/ specific stuff. For example the production docker-compose.yml has lots of different values from environmental variables!
After that it is up to you to work out how to deploy if you want to use it :) I suggest the easiest way would be docker-machine to a VM :P
One final hint I use https://github.com/mjstealey/wordpress-nginx-docker to get SSL into the serve container.