Back to basics
So I’ve had a couple of months of using WordPress now, and I have to say for blogging, site which are going to grow rapidly or for multi-editor sites, I would definitely recommend it. I still believe, however, it is overkill for many uses cases. HTML is very good at what it does and it is not hard to learn. CSS is even better – and frankly the way that WordPress forces you to engage (or not) with CSS is a dog’s breakfast. The alternative is to go back to basics and build it yourself. HTML and CSS is all you need – but I would throw PHP and JSON into the mix as well.
Before we begin, some warnings. The bad news is it is very easy to write bad PHP that is hard to read and even harder to maintain. The good news is with a bit of planning it is also easy to write clean maintainable PHP.
The first site I built in PHP many years ago was more of dog’s breakfast that WordPress. I didn’t realise that until I decided to refresh the theme two years later. I realised then that my styling was scattered randomly every where and bound up with my site code (or logic). The good news is that I have learned a lot since then.
Model, View, Controller Approach
The key to writing maintainable PHP is to be very clear about what you are doing with it. To avoid mixing code which is about how the site runs from code which is about how the site looks, or what the site says. This approach is called Model, View, Controller.
The Model is the site’s content and data. The View is the site’s appearance. The Controller is the code to make the site run.
Generally I like to break a site down as follows:
- Structure – Navigation structure of the site. Can be PHP, mySQL or my preference, JSON (Model)
- Content – mostly HTML (Model)
- Style – usually CSS and nothing else (View)
- Layout – page templates built in HTML with PHP includes and any repeating sections (View)
- Site logic – PHP (Controller)
It might seem a daunting list – but it really isn’t that hard. So lets dive in
View: A simple index.html
As I said at that outset all you really need for a single page site is HTML and CSS. So let’s begin by creating a simple index.html which will go on to become our main template. If you place this in the root directory of your web hosting you don’t need to name it as part of the URL – the web-server automatically looks for index.html as being the first page of a website.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=yes">
</head>
<body>
<h1>Site Name here</h1>
<p>Site text here</p>
</body>
</html>
HTMLIf all you ever need is a single page, you can build the entire thing inside the body tag and not worry too much about adding any complexity. Our purpose here, however, is to have a simple, multipage website, and for that we will delve into PHP and JSON.
Model: Site Structure (main.json)
To start with we’re going to create a very simple site structure file in JSON as follows. Let’s save this in a new folder called site and name it main.json
As you can see it declares three web pages giving each a name, title and pointing them to a content page
{
"home":{
"title":"Welcome",
"content":"content/home.php"
},
"about":{
"title":"About Us",
"content":"content/about.php"
},
"contact":{
"title":"Contact Us",
"content":"content/contact.php"
}
}
JSONController: Site logic (site.php)
Next we need a simple PHP file to read it. We’ll call this site.php and save it in a directory called scripts.
In it let’s declare a class called site and add a method (function) to it which read in a JSON file. We can also create a method to throw a 404 error in case the file is not found. It is in a separate function because we will need to use this again.
<?php
class site {
function getJson($file) {
if (file_exists($file)) {
$json = file_get_contents($file);
return json_decode($json);
}
$this->throw404();
}
function throw404() {
http_response_code(404);
print "404: Page Not Found"; // ToDo: Include 404.html
die();
}
}
PHPNext we need to read the URL which is passed our site and use it to choose the page from main.json.
PHP breaks the request given to it into several parts and stores these in an array called $_SERVER. The bit we will be using is call the QUERY_STRING. This allows us to pass parameters to a URL and use them to drive which page is shown. For the three pages in main.json we will need three URLs as follows.
http://yoursite.something/?page=home
http://yoursite.something/?page=about
http://yoursite.something/?page=contact
Depending on how your web server is set up your url may be http or https, and yoursite.something will be your domain name. The method getPage takes this query part of the URL – basically the bit after the question mark – and splits it into an array. PHP provides a function to do this for us called parse_str. It then looks for the page name in main.json. If it finds it, it passes the details of that page back to wherever it was called from.
function getPage() {
$pages = $this->getJson("site/main.json");
if ($pages) {
parse_str($_SERVER['QUERY_STRING'],$query);
if (is_array($query)) {
if (array_key_exists("page", $query)) {
$pageName = $query["page"];
if (isset($pages->$pageName)) {
return $pages->$pageName;
}
}
}
}
$this->throw404();
}
PHPController: making the page dynamic using index.php
In order to call getPage, we’re going to change the main document in our site to a php file. We can do this by creating a new document in the root directory of our website and call it index.php
This will include the site script that we have just created, declare a new instance of the site object, call getPage and include a page template, which I am going to call main.php
<?php
include "scripts/site.php";
$site = new site();
$page = $site->getPage();
include "templates/main.php";
?>
PHPView: The main template
To create the template file we can rename our index.html to main.php, move it into the templates folder and make a couple of small changes to it to change the hard-coded title and contents to read the values we retrieved from our JSON file.
<body>
<h1><?php echo $page->title ?></h1>
<p><?php include $page->content ?></p>
</body>
PHPModel: Creating some content
The final piece of the puzzle is to create some files in the content folder. We need one for each page defined in main.json (home.php, about.php and contact.php). I’ve shown only one here and for testing purposes it is good to start with one or two only, so we can see what happens if one of these is missing. You can put in pretty much any HTML you like in the content file.
<h2>Getting started</h2>
<p>My first dymanic web site in PHP!</p>
PHPTesting it out
Hopefully, if everything has gone to plan typing in the URL of the page we created above should give show us our web page. If it doesn’t – refer to the troubleshooting section at the bottom.
However, in testing we should find two immediate issues. The first is that whilst this code works for our homepage if we call it with http://yoursite.something/?page=home it doesn’t work if we call it with out any parameters at all – instead it gives us a 404. The second issue is that it gives an error if we direct it to a page in the main.json before we have created the relevant content page.
Warning: include(content/about.php): failed to open stream: No such file or directory in .../templates/main.php on line 11
In order to fix these two errors we need to make a couple of changes in site.php. Firstly we need to cope with the case when there is no page provided in the query string – this should take us to the home page. Secondly we need to check that the content page actually exists, and if not throw a 404.
function getPage() {
$page = false;
$pages = $this->getJson("site/main.json");
if ($pages) {
parse_str($_SERVER['QUERY_STRING'],$query);
if (is_array($query)) {
if (array_key_exists("page", $query)) {
$pageName = $query["page"];
}
else {
$pageName="home";
}
}
if (isset($pages->$pageName)) {
if (file_exists($pages->$pageName->content))
return $pages->$pageName;
}
}
$this->throw404();
}
PHPTroubleshooting
If the PHP will not run it may be because PHP is not installed, or the web server is not set up to run find index.php as the home page. Talk to your hosting provider and they should be able to sort this.
If it runs but gives you an error check you have typed everything correctly – unless the error says something like
Warning: file_get_contents(site/main.json): failed to open stream: Permission denied in ...
This means that there is an error in the permissions or file ownership of one or more of your files. In order to be able to run your website the web server needs have read access to every file. Normally the files are set up to be in the same group as the web server, so having read access at the group level should be sufficient. If this fails try adding read access for world (or everyone).
Next steps
With our code now working, it should be possible rapidly add pages to the website simply by modifying main.json and adding new content files.
In the next post we’ll look at how to make these changes safely, as well as adding some navigation and styling to our website.
Leave a Reply