Creating A Single Page Application Using Mustache and PHP

Creating A Single Page Application Using Mustache and PHP

Ever wanted to master Mustache single-page application development? Did you know you can use PHP with it? In this tutorial, we go over how you can create a single-page application using Mustache and PHP.

In today's fast-paced world, users expect websites and applications to load quickly and provide a seamless experience. Single-page applications (SPAs) have emerged as a popular solution to meet these expectations. With Mustache and PHP, developers can build dynamic, responsive, and scalable SPAs that deliver content and functionality without requiring page reloads. However, mastering these technologies can be challenging, especially for those new to web development.

In this tutorial, we will dive deep into the world of Mustache and PHP to help you master single-page application development. We will cover the basics of SPAs, discuss the benefits of using Mustache and PHP, and provide step-by-step guidance on how to build a SPA from scratch. Whether you're a beginner looking to learn more about web development or an experienced developer seeking to expand your skills, this tutorial will provide you with valuable insights and practical tips to take your SPA development to the next level.

View This On YouTube

File Structure

index.php
autoload.php
.htaccess
/controllers
   Nav.php
   Templates.php
/sass
     style.scss
/css (generated by Sass)
   style.css
   style.min.css
/views
   404.html
   about.html
   contact.html
   home.html
   partials/
      /contact
         forms.mustache
      footer.mustache
      header.mustache
      styles.mustache

htaccess File

We are using the .htaccess file to redirect all page calls to the index.php file. So if you go to / it will show the index.php and if you go to /about it will show the same index.php. We will use this as the basis of our routing.

<IfModule mod_rewrite.c>
    Options +FloowSymLinks
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.*) index.php [L]
</IfModule>

Install Mustache

You can either download Mustache from their website or use Composer to install it. For this tutorial, we will be using Composer.

composer require mustache/mustache

This will give us access to the vendor and autoloader via Composer.

Setup our index.php

Since this file will be used for all requests on this website, we need to configure it in a way it acts as a router.

<?php
require_once 'vendor/autoload.php';
require_once 'autoload.php';

Mustache_Autoloader::register();

Create Our Autoloader (for our application classes)

In a previous video I created, I went over how to create your own Autoloader for your custom classes. You can see that video here:

This code comes in handy when you are creating your own custom classes and don't want to have to require or include them. In this case, we will use it to pull our custom classes from the controllers folder.

<?php
function autoload($class) {
    include 'controllers/'.$class.'.php';
}

spl_autoload_register('autoload');

Create Our Templates Class

The template class will have some key methods in it that use Mustache and render the content/data.

In our __contruct method, we will initialize the Mustache Engine and add our partials to the object. This will help when we go to use our partials below.

Next, we create the render method. This method will get the content from the view HTML and parse it using Mustache. For the purposes of the next block of code, we have coded a $data array that will be used for the home page. In a few steps below, we will create a method data that uses a switch statement to get the content for multiple pages.

Finally, we have getPageURL. This method grabs the current page from the URL and allows us to use the render function to pull the appropriate template from the views folder.

<?php
class Templates {
    private $m;

    public function __construct(){
        $this->m = (new \Mustache_Engine(
            [
            'partials_loader' => new \Mustache_Loader_FilesystemLoader('views/partials'),
            ]
        ));
    }

    public function render($template) {
        $data['content'] = [
           'title' => 'Home',
           'heading' => 'Welcome to the home page!',
           'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
        ];
        $template = @file_get_contents('views'. $template.'.html');
        if($template === false) {
            $template = file_get_contents('views/404.html');
        }
        return $this->m->render($template, $data);
    }

    public function getPageURL() {
        $url = explode('?', $_SERVER['REQUEST_URI']);
        return ($url[0] == '/' ? '/home' : $url[0]);
    }
}

Notice the @ symbol on the file_get_contents method. This will prevent warnings from showing if the file is not found. We will handle that with our 404 template call.

Setup Our First Template

We are now going to use the {{}} Mustache variables in our simple HTML.

When you see the {{ variable }}, this will print out a variable that matches the data being sent over. In our code, we use {{ content.title }} for the title. This tells the template to look for an array content and add the value from the title object. If you need the template to produce a rendered object, you would need to use {{{ variable }}}, otherwise, it just displays as text.

You will also notice {{> styles }} in the below code. This adds partials that match that name. We will get into that a bit more below.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{{ content.title }}</title>
    {{> styles }}
</head>
<body>
    {{> header }}
    <main>
        <h1>{{ content.heading }}</h1>
        <p>{{ content.content }}</p>
    </main>
    {{> footer }}
</body>
</html>

For the most part, you can duplicate this for each additional page unless you are adding different content or data to the template.

There are certain tags you use in Mustache. I will list the most common ones out here:

{{ variable }} this allows you to add text from a variable.

{{{ variable }}} this allows you to add rendered text (it is different from the {{}}).

{{# variable }} whatever you want here {{/ variable }} if a variable is true

{{^ variable }} whatever you want here {{/ variable }} if a variable is false

{{# array }}
   {{ item }}
{{/ array}}

get items from an array as a loop or use {{ array.item }} to get a single item

{{> folder/template }} get a mustache partial from a folder, remember the templates in this folder must have the extension .mustache since it is rendered via the Mustache code.

Setup Partials

In this part of the tutorial, we are going to create a header, footer, and style partial. Think of a partial as a include or require file you would normally use in PHP.

In the views/partials folder, create the following files:

header.mustache

<header>
    {{# nav.header }}
        <div class="logo">[logo]</div>
        <ul>
            {{# links }}
                <li><a href="{{ url }}">{{ name }}</a></li>
            {{/ links }}
        </ul>
    {{/ nav.header }}
</header>

footer.mustache

<footer>
    {{# nav.footer }}
        <ul>
            {{# links }}
                <li><a href="{{ url }}">{{ name }}</a></li>
            {{/ links }}
        </ul>
    {{/ nav.footer }}
</footer>

styles.mustache

<link href="/css/style.min.css" rel="stylesheet">

You can create as many partials as you need, but for this tutorial, we will only be using these 3.

Create Your Nav Class

In your controllers folder, create your Nav.php file. We will use this to dynamically generate the header and footer links.

<?php

class Nav {

    public function header() {
        $header = [
            'links' => [
                ['url'=>'/', 'name'=>'Home'],
                ['url'=>'/about', 'name'=>'About'],
                ['url'=>'/contact', 'name'=>'Contact'],
            ]
        ];
        return $header;
    }

    public function footer() {
        $footer = [
            'links' => [
                ['url'=>'/about', 'name'=>'About'],
                ['url'=>'/contact', 'name'=>'Contact'],
            ]
        ];
        return $footer;
    }
}

Now that we have created the nav class, we can add it to our template class.

In your Templates.php file, add a new variable below private $m;, so it now says

private $m;
private $nav;

This will declare our class variable. So, now, in your constructor add $this->nav = new Nav(); under the Mustache_Engine variable. This will give us access to the nav class.

We will use this in a moment.

Create Dynamic Data

In the first part of the code, we added only data for the home page.

$data['content'] = [
    'title' => 'Home',
    'heading' => 'Welcome to the home page!',
    'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
];

We want to take this and make it more dynamic. Create a new function in the Templates.php file called data(). We are going to add our header, footer, and switch statement for the data. Your final code should look something like this:

public function data($page) {
    $data['nav']['header'] = $this->nav->header();
    $data['nav']['footer'] = $this->nav->footer();
    switch ($page) {
        case '/home':
            $data['content'] = [
                'title' => 'Home',
                'heading' => 'Welcome to the home page!',
                'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
            ];
            break;
        case '/about':
            $data['content'] = [
                'title' => 'About',
                'heading' => 'Welcome to the about page!',
                'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.',
                'additional' => ['item 1', 'item 2', 'item 3']
            ];
            break;
        case '/contact':
            $data['content'] = [
                'title' => 'Contact',
                'heading' => 'Welcome to the contact page!',
                'content' => 'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
            ];
            break;
        default:
            $data['content'] = [
                'title' => '404',
                'heading' => 'Oops! Page Not Found',
                'content' => 'This page cannot be found, please try again.'
            ];
            break;
    }
    return $data;
}

This should allow us to create other HTML templates in our view (about.html,contact.html,404.html) as well as link to our header and footer partials.

Go ahead and create those pages if you have not already done so.

They should look like the home.html we have already created.

Update index.php For Template Changes

We initially created the index.php with a reference to the Mustache_Autoloader. We can now finish this page.

Add the following code to the end of the index.php:

$templates = new Templates();
$page = $templates->getPageURL();
$data = $templates->data($page);

echo $templates->render($page, $data);

That code should now pull in the Templates class and call the functions we created to display the data and get the templates.

Conclusion

You should be able to run your code now and see the different pages and content from your methods.

This is a simple way to create a dynamic website, and the cool thing is Mustache does not care where the data comes from. In this tutorial, we are hard-coding it in the method, but you can pull it from a database, an API, a JSON file, or even a CSV. As long as you are sending the data to the template, Mustache will display it where the {{ variable }} is.

The only thing you have to remember is, Mustache is a "logic-less" template engine. So you cannot do logic statements. The data has to be prepared prior to entering the template. So if you need to do a if statement, you will need to do it in the PHP code before rendering the template. Outside of that, it is a very useful tool for creating dynamic, data-driven websites.

Watch the video above or download the full codebase using my GitHub profile here: https://github.com/thedevdrawer/mustache-php.

Good luck coding with Mustache.