Modern JS frameworks and old-school PHP hosting?

Modern JS frameworks and old-school PHP hosting?

This post was translated using the DeepL translator, so I apologize for any incomprehensibility. In this article you can read more about my decision.

Would you like to try a modern JavaScript framework like Angular, React or Vue, but only have PHP hosting available? One option is to look for services like Netlify or Vercel, both of which provide free JAM stack hosting. However, if you don't want to give up your PHP hosting, want to try a JavaScript framework and are also thinking about SEO, there is another option. However, it's definitely not for large projects or sites that stand for the best SEO optimization, although the latter is less of a problem in this case.

Let's say we have a finished front-end, built as a SPA (single page application) and uploaded to a test FTP site. Next, we create a ssr-index.php file. We will then insert all the functions to display the API data to robots and crawlers. No, don't worry, you won't have to copy all the HTML code from your front-end.

PHP server side rendering

PHP provides a file_get_contents function, we can easily use this to communicate with our API. Then convert the received response into a PHP object or array and work with the data. It is also a prerequisite for success that the URL contains at least one identifier of the post or page whose data we want to retrieve. In my example, this would be slug. So the first part of the ssr-index.php file will look like this:

1<?php
2
3$SITE_ROOT = "http://example.com";
4
5if ($_GET['slug']) {
6    $response = file_get_contents($SITE_ROOT.'?slug='.$_GET['slug']);
7    $jsonData = json_decode($response);
8
9    if ($jsonData) {
10        renderPage($jsonData, $_GET['slug']);
11    }
12} else {
13    $jsonData = json_decode('{
14        "title": "Name of the page",
15        "content": "Content of the page"
16    }');
17    renderPage($jsonData, '');
18}
19

For better clarity, we define the root URL at the beginning of the file. Then, if the GET value slug is within the address, we call the file_get_contents API and convert the response to a PHP object using json_decode. The response from our API is JSON, if you are working with other data, a different transformation function will be needed. If the transformation to the PHP object is successful and the variable carries a value, we render the HTML page. If the GET parameter was not present within the URL, we can render an empty fallback page, since the robot is probably on the home page. The example is missing the situation where the API returns a response with an error code, this would also want to be handled.

In both cases, the renderPage function will ensure that the base HTML page is rendered. In our example, I'm making do with just plain HTML and a few meta tags, but there are limits and you can play around with the look of this page. However, it is pretty much useless to design it in any way. I would focus more on semantics.

1function renderPage($data, $slug) {
2    ?>
3    <!DOCTYPE html>
4    <html lang="cs">
5        <head>
6				    <meta charset="UTF-8" />
7            <title>Name of the page</title>
8            <meta property="og:title" content="<?php echo $data->title; ?>" />
9            <meta property="og:description" content="<?php echo preg_replace('/<\/?[^>]+(>|$)/m', '',$data->excerpt); ?>" />
10            <meta property="og:site_name" content="Name of the page" />
11            <meta property="og:image" content="<?php echo $data->image; ?>" />
12            <meta property="og:type" content="article" />
13            <meta property="og:url" content="https://example.com/<?php echo $slug; ?>" />
14            <meta name="twitter:card" content="summary_large_image" />
15        </head>
16        <body>
17	        <main>
18		        <h1><?php echo $data->title; ?></h1>
19            <?php echo $data->content; ?>
20	        </main>
21        </body>
22        <script type="application/ld+json">
23            {
24                "@context":"http://schema.org",
25                "@type":"Article",
26                "name": "<?php echo $data->title; ?>",
27                "headline": "<?php echo $data->title; ?>",
28                "datePublished": "<?php echo $data->date; ?>",
29                "articleBody": "<?php echo preg_replace('/<\/?[^>]+(>|$)/m', '',$data->content); ?>",
30                "abstract": "<?php echo preg_replace('/<\/?[^>]+(>|$)/m', '',$data->excerpt); ?>",
31                "url": "https://example.com/<?php echo $slug; ?>",
32                "publisher": {
33                "@type": "Organization",
34                "name": "Name of the page"
35                }
36        </script>
37    </html>
38    <?php
39}

As you can see from the snippet, the rendered page will contain the basic meta here, as well as OpenGraph headers for social media and JSON+LD schema for rich results. In the body itself, I've made do with just an H1 for the headline and the HTML content of the post. However, there is room to add more tags and information here.

How to tell the robots?

It remains to redirect the bots to ssr-index.php. To do this, you need to edit the .htaccess file. Assume you have standard hosting with RewriteEngine On otherwise you need to turn it on.

1 <IfModule mod_rewrite.c>
2  RewriteEngine On
3
4	# allow social media crawlers to work by redirecting them to a server-rendered static version on the page
5  RewriteCond %{HTTP_USER_AGENT} (facebookexternalhit/[0-9]|Twitterbot|Pinterest|Facebot|Google|Ads|SeznamBot|Bing|Telegram|Discord|Whatsapp|FreshBot)
6  RewriteRule ^(.*)$ ssr-index.php?slug=$1 [QSA,L]
7
8  RewriteCond %{REQUEST_FILENAME} !-f
9  RewriteCond %{REQUEST_URI} !api
10  RewriteRule ^(.*)$ index.html [QSA,L]
11</IfModule>

As can be seen from the snippet, if the USER-AGENT of the visitor corresponds to one of the defined in the list, the visitor is redirected to the ssr-index.php file, otherwise the visitor continues to the index.html file, i.e. the classic web.

Conclusion

As can be seen from the snippets, the whole solution has a number of pitfalls, starting with the need to define a list of robots and ending with the creation of a special page designed to communicate with the API. Therefore, this is not a solution I would recommend for large sites or sites that care about 100% reliability in SEO. It is rather a solution for smaller sites that do not rely on 100% SEO. However, it is a solution that can provide a good stepping stone for moving from traditional hosting to new services.