I'd personally favour to move to a template engine for 2.0.. this is a quick working draft made in mustache.php (very simple to learn, almost logicless).
the current code taken from ManageMail.template.php
function template_mail_queue()
{
global $context, $txt;
echo '
<div id="manage_mail">
<div id="mailqueue_stats">
<h2 class="category_header">', $txt['mailqueue_stats'], '</h2>
<div class="content">
<dl class="settings">
<dt><strong>', $txt['mailqueue_size'], '</strong></dt>
<dd>', $context['mail_queue_size'], '</dd>
<dt><strong>', $txt['mailqueue_oldest'], '</strong></dt>
<dd>', $context['oldest_mail'], '</dd>
</dl>
</div>
</div>';
template_show_list('mail_queue');
echo '
</div>';
}
the same as mustache template.
<div id="manage_mail">
<div id="mailqueue_stats">
<h2 class="category_header">{{txt.mailqueue_stats}}</h2>
<div class="content">
<dl class="settings">
<dt><strong>{{txt.mailqueue_size}}</strong></dt>
<dd>{{context.mail_queue_size}}</dd>
<dt><strong>{{txt.mailqueue_oldest}}</strong></dt>
<dd>{{context.oldest_mail}}</dd>
</dl>
</div>
</div>
{{>mail_queue_list}}
</div>
IMO there are some big benefits for designers (and developers):
- easy readable code (almost simple html files)
- reduced syntax errors while developing code (PHP is sometimes complex, especially if the templates are using nested ternary operators)
- syntax highlightning in editors (makes it easier to find a syntax error)
- reusable code (mustache templates can be rendered via PHP or Javascript)
Not sure if you like it? I'd be interested in your opinions regarding a template engine..
Back in the early 2000s I experimented with a then-popular template engine (Smarty) in place of just sticking with a self-imposed subset of PHP. It worked fine, but after playing around with it for a while I could only conclude that it was just a redundant extra layer of complexity.
{if !$error}
<h2>User info for {$member}</h2>
<dl>
<dt>Member name:</dt><dd>{$member}</dd>
{if $showemail eq 1}
<dt>Email Address:</dt><dd>{$email}</dd>
{if $altemail}<dt>Alternate Email:</dt><dd>{$altemail}</dd>{/if}
{/if}
{if $ICQ}<dt>ICQ Handle:</dt><dd>{$ICQ}</dd>{/if}
{if $AIM}<dt>AIM Handle:</dt><dd>{$AIM}</dd>{/if}
{if $MSN}<dt>MSN Handle:</dt><dd>{$MSN}</dd>{/if}
{if $fname}<dt>Real name:</dt><dd>{$fname} {$mname} {$lname}</dd>{/if}
{if $bday > 0}
<dt>Birthday:</dt><dd>{$bday} - {$bmonth} - {$byear}</dd>
{/if}
{if $location}<dt>Location:</dt><dd>{$location}</dd>{/if}
{if $occupation}<dt>Occupation:</dt><dd>{$occupation}</dd>{/if}
{if $hobbies}<dt>Hobbies:</dt><dd>{$hobbies}</dd>{/if}
{if $skills}<dt>Skills:</dt><dd>{$skills}</dd>{/if}
{if $title}<dt>Title:</dt><dd>{$title}</dd>{/if}
{if $about}<dt>About user:</dt><dd>{$about}</dd>{/if}
{if $signature}<dt>Forum signature:</dt><dd>{$signature}</dd>{/if}
</dl>
<h2>{$member}'s Gallery</h2>
{foreach from=$images item=row2}
Title: {$row2.title}<br/>Subtitle: {$row2.subtitle}<br/>Size: {$row2.width}x{$row2.height}
<br/>
<a href="gallery.php?iid={$row2.imageid}"><img src="image.php?img={$row2.imageid}" width="200" height="160" border="0"/></a>
<br/>
{/foreach}
{/if}
Disagree. It's just another syntax. Slightly more elegant than PHP in some cases, but I think
this (https://github.com/FreshRSS/FreshRSS/blob/ceda55c75b158fc1cf4813fe0f258527754b9289/app/views/user/profile.phtml) is much closer to the bottom example while retaining regular PHP.
Agree and disagree. Sounds more like a style guide issue, a style enforcement issue, or a legacy code (style) issue.
It looks like this Mustache thing is "only" 10 kB? I suppose that could be acceptable.
tl;dr Seems redundant but probably harmless.
I think a template engine would be interesting.
I thought about it for a while myself, but never managed to even start reading twig documentation. lol
I'm not against for sure, the advantages I see are mainly two:
1) we stop having at least one potential security risk (I know is just a part of the big picture, because the package manager is not different but at least is one less) not having to write directly to php files on the server,
2) we would give end-users a much more user-friendly way of dealing with template edits (i.e. no need to explain that to add a google analytics script they have to either learn a bit of php or install an addon that may or may not work because "someone" forgot to update it xD).
Then, as side-effect, there would be the fact that becoming the templates html files, we would be forced to avoid certain things we have in the templates right now (yes,
@Frenzie they are either legacy stuff or some fancy coding we did, but still with php templates it
is possible to do it, while with a template engine it is not (always, or at least so heavily) possible).
On the "which one to use", I always looked at twig because, as far as I understood, it would allow us a much smoother transition since Twig can use php files as templates and has pretty much the same features as php (conditionals loops, etc.).
As far as I can see, Mustache would instead mean a one-time-full-rewrite of the whole template, that may also require some considerable work on the backend to provide exactly what we need to display (since we nowadays do quite a bit of fancy stuff in the templates).
That said, I expect it would be possible to use some dirty workaround at least during the development phase (like for example use the current php templates to instantiate Mustache and work on one template at a time) to make the transition easier to manage.
All the processing is supposed to be done on the backend. I am a firm believer in lean templates where processing (checks for isset and so on, ternary operators) is to be kept to a bare minimum, avoiding them if at all possible.
@emanuele Instant Twig dislike from me, sorry. While
the Twig blurb (https://twig.symfony.com/) superficially seems to have been written to appeal to me, I find its first argument a spurious, distasteful strawman.
That may be truth-adjecent, but obviously, as @live627 said, that should be done before it reaches the template.
Or you could define a function like escape, esc or e (also, hasn't anyone heard of ViewModels (https://fuelphp.com/docs/general/presenters.html)?) if you want to do it in the template itself. Obviously {{ var|e }} is slightly more concise than <?php echo e($var) ?> but basic critical thinking and courtesy demand that you steelman the competition rather than serving up a strawman.
And PHP doesn't? O-o
Okay, so scratch that other nonsense and there might be something vaguely of interest here. Maybe. It's still unclear to me how this is supposed to be better than regular PHP OOP. But Twig should've led with this rather than with stupid strawmen.
They're not HTML files. You're just replacing PHP with a similar construct. :P
That's a non-argument. So you have to learn ten Twig commands instead of ten PHP commands. :)
It sounds like refactoring the code to use proper separation of concerns as if something like Mustache were involved may not be a bad idea. Cf. https://fuelphp.com/docs/general/views.html and https://fuelphp.com/docs/general/presenters.html But this can never be used as an argument in favor of a template engine.
Ignoring any arguments that are architectural in nature, it would seem that we're left with these two arguments in favor of a template engine:
- Supposedly easier.
- Reusable in JS.
I reject the first argument. What's this supposed to be exactly?
{{#wrapped}}
{{name}} is awesome.
{{/wrapped}}
Oh right, I think it's equivalent to this:
<?php foreach($wrapped as $name): ?>
I'm sure users will greatly appreciate the increased clarity. :o :(
That leaves the reusable in JS argument. The question is, does it matter? On the one hand you're probably shaving off a few bytes by using JSON, on the other hand the browser needs to do some extremely slow templating nonsense. My instinct says it's probably a counterproductive battery usurper but benchmarks can easily prove me wrong.
@Frenzie : yes ... twig, smarty and most of the other template engines are complex and just another syntax for PHP code at all. I wouldn't use any of them...
But that's not the case with Mustache.. the logic (some special cases) would have to be moved to the controller.
Another example, taken from ElkArte code:
// Is the clock ticking?
if (!empty($context['poll']['expire_time']))
echo '
<p>
<strong>', ($context['poll']['is_expired'] ? $txt['poll_expired_on'] : $txt['poll_expires_on']), ':</strong> ', $context['poll']['expire_time'], '
</p>';
in mustache.php you could do it that way:
{{#context.poll.is_expired}}
<p>
<strong>{{txt.poll.expires_on}}:</strong> {{context.poll.expire_time}}
</p>
{{/context.poll.is_expired}}
another approach would be
// poll expired? let's show a small warning
if ($context['poll']['is_expired'])
echo $mustache->render($render_data, 'poll_expired');
and
<p>
<strong>{{txt.poll.expires_on}}:</strong> {{context.poll.expire_time}}
</p>
I think both versions are easier to read compared to the original ElkArte code..
If you look at the more complex templates, espacially those with mixed HTML, PHP and Javscript:
if (!empty($context['attachments']['ila_enabled']))
{
addInlineJavascript('
var IlaDropEvents = {
UploadSuccess: function($button, data) {
var inlineAttach = ElkInlineAttachments(\'#postAttachment2,#postAttachment\', \'' . $context['post_box_name'] . '\', {
trigger: $(\'<div class="share icon i-share" />\')
});
inlineAttach.addInterface($button, data.attachid);
},
RemoveSuccess: function(attachid) {
var inlineAttach = ElkInlineAttachments(\'#postAttachment2,#postAttachment\', \'' . $context['post_box_name'] . '\', {
trigger: $(\'<div class="share icon i-share" />\')
});
inlineAttach.removeAttach(attachid);
}
};', true);
}
IMHO that code is readable for a skilled developer but not for an average designer, typical problems here:
where do I use single quotes / double quotes?
where do I need to escape a quote with a backslash?
Another possible case:
Let's assume our controller would just give you JSON data. You could render that code on the server side (with mustache.php) and also on the client side, for example inside an android or IOS app (JS version of mustache) by using the exact same templates.
Which is absolutely terrible as far as I'm concerned. I think it's an incomprehensible illegible monstrosity. I take back what I said about it looking harmless.
{{#items}} // this is foreach
{{#first}} // this is if?! this isn't logic-less, this is logic-unclear
<li><strong>{{name}}</strong></li>
{{/first}}
{{#link}}
<li><a href="{{url}}">{{name}}</a></li>
{{/link}}
{{/items}}
Mostly true, but irrelevant.
Entirely true, yet also entirely irrelevant.
Whether this would be in any way beneficial is what has to be proven. You can't presuppose that it's somehow magically useful to use "the exact same templates." That just sounds like adding extra complexity on the client side and wasting a lot of battery life by short-cutting the highly optimized HTML parser. Using
different templates could potentially be worthy of the wasteful trade-off.
You can't use current Elkarte code as an argument. You have to imagine the Elk template controller and view code
as if it were written for Mustache. A concrete example of a ViewModel implementation that I already mentioned can be seen in https://fuelphp.com/docs/general/views.html and https://fuelphp.com/docs/general/presenters.html
Answering only a quote because I'm late for work. :P
Sort of, my point is that to do any tweak to a template nowadays you at least to learn the specifics of "echo", this is a mandatory requirement. Yes, you can argue that is just double and single quotes, fine. I can tell you that, from my support experience, this is far more than the average admin wants to learn.
I'm not talking about designers here, I'm pretty sure designers can learne pretty much whatever language they want (if they understand bootstrap I'm pretty sure they can).
On top of that, any error in the writing of a simple tweak results in the crash of the forum (or at least part of it, but since 99% of the edits people want to do are done in index.tempalte.php, it means full crash).
With a template engine, this risk should be reduced quite a lot.
The comparison with wordpress is slightly less evident, because WP uses a completely different approach (i.e. html-with-php-injected VS php-echo'ing-html), that per se is kind of easier to grasp for the average user, but that for my personal point of view is something that makes my eyes spill blood.
You can write Wordpress templates "Elk style" if you prefer as well, though really doing so is just more difficult and less clear. But why does the "Wordpress style" offend you? The alternative is just "replacing PHP with a similar construct" to quote what I wrote a few hours ago. {{ var }} may or may not look superficially vaguely more attractive than something like <?php echo $var; ?> but what difference does it actually make? I'm not particularly convinced one is clearer than the other either — a much more important metric, I might add. If you truly dislike that style so badly for some reason then yes, perhaps something that compiles down to <?php echo $var; ?> is better. But it doesn't sound like a very good argument.
Incidentally, I think this is quite elegant: https://github.com/tropotek/tk-domtemplate
In any case, the point is that showing some complex thing full of commas and quoting difficulties and ternary operators in order to present a template engine as an alternative to
that is deceptive toward yourself and others. It's just not a fair comparison. You can do the same rewrite with the same separation of concerns without adding anything extra.
An interesting point.
Btw, there's also http://www.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
That way you can
echo <<<HTML
no " quote ' escaping necessary lalala $var
and because we used HTML we get the correct highlighting in Vim!
No logic allowed in here either.
HTML;
Because my brain is too simple, last time I tried to enter-php(conditional)/exit-php(bloc-in-the-conditional)/enter-php(second-optiona-of-the-conditional)/exit-php(some-html)-enter-php(start-loop)/exit-php(bits-of-html-for-theloop)/enter-php(echo-var)/etc. my brain gave up and shutdown. xD
I'm not able to follow a slightly-more-than-basic conditional/loop in the WP-like style (and that's one of the reasons I abandoned almost completely the software).
But I guess that's mostly an holy-war like it could be tab-VS-spaces and curly-on-the-same-like-VS-curly-on-the-next-line. ;D
That said, I'm not trying to defend Elk-styling, because I don't like that one either: two levels of indentation (one for php code, one for html markup), quite complex logic structures, function calls (and even closures I think) and so on.
I'm open to alternatives, in order to find something that:
1) is not too difficult to understand and learn,
2) is easy on end-users (not talking about themes) not generating hard failures,
3) (that is more 2b) does not require executable files in the template directory,
4) is not too complex to implement,
5) is maintained (for two reasons: a) have a fast reaction to potential security issues and b) no need to write our own template engine when the only advantage we'd have is to have more code to maintain).
Then, of course, point 1 and 2 are subjective (and point 4 depends on the skills and knowledge of the one that is going to implement it, so it's kind of subjective as well).
Based on my objectives, almost any template engine is to me preferable to php code because of point 2 (and 3), then, which one in particular is just a matter of discussion.
Of course, that's just my own opinion and not much more, if others prefer not to use a template engine at all, fine.
Interesting indeed. :D
I'm fine with a template engine really, whichever out of e.g. Smarty, Twig or Mustache (not RainTPL anymore; it's dead), maybe others. The benefit is much the same regardless whether you implement the better separation of concerns with or without a special template engine, but it's an improvement in maintainability, comprehensibility and convenience either way. It would be counterproductive to oppose that, especially if it means the situation would otherwise remain as it is. ;)
Smarty has clever template inheritance. Mustache only has
unofficial extensions (http://trimou.org/doc/latest.html#extend) that are mutually incompatible (https://github.com/bobthecow/mustache.php/wiki/BLOCKS-pragma). I'm also not sure if it's quite as clever, but it's probably good enough.
Not being a coder and no nothing about php I think a template system would great for people like me that makes themes and know nothing about coding.
I'm not sure what this buys other than another dependence on a third party project and whatever limitations it enforces and yet more files that have to be edited /searched to make a change. All the ifs, elses, and variable setting has to happen anyway. If you don't want to break up your echo statements do all the work you'd have to do for the template engine above the echo then just write the echo with variable names.
echo '
<html stuff>${variable_name}<more html stuff>
';
No splits, indent how you want, etc. If it's complicated enough to need split up for lots of if / else branches that totally change the rendering that's all still true for the template too right?
Then is it not too big for its britches?
I think that is more that 99% of the edits are done either in the header area or in the footer so that they are visible in any page (and both are in index.template.php).
They do, but — and I must stress that this has nothing to do with template engines — you can separate such logic from the output to a much greater degree than it presently is. This tends to increase the clarity of both logic and output.
The bulk just looks like a slight overuse of inline ternary operators. :P
A question I just thought of while working on an addon for a client: How would template layers work in Twig et al? Genuinely curious, as I don't know how to work with any template engine other than PHP.
depends on where you want it integrated..
it could be injected in the TemplateLayers.class.php (haven't looked at how, tbh) or you could use the existing template functions and replace the code with a template loader:
function template_mail_queue()
{
global $mustache, $context, $txt:
$tpl_data = array(
'context' => $context,
'txt' => $txt,
);
$tpl = $mustache->loadTemplate('manage_mail'); // loads __DIR__.'/views/manage_mail.html';
echo $tpl->render($tpl_data); //renders the tpl_data array
template_show_list('mail_queue');
}
That would (in theory) allow us to create different themes with different engines. And funnily without touching the core files at all,
for example one Theme with pure PHP, HTML, CSS (what we currently use) ,..
another one with mustache as template engine ..
and a third one with twig..
Please explain to me exactly what advantage this brings. Syntax substitution is all I've seen really.
Please, read the topic from the beginning and I made at least a couple of arguments that are not at all about syntax substitution.
Syntax. It really doesn't look any easier to me. As I've said you can rearrange the php to make it prettier if you want.
Syntax. And one more syntax / system to learn.
Syntax.
So you have to load mustache into the browser so it can do the work?
Not really seeing this one, especially since you'll still be writing to all the ones in say the source directory. Plus what security risks will whatever template engine whose files you're updating have?
Not seeing this at all. It's just a different syntax to learn. Probably on top of php if you're adding anything new feature wise as there will be php code required to do that.
As to the crash the forum, at least that gets the bug fixed. I don't know how the various template engines will actually respond if you have a, you know, syntax error. Plus you've still got all the conditionals which will probably be in php anyway and thus just as prone to crashes. Really all I see is changing syntax and taking on the hassle of some third party package and whatever support it does or doesn't have and whatever limitations and bugs it does have.
I actually hadn't thought of turning this pro-template argument right on its head. PHP supposedly lures you into using more features than those strictly needed for templating. By contrast, Mustache easily enables doing much worse! :P
But the answer to the question is no. I wouldn't use terms like "mostly harmless" for Mustache if that were the case.
The funny thing is that Mustache doesn't do what it advertises at all. Like I said, they're not "logic-less" (hah!): they're logic-unclear. It's still spaghetti code. For proper logic-less templates, which are highly superior to Mustache's "look how cleverly we're trying to hide the logic" attitude, you need a template engine like I already linked to above.
https://github.com/tropotek/tk-domtemplate
https://code.google.com/archive/p/querytemplates/
https://github.com/punkave/phpQuery
Those actually deliver what Mustache promises. Unlike Mustache.
tl;dr Smarty doesn't pretend to be anything it's not and is therefore infinitely superior to "Strawman" Twig and "Logic Soup Spaghetti Code" Mustache. However, that which Mustache argues actually does make sense. It just plain sucks at it.
PS The actual logic-less approach may not meet the "friendly on the user" requirement. But it'll properly reduce maintenance nightmares.
They will compile down to valid PHP and silently output different HTML than you're expecting. There's no such thing as a syntax error really. It's either something special or just regular old output. But you can easily make the same kind of mistakes in PHP.
Apart from the template engine, that could be whatever, I think we can agree on two things:
1) lots of logic should disappear from the templates (pretty much like queries disappeared from the controllers),
2) admins that are not insterested in learning anything deserves something that doesn't crash their forums incase of mistakes.
These are tge two current problems.
1 can be addresses withot a template engine (and actually I think it would be better to solve it before thinkinf about anything else).
2 would definitely require an approach similar to that of a template engine, but is nor an immediate concern.
Based on that, I think the first thing to do is solve 1, with agreed c9nventions and conding styles, something like do not use any other variable apart $context in the template files.
Sounds like a good plan. After one is handled you can better decide how to handle two if it's even still much of a problem.
To all the suggestions of 'but it just changes the syntax', respectfully, you've all missed the point.
Yes, it changes one syntax for another. Most importantly it forces you to not have complex logic in the template, which is a good thing. Because complex logic has no place in the template.
Additionally, it means that anyone who wants to put in some tracking HTML or some other kind of HTML can just copy/paste it without having to futz around working out the correct quoting; to hardened programmers this is a triviality if annoying - but the majority of consumers (both in SMF and Elkarte terms) are not hardened programmers. They're regular people who run a forum who just want to be able to put their thing in and have it work without it being a problem.
I won't pretend it isn't a lot of work - it is a lot of work to do the conversion.
I should know (https://github.com/SockDrawer/StoryBB/tree/master/Themes/default/templates) whistle
But I think the net result is worth it.
Looks to me like each template block is a separate file. /me likes that :)
It's a separate file so you can just globally say 'I want this template' regardless of where it might otherwise be located. It also makes you think about some of the 'clever' logic that SMF did where templates sometimes got repurposed or templates were chunks of if (condition) echo 'bunch of stuff' elseif (condition) echo 'different bunch of stuff' which really should have been separate templates.