Over the last years I have worked with a couple of modern CMS platforms and technologies like Adobe CQ5, Craft CMS, Craft Commerce, Zend Expressive, Laravel and so on.
Working with WordPress again is painful at times, specifically looking at its template engine, its database design (with all sorts of meta tables, taxonomies and multiple data types like orders, posts, pages, invoices into one single wp_posts table) and the way hooks, filters and actions make it virtually impossible to know which, how much PHP code and its what order it is executed at a single request.
That said, I perfectly understand that things are like this for a good reason. This allows a backwards compatibility which allows the use of wide range of plugins. Improving the database structure would render most plugins useless. But speaking as a developer, I want clean code and a fast website and I don’t care for backwards compatibility.

So on this website, I am using WordPress exclusively as a backend as it helps me create posts, pages, upload images etc.

In order to have a modern frontend, I will write a WordPress Plugin which uses Dice dependency injector, FastRoute to handle routes, Symfony’s Twig Templating Engine for our views and a Symphony Console Command which is in charge of exporting posts and pages from the DB into a compact PHP Array every now and then.

Step 1: The WordPress Frontend Plugin

Grab a copy of this basic plugin here. Add it to your WordPress installation. Done. There’s no admin page, or settings page included. You simply use the new frontend by pointing your document root to the plugins’ public folder.
If you want to test it, just open the URL http://yourdomain.com/wp-content/plugins/wordpress-twig-frontend/public/ directly.

Download WordPress Twig Frontend master.zip (7.4 MB)

Step 2: The Cronjob updating our PHP-Array

Now we can create a cronjob with crontab -e and add the following line
*/15 * * * * cd /var/www/html/wordpres/wp-content/plugins/wordpress-twig-frontend && php bin/posts-to-json.php
which will cause the export to run every 15 minutes.
This has disadvantages since I cannot use any other frontend related plugins anymore. But it does give me clean templates and a fast frontend without having to load any WordPress Core files nor templates nor do I need to query the database. This creates an array structure like seen below, including post fields, meta fields, and so on.

...31 => [    'ancestors' => [],    'comment_status' => 'open',    'filter' => 'raw',    'guid' => 'https://erikpoehler.com/?p=31',    'id' => 31,    'meta_encloseme' => '1',    'meta_pingme' => '1',    'meta_yoast_wpseo_primary_category' => '1',    'page_template' => '',    'post_author' => '1',    'post_category' => [        0 => 1,    ],    'post_content' => '<div class="post-content">Hello World.</div>',    'post_date' => '2020-02-03 09:52:36',    'post_excerpt' => '',    'post_exported_date' => '2020-11-25 15:28:24',    'post_exported_time' => 1606318104,    'post_mime_type' => '',    'post_modified' => '2020-02-07 14:52:15',    'post_name' => '31',    'post_parent' => 0,    'post_permalink' => 'http://localhost:8001/2020/02/03/31/',    'post_title' => 'Hello World',    'search_content' => '',    'search_full' => 'Hello World',    'search_title' => 'Hello World',    'type' => 'post',],...

Step 3: Do your actual programming

By default, the plugin comes with only a few Controllers, HomeController.php, SearchController.php, PostController.php, which basically led the JSON/PHP Array created by the CLI command, and passes it to Twig. Your actual Twig templates go in storage/resources/views.

Step 4: Happy templating

Let’s finally take a look at one of these Twig templates. This blogs’ homepage article listing.

{% for item in post %}<article class="post{{ item.id }}" data-id="{{ item.id }}">    <a href="/{{ item.post_name }}/" title="{{ item.post_title }}">        <time datetime="{{ item.post_date }}">{{ item.post_date|date('F jS, Y') }}</time>        <h2>{{ item.post_title }}</h2>        {{ item.post_excerpt|raw }}        <p class="read-more">Read more →</p>    </a></article>{% endfor %}

Sweet. Isn’t it? As you can see we access, the PHP array keys from the array example above. Besides the beauty of the Twig syntax, it also brings performance benefits. Twig templates are pre-rendered into a more machine-friendly syntax and cached for subsequent requests.


This is a lot of work, it’s not suitable for everyone, or every type of website. But, it shows that it is possible to combine modern technologies with WordPress as a backend – and this way have the most performant, modern, Twig-based frontend possible. Without any overhead from DB requests, without loading any WordPress file at all, when a request is made.