Getting started with the Themosis framework – Part 4

In this final tutorial part, we're refactoring our home route to use a controller and setting up all our application routes in order to get a fully functionnal blog.

Final step into building our simple blog application with the Themosis framework. In order to follow along in this last article, make sure to have fully completed the steps in part 1, part 2 and part 3 of this “Getting started” tutorial.

This fourth installment will introduce you to controller classes and how to leverage the new CLI tool in order to scaffold your files. Watch the video or/and read the tutorial below.

Video

Tutorial

Use a controller

As a first step to improve our code, we’re going to refactor the home route to use a controller class instead of an anonymous function. This improves code readibility and management as we can split the logic into individual pieces instead of writing everything in a single file.

A controller is nothing more than a PHP class where you orchestrate the logic based on a request end-point. For example, you can fetch data from a storage (database, …), call an third-party service, and then prepare your data for output and finally returning a view to the browser.

Now open your Terminal or Console and connect to your virtual machine using Vagrant like so:

vagrant ssh

Then change directory to your application root:

cd code

Since release 2.0, the Themosis framework is bundled with a CLI tool. By calling the CLI tool without any arguments, you should get a list of all its available commands. Run the following command into your Terminal or Console:

php console

Normally, you should get something like in the screenshot below. The command we are interested into here is the make method and more specifically, it is the make:controller command.

Themosis framework CLI application default commands.
Themosis framework CLI

Now, run the make:controller command and pass it the name of your controller class as the first argument, here we’re going to call our class the HomeController:

php console make:controller HomeController

The make:controller command generates a new file called HomeController.php and stores it into your app/Http/Controllers directory. Open the file into your code editor.

My Blog home controller class.
HomeController.php

Let’s define a new public method into the HomeController class that is going to handle our home route request. Add the following code:

public function index()
{
    return view('blog.default');
}

Only “public” methods can respond to requests. In this code snippet, we are simply returning a view called blog.default (replacing the blog.archive view). Now, how do we connect our home route to use our controller index method?

Open the routes/web.php file in order to edit our default home route. Replace the anonymous function passed to our home route and call our controller like so:

Route::any('home', 'HomeController@index');

The syntax use the @ character. On the left we specify the class name (not its full name) and on the right the method name. If you switch to your browser and visit the home page (refresh), you should have the following image on screen.

Twentynineteen home page handled through the HomeController PHP class.
Twentynineteen home page

This now completes our home route. Each time an end-user requests the home page, it runs through the home route, here defined using a WordPress route. Then the route passes the request to our HomeController PHP class which handles very basic logic and returns the HTML or output through a view file.

Next, we’re going to define all the necessary routes in order to navigate our blog application.

Single post route

If we click on the “Hello world!” article on the home page, we get a 404 Not found page.

Themosis framework default 404 page.
Page not found – 404

This is the default framework 404 page. Note that this screen is rendered from the core package and can be overwritten or you can simply provide your own 404 view file as we’ll see later on.

We’re missing a route that listens on requests made to a single blog post. Let’s fix this! Open your routes/web.php file and add the following WordPress route:

Route::any('single', 'PostController@index');

The PostController does not yet exist, so let’s create it using the CLI make:controller command. Open your Terminal or Console and run the following command:

php console make:controller PostController

Just like with our home controller, the make:controller command generates a new file called PostController.php into your app/Http/Controllers directory. Open the file and insert the index method like so:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PostController extends Controller
{
    public function index()
    {
        return view('blog.single');
    }
}

The index public method returns the blog.single view stored inside your theme views/blog folder. If you switch back to the browser and refresh the “Hello world!” post, you should now get the following output on screen:

My Blog single post.
My Blog – Hello world!

Next, let’s tackle the category and date archive routes!

Archive route

If we follow the WordPress template hierarchy like below, you can see that in order to handle requests made to a single category term or a date archive, we can use the WordPress archive “template”.

WordPress template hierarchy
WordPress template hierarchy

Behind the scene, WordPress is finding this request by calling the is_archive template function. And inside our Themosis framework blog application, this template function is by default associated to the archive condition keyword. So let’s use this archive condition!

Open the routes/web.php file and add the archive route like so:

Route::any('archive', 'ArchiveController@index');

Next, generate the ArchiveController class using the CLI:

php console make:controller ArchiveController

Open the ArchiveController.php file in your code editor and define the index public method like so:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ArchiveController extends Controller
{
    public function index()
    {
        return view('blog.archive');
    }
}

From the browser, try to visit the default “uncategorized” category or the date archive link displayed on the home page footer (add the archive widget if necessary). Normally you should have the following output:

If you still get a 404 Page not found, simply flush the WordPress permalinks.

My Blog single category term archive.
My Blog – Single category term archive
My Blog date archive
My Blog – Data archive

Now, let’s define the route that listens on requests made to a WordPress page.

Page route

Before setting up our page route. We first need to have a link to one WordPress page. At installation, WordPress is always adding a “Sample page” as an example. First, let’s add a menu with a link to this sample page.

Visit the WordPress administration from your browser and then go to “Appearance -> Menus”. Then create your first menu. Here we’re calling it “Main menu”, and attach the “Sample page” menu item to it. Next, under the “Menu Settings” section, apply the “Primary” display location and save your menu.

My Blog main menu attached to the primary display location.
My Blog – Main menu

Quick note about the menus and how to handle them within a Themosis framework theme. Just like at your application root, a theme and even a plugin, contain a config directory. If you open your theme config directory, you should a list of configuration files. The one we are interested into here is the menus.php file and should have the following code attached to it:

<?php

/**
 * Edit this file in order to add WordPress menus locations.
 * The key is the menu location slug and its value is its description.
 *
 * @see https://developer.wordpress.org/reference/functions/register_nav_menus/
 */
return [
    'menu-1' => __('Primary', THEME_TD),
    'footer' => __('Footer Menu', THEME_TD),
    'social' => __('Social Links Menu', THEME_TD)
];

A configuration file is just an array of key/value pairs. Within this menus.php file, you can register your theme menu locations. The key is the menu slug and the value is its displayed title. Note the use of the THEME_TD constant here. This constant is defined for you automatically and should be used if you need to provide theme translations.

Back to our sample page, visit the home page of your blog and then click on the “Sample Page” link to view its content. You should get a 404 page not found. Let’s now define the WordPress route! Open your routes/web.php file and add the following route between your “single” and “archive” routes:

Route::any('page', 'PageController@index');

Routes are read top to bottom inside your file. And if the framework finds a match for the current request, it takes the first route that works. Generally it is recommanded to define routes in this order:

  1. Classic routes
  2. WordPress routes
    1. Single WordPress routes
    2. Archives/generic WordPress routes

So based on this order, your routes/web.php file should look like this:

<?php

/**
 * Application routes.
 */
Route::any('home', 'HomeController@index');

Route::any('single', 'PostController@index');

Route::any('page', 'PageController@index');

Route::any('archive', 'ArchiveController@index');

Next, open your Terminal or Console and generate the PageController class using the CLI tool:

php console make:controller PageController

Open the PageController.php file and define the public index function in order to return the pages.default view stored inside our theme:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class PageController extends Controller
{
    public function index()
    {
        return view('pages.default');
    }
}

If you visit the “Sample Page” link inside the browser, you should now be able to view its content like in the image below.

My Blog sample page.
My Blog – Sample Page

The page WordPress route is the most generic WordPress route for pages. With it, it is also possible to be more specific by passing a page ID or slug if you need to return a different layout. The framework also support page templates using the template WordPress route. I encourage you to dig into those case scenarios by looking at “Page route” documentation.

Search route

Back to our routes/web.php file, let’s define a WordPress search route in order to be able to use the default search form on our blog. Add the following route:

Route::any('search', 'SearchController@index');

Then from your Terminal or Console, use the make:controller command to generate the controller class like so:

php console make:controller SearchController

Inside your code editor, open the SearchController.php file and define the public index method as defined in the route. Then simply return the search view stored inside your theme views directory.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class SearchController extends Controller
{
    public function index()
    {
        return view('search');
    }
}

If you now test the default search form, you can see that our blog application is correctly handling the results.

My Blog search results.
My Blog – Search page

404 route

As a last route, we’re going to handle non-existing endpoints inside our blog application. In order to do so, open your routes/web.php file and add the following route:

Route::any('404', 'ExceptionController@index');

Next, generate the ExceptionController class using the CLI tool:

php console make:controller ExceptionController

Open the ExceptionController.php file stored inside the app/Http/Controllers directory, add the public index method and return a 404.blade.php view like so:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class ExceptionController extends Controller
{
    public function index()
    {
        return view('exceptions.404');
    }
}

Visit a random URL in the browser and you should see a newly styled 404 page.

Now I could have stopped here but you should note that there is one issue with the WordPress 404 route. Behind the scene, it leverages the is_404() template function. And if WordPress does not recognizes a request based on the core elements it defines, like a post, a page, an archive, … WordPress is setting the request has not found.

This default behavior may cause some issues if you work with “classic” routes or if you have plugins that define custom endpoints/routes. Indeed, because this WordPress 404 route is a catch-all requests if not from the core, your custom routes may simply return the 404 view instead of your personnalized content.

So instead of using this default 404 WordPress route, I recommand you to use another method provided by the Routing API, which is the fallback() method.

Replace the 404 route code by this one:

Route::fallback('ExceptionController@index');

If you try again a random URL in the browser, you should still get the appropriate view diplayed like the image below.

My Blog fallback content.
My Blog – Fallback route

Final words

That’s it for our “Getting started” tutorial. This is an introduction and we have covered quite a few of the groundwork. We learnt how to start a new project, how to setup a local development environment and configure our application. We learnt the basics of the Routing API, how to define custom routes (“classic”) and how to use the “WordPress” routes. We introduced Laravel Mix to handle our theme assets and see how to register them using the Asset API.

I plan to create a more “Advanced” tutorial that will dig into more APIs provided by the framework. Subscribe in our newsletter below to be notified when the course is available.

In the meantime, you can also follow us on Twitter or contribute to the project by visiting our GitHub account and dig into the source code.

For people that are seriously considering to work with the Themosis framework for their business, we also provide a professional support to help you in your projects. Visit our support platform and create an account in order to receive assistance.

Finally, I encourage you to read the extra resources below in order to get a deeper understanding of what’s possible with the Themosis framework. I hope this tutorial helped you. See you! 👋

Resources

Here is a list of references to check if you’re looking for more detailed informations on a subject:

2 thoughts on “Getting started with the Themosis framework – Part 4

  1. Maxime

    Hi Julien !
    thanks for this Getting Started tutorial. In your upcoming advanced tutorial, it would be great to have a demo on some more advanced concepts regarding the link between Laravel stuff (such as Models, Eloquent, Form validation) and WordPress (localization, custom fields, plugins).

    Thanks again.

    1. Julien Lambé

      Thanks! This is indeed planned for the advanced course. I’ll cover all APIs and you’ll learn to build a bespoke web application from scratch with the Themosis framework. Stay tuned 😉

Comments are closed.