Prepending PHP to a Page in Gatsby

Hero image for Prepending PHP to a Page in Gatsby. Image by Ben.
Hero image for 'Prepending PHP to a Page in Gatsby.' Image by Ben.

It goes against the entire Jamstack philosophy to add reliance to a backend technology like PHP, and certainly the Gatsby Content Mesh advocates against it, but sometimes there's simply no alternative.

Often, these serverside scripts can be set up as standalone endpoints which you can then call via HTTP (for example by using axios). This is a really common approach for oneway communication, like submitting a contact form. In Gatsby, if you are confident that your eventual hosting environment supports PHP (for example) you can even add these files into your static folder, safe in the knowledge that they will then be placed in, and be available at, the root of your domain.

However, there are times when this isn't sufficient. A recent project I worked on required that every page load be hydrated with uptotheminute live pricing data, acquired from a monolith system built in PHP, where security policies made it impossible to use a more familiar, distributed approach. You might argue: possibly not the best use of a static site generator!

Appending PHP functionality to a Gatsby template allows us to fetch up-to-the-minute prices and hydrate the data on-screen.

So, the answer in this instance was to use a include prepended to each generated page at buildtime, to build an object on window, then read back into the React components onpage.

Another good use example for me has been to append a tiny piece of PHP to my error page. This way, I can collect data about what errors are occurring onsite, what type of visitors are causing them, and react accordingly. This also has a benefit against the more accepted HTTPclient approach: it doesn't require a visitor with JavaScript enabled (which inevitably more nefarious bots do not).

From here, I'm going to assume you're serving your Gatsby site on a PHP environment with access to htaccess. Otherwise, this solution isn't going to work for you.


Use .htaccess to Allow PHP Processing

The html files generated by Gatsby are not on their own going to trigger any PHP you attempt to push into them without a little help.

If you don't already have an htaccess file in your project, create one (important: the file name is .htaccess there is nothing before the extension, your OS is probably going to hide it immediately). This goes into your static folder and will then be copied into your site root on build.

Then, there are two options in the code block below to use as best suits your needs:

  • The first will mean that all files with the .html extension should be parsed as PHP. I don't recommend this unless you really and genuinely are relying on the backend for every page (in which case, maybe Gatsby isn't the answer).
  • The second does the same but only applies to a specific file in this case 404.html.
AddType application/x-httpd-php .html<Files 404.html>  AddType application/x-httpd-php .html</Files>

Install prepend‑file

prependfile is a simple package which just prepends text to a file within your generated site. We will use this as part of our deployment script. So, add to your project by simply running yarn add prependfile from the project root (unless you're using NPM, in which case it's npm install prependfile).


Write Your Prepend Script

This is a very similar process as I've described before where we want to add additional Node.js functionality within our build process. Create a file called prepend.js in your folder root, import prependfile, and configure it to add an include to your PHP file to the file you want to add PHP to.

This is how I capture hits on my error page (with some comments to explain what's going on). Note that I'm also using my LIVE_DEPLOY environment variable here to determine where the build is occurring.

// import our environment variablesrequire('dotenv').config({ path: '.env' });// if our LIVE_DEPLOY variable isn't set, or is not set// to 'true', then we return without going any furtherif (process.env.LIVE_DEPLOY !== 'true') {  console.warn('Deploy env is false, not prepending');  return;}// import prepend-filevar prependFile = require('prepend-file');// open the 404 file, and inject an include for// error-include.phpprependFile('./public/404.html', "<? include_once('include.php'); ?>", () => {  console.log('Error file prepend successfully');});

What this does is open the generated 404.html from the public folder and append a simple string of text:

<? include_once('include.php'); ?>

From here, as long as you've created a file called include.php, and put it inside your static folder, then its contents will be added into the base of your 404.html file. When the page is loaded by a visitor, whatever PHP you've written will also be triggered.


Add Prepend to Your Build Script

Much like setting up Gatsby to deploy via FTP, one final task is to add your new prepend script into your build process and much of this will come down to your own personal preference.

Inside my package.json, I like to have a specific 'deploy' script which is only called (via yarn deploy) within the pipeline I have configured to push content out onto the live site. Mine looks like this:

"scripts": {  "deploy": "gatsby clean && gatsby build && node prepend && node deploy"}

In order, this chains four commands together:

  1. gatsby clean make sure we have cleared out any cached items we don't need;
  2. gatsby build build the Gatsby project;
  3. node prepend calls our new prepend.js file which in turn adds a PHP include to our 404.html file;
  4. node deploy calls deploy.js which takes a copy of the contents of the public folder, and uploads it via FTP. I've written about this here.

And it is as simple as that! If you wish to try this locally, you can simply run node prepend and then look at the source code of the file in your public folder (assuming you have a recent build in there already). Just be sure to set your LIVE_DEPLOY environment variable to true, otherwise, it will just say no.


Categories:

  1. Development
  2. FTP
  3. Gatsby
  4. Node.js
  5. PHP