Idea: Static Templates for WordPress

I was helping out a friend a few days with their fairly complicated WordPress website. Complicated because it had over 40 different page templates, rendered exclusively by PHP.

Each page template had something special about it, like a form and form handler, a JavaScript calculator, a list of registered users, the current user profile and more. Page Templates worked pretty well, and the other “simple” options were shortcodes (bleh!) or page-{slug}.php templates.

Anyway, when this friend of mine was porting the site over from his development environment to production, he had to recreate those 40 pages, make sure their slugs matched, and assign the appropriate page template from that drop-down list of over 40 times. What a nightmare!

Static Templates

I thought there should be an easier way. One that would work similar to page templates, but without that extra database overhead, without the UI and everything else. Obviously this would render a WordPress theme completely useless outside of the original context, but so do 40 page templates.

I drafted up a plugin, a proof of concept, and called it Static Templates. The idea is for a theme to have a static-templates folder, with .php templates named after certain slugs. For example:

/about/           => /themes/foo/static-templates/about.php
/about/contacts/  => /themes/foo/static-templates/about-contacts.php
/foo/bar/baz/     => /themes/foo/static-templates/foo-bar-baz.php

So when /about/ is requested, you don’t need to worry about creating a page in WordPress, creating a new template and assigning it to your page. All you have to worry about is your /static-templates/about.php file.

Obviously if a page with that slug exists in the WordPress database, it’ll be loaded instead, so static templates have a lower priority, and there’s still that little overhead of trying to fetch a non-existent page from the database before a static template is invoked. It also does not (yet) distinguish between /foo/bar/ and /foo-bar/ requests.

Anyway, as I mentioned this is just an idea, and I would absolutely love to hear your thoughts about it.

About the author

Konstantin Kovshenin

WordPress Core Contributor, ex-Automattician, public speaker and consultant, enjoying life in Moscow. I blog about tech, WordPress and DevOps.

35 comments

  • What your friend experiences is exactly what I did years ago. Recently, i’d rather utilize add_rewrite_rule and add_rewrite_tag for creating custom “databaseless” page and redirect it using template_redirect as you use in the static-template.

    However, I think your solution is kinda neater. I should give it a try.

    Thanks for sharing the idea :D

    • Thanks for your comment! I think that you aren’t really avoiding that database query with rewrite rules, you’re still pointing it to index.php with some extra query variable, then catching that variable during template_redirect, at which point WordPress has already fired the main WP_Query for the 10 latest posts. Unless of course you’re doing something smart in pre_get_posts to avoid running that main query.

      I thought about doing that for Static Templates, which would increase performance by a little bit, but also break pages with matching slugs, which may or may not be a good thing. I haven’t decided yet :)

    • you’re still pointing it to index.php with some extra query variable, then catching that variable during template_redirect, at which point WordPress has already fired the main WP_Query for the 10 latest posts.

      That’s more to why I think your solution is kinda neater :D

  • Having dealt with many large sites and knowing the frustration that too many templates leads to, I think this is a wonderful idea. I would love to give it a try, it looks like it could make things a lot easier for clients (not having to remember to choose the right template is a huge plus)

  • Maybe I misunderstood the problem, but why wouldn’t it be possible to migrate the database from development to production using WP Migrate DB Pro and deploy the files with sth like Beanstalk?

    • You probably did :) Migration is not the problem. Usability and maintainability are.

      I mentioned database migration because that’s when it hit me. That’s when I thought it should all be easier. Not the migration, we have that covered by numerous plugins, WP CLI, mysqldump, etc. But the whole idea of using page templates for a bunch of static .php files.

    • So how are 40 static templates more usable and maintainable than 40 page templates?

      What about less page templates and a few more template parts instead?

    • Good question. To create a new static template you just choose a name and create it. For page templates you need extra stuff like the page template header, you’ll also need to create a new page in WordPress and assign that template.

      Template parts are different, you can still use them in both page templates and static templates, it’s just a matter of how you organize your code.

      Also, when I say “usable”, I mean usable by developers. None of these (static templates, page templates, shortcodes) are usable by users.

    • Хотел написать умный комментарий на английском, но тренировочка и последующая банька совсем распарили мозг, могу ток на русском)

      на мой взгляд спорное решение. чем больше код отличается от стандартов WordPress, тем сложнее его следующая поддердка.

      В моем случае, такое решение однозначно не пройдет. Работаю в нише биджетных типовых сайтов-взиток. Структура у таких сайтов практически идентична: главная, страница о компании, страница с формой обратной связи, портфолио, либо работы, раздел с новостями. Такие сайты дешевы, поэтому для меня критично время затраченное на каждый сайт.

      Если воспользоваться подходом с статьи, мне нужно будет после сдачи сайта тратить время на обучение заказчика. Объяснять ему как править страницы, почему так, убеждать, что так удобнее и тп.
      Минус для меня – трачу дополнительное время.

      Для закачика минус в том, что если он позже хочет что-то добавить на сайт, то вынужден обратится либо ко мне (что, в принципе, хорошо для меня, но могу быть занят), либо следующий разработчик будет тратить время чтоб разобраться “как оно сейчас работает” – т.е. либо привязан ко мне, либо выйдет дороже у другого.

      Для себя проблему решил проще (на мой взгляд).
      Сделал мастер-дамп базы. В котором уже созданны все нужные страницы, настроены основные плагины и тп.

      И слегка подкрутил wp-config.php
      https://gist.github.com/Dimasmagadan/9139663

      теперь, когда нужно развернуть новый сайт, меняю в этом файле префикс на название сайта (в пример lamoda), копирую с мастер копии папку wp-content в папку с префиксом (lamoda-wp-content), заливаю дамп.
      примерно такой же алгоритм при выкладке сайта в продакшн. (так там естественно wp-config нормальный, пути стандартные, и меняю путь с local на нормальный в дампе).

      на мой взгляд такой подход более WordPress way) и, если заказчик требует инструкций по работе с сайтом, могу с чистой совестью направить его на официальный сайт)

      можно и дальше автоматизировать, но, в принципе, пока копируются файлы, я как раз прописываю нужные префиксы. поэтому по времени то на то и выйдет

    • Спасибо за комментарий!

      Вероятно вы не совсем поняли откуда возникла эта идея и для чего это все. Если вы разрабатываете сайты для заказчиков то вам вообще лучше их держать по-дальше от PHP кода, т.е. ни редактируемых шаблонов страниц, ни предлагаемых статических шаблонов у вас быть не должно.

      Статические страницы здесь предлагаются как вариант замены шаблонов страниц для тех вещей, которые стандартными средствами WordPress (т.е. через интерфейс) в страницу не запихать, например профиль пользователя, сложную форму, карту с 200 js-маркерами из .csv файла и прочее. Разработчику такими страницами легче управлять в .php файлах напрямую, нежели пытаться это все обернуть в какие-то шорткоды и т.д.

      Но опять же, для пользователей WordPress (и для ваших клиентов) это ни в коем случае не подойдет :)

    • Piet – you’re right about WP Migrate being a solution to Konstantin’s friend’s problem of having to reassign templates with the dropdown. The template names are in the wp_postmeta table so all of that is wonderfully conveniently migrated to production by WP Migrate. I love that plugin. It has saved me a ton of time in deployment :)

      I do think Konstantin’s plugin is an interesting idea tho. Think I would have to experiment with it to understand how it would fit with our workflow.

  • This is a neat solution Konstantin, I’ll definitely be using this in my next multi template site for sure. I like the idea of taking the responsibility away from the client, less likely to screw the site up, you could also hide those pages if necessary for example if it was a login/profile section – the amount of times I’ve had concerned clients on the phone due to a mis allocated template ><

  • Love this!

    It would be neat if the wordpress code editor could be modified to create/use/edit your static templates. This could be helpful in some of the shared hosting situations or for when your IT department gives you access to wordpress but not the underlying file structure. I was just helping someone last night in that boat.

    • Thanks for your comment Chris! Editing PHP files from the WordPress interface is insecure, there’s a reason why your IT department gave you access to WordPress, and not the underlying file structure :)

      That said, WordPress does ship with a code editor that lets you edit theme and plugin .php files from within the admin. You’ll need the appropriate capabilities as well as file modes on the server to access that. But again, that’s insecure and fragile. If you break it and you don’t have FTP access, you’re doomed :)

  • Dude, I love this idea! About to go test it. I’ve been struggling with the same issue. I really only use WP for the blog part and have been creating my pages like you mentioned ,create the page in WP then create a file with the slug.

    This plugin seems like a perfect solution so I can A/B test with less hassle :)

  • This looks like a really good idea – I think Login & Register pages are very good use cases for this.

    One question I have is about the hierarchy:

    Shouldn’t
    /about/contacts/

    be equal to
    /themes/foo/static-templates/about/contacts.php

    Because I’d want
    /about-us/ => /themes/foo/static-templates/about-us.php

    Not
    /about-us/ => /themes/foo/static-templates/about/us.php

    Thoughts?

  • Хотел написать умный комментарий на английском, но тренировочка и последующая банька совсем распарили мозг, могу ток на русском)

    на мой взгляд спорное решение. чем больше код отличается от стандартов WordPress, тем сложнее его следующая поддердка.

    В моем случае, такое решение однозначно не пройдет. Работаю в нише биджетных типовых сайтов-взиток. Структура у таких сайтов практически идентична: главная, страница о компании, страница с формой обратной связи, портфолио, либо работы, раздел с новостями. Такие сайты дешевы, поэтому для меня критично время затраченное на каждый сайт.

    Если воспользоваться подходом с статьи, мне нужно будет после сдачи сайта тратить время на обучение заказчика. Объяснять ему как править страницы, почему так, убеждать, что так удобнее и тп.
    Минус для меня – трачу дополнительное время.

    Для закачика минус в том, что если он позже хочет что-то добавить на сайт, то вынужден обратится либо ко мне (что, в принципе, хорошо для меня, но могу быть занят), либо следующий разработчик будет тратить время чтоб разобраться “как оно сейчас работает” – т.е. либо привязан ко мне, либо выйдет дороже у другого.

    Для себя проблему решил проще (на мой взгляд).
    Сделал мастер-дамп базы. В котором уже созданны все нужные страницы, настроены основные плагины и тп.

    И слегка подкрутил wp-config.php
    https://gist.github.com/Dimasmagadan/9139663

    теперь, когда нужно развернуть новый сайт, меняю в этом файле префикс на название сайта (в пример lamoda), копирую с мастер копии папку wp-content в папку с префиксом (lamoda-wp-content), заливаю дамп.
    примерно такой же алгоритм при выкладке сайта в продакшн. (так там естественно wp-config нормальный, пути стандартные, и меняю путь с local на нормальный в дампе).

    на мой взгляд такой подход более WordPress way) и, если заказчик требует инструкций по работе с сайтом, могу с чистой совестью направить его на официальный сайт)

    можно и дальше автоматизировать, но, в принципе, пока копируются файлы, я как раз прописываю нужные префиксы. поэтому по времени то на то и выйдет

    Что-то после отправки комментария никаких сообщений про successful posting или про “подождите проверки модератора” не написано было. Продублирую комментарий, и чуть его отредактирую)

    Но, идея хорошая.
    Подобный подход используют парни с wpmu.org в некотрых своих плагинах. Т.е. для плагинов такой подход иногда единственно возможный вариант. А вот для темы, все же на мой взгляд не лучший вариант(

    • кстати, почему-то в поле под комментарии не работает проверка орфографии( теперь вот стыдно за написанное((

      поддердка, биджетных, сайтов-взиток, некотрых – планировалось, что эти слова будут написаны немного по другому)

  • Great idea! I struggled with this situation previously as well and this seems like a neat solution.

    Quick question. What if you need to include a page created with a static template into a menu — do you use absolute URL to define the link location in the menu? Or is there any way to make these static pages “detectable” from the inside?

  • Hi Konstantin,

    I think you might be on to something here, although I think there are numerous edge cases that would need to be worked out. This would certainly resolve the issue where you point a menu option to a URL like /about/ and then the user haplessly goes and breaks the site by changing to “About Us” and /about-us/ because they like how it looks better!

    Concerns to resolve are that WordPress pretty much assumes a valid queried object unless it’s on a 404 page, and numerous functions that might otherwise be expected to work would need to be tested and if applicable ensure they still work on such a static page.

    Further, rather than use `template_include` to inspect the URL I think it would be better to use `do_parse_request` so you can avoid inspecting all the regexes that you are not going to match anyway. And in that hook you could set `$wp->query_vars[‘static-template’]` which you could use in `template_include`.

    Finally, if this got traction for core they could bypass calling $wp->query_posts() and $wp->handle_404() from within $wp->main(), which I’ve been asking for a way to do for, oh I don’t know, like 5 years! :) Maybe there’s a trac ticket in your near future?

    -Mike

    • Thanks for your feedback Mike! You’re right, there’s a lot of stuff that needs to be worked out, also things like “current-menu-item” classes for wp_nav_menu(). I’m not so concerned about folks changing slugs and breaking things, as well as creating a page with a matching slug and breaking it.

      Again, I don’t think this can be user friendly. It’s like asking a client to maintain a list of rewrite routes in a Django configuration file and if they want to edit the content, we can ask them to edit the views and controllers. Nah :)

      This is more of a hack I guess, but for sure with some more thought we can take it further. In any case, I don’t think it’s something that should belong in core. Definitely not something that 80% of the users would appreciate, not something you would bundle in a theme. Users shouldn’t have to edit PHP files. Ever.

      The whole querying vs not querying question is also interesting. At first I thought I don’t want to break existing pages in the database, which is why the hook on a potential 404, now I’m leaning towards doing it earlier and ignoring any pages, archives or other rewrite rules that may exist.

      Anyway, thanks again for your feedback, I really appreciate it :)

    • Hi @Konstantin,

      If it wasn’t clear, I was not thinking about end-user friendliness, I was thinking about how an agency builds a website using WordPress and then the client breaks it! (Those are the use-cases I see most.)

      Oh and the other things that would ideally be needed is to disallow users from adding slugs that match any of the slugs in the “static templates”, or at least get notified that they would effectively hide the static template pages if they do.

      Actually maybe you should call them static “pages” instead, because unlike Pages that all the WP pundits and end-users call “static pages,” these really would be! :)

      -Mike

    • I like the idea of an admin notice when folks are on an edit page with a slug matching a static template. I also dislike the word “static” in general, because it’s like static HTML, something that does not change, but these are (probably) meant to be more dynamic than your average page. Needs more thought :)

      Either way, if I was an agency or freelancer building a website for a client who’s not fluent in PHP and WordPress, I wouldn’t use something like this.

  • I’ve been using this kind of concept before for my slightly large client, well sort of. Instead of baked in functionality into the theme itself, I created a custom option page where I can put in custom permalink and associated PHP files to be loaded in case of URL match.

    The nice thing with that is I now can access, say `/api` from the URL that basically loaded up my PHP file in custom plugin folder.