XF 1.2 Template Modifications and Comparison

Anyone who has developed add-ons for XenForo 1.1 knows that template hooks are a pain. They're a pain for us too, to say the least. Plenty of people have installed the Template Modification System add-on. We've been planning a TMS-like system for some time, before the XenForo add-on was ever actually released.

XenForo 1.2 will deprecate the template hook system and introduce it's own template modification system to make it easier for add-on developers to change templates. Note that I'm primarily focused on add-on developers here. It is possible to create your own custom template modifications if you're not an add-on developer, but unless you have multiple styles, I'd recommend just making the changes to the templates directly.

Let's look at what a template modification is:

ss-2013-04-12_11-35-58.webp


It's simply a "find this" and "replace with that" style replacement. You can do this to any template. If your find matches multiple times in a single template, it will replace each occurrence.

Applying a template modification does not actually modify the template, so it will not show up as customized and it will be automatically reapplied (if possible) when upgrading.

For those of you that want technical details, the modifications are applied before a template is parsed. If the modifications cause a template compilation error, they are automatically disabled.

Here's what the template modification overview looks like:

ss-2013-04-12_11-41-07.webp


All of the template modifications will be listed here, grouped by add-on and ordered by template. The checkbox enables/disables the modification. Note that if the modification is part of an add-on (and you're not in debug mode), you will not be able to edit the modification here but you can enable/disable it. More about this when editing a template.

The 3 numbers indicate the number of times the modification matched (green), the number of times the modification failed to match (grey) and the number of times the modification caused an error (red).

Editing a Template
There are a few new bits when editing a template as well.

ss-2013-04-12_11-43-10.webp


There are 3 new things here:
  • The "prevent" checkbox. If selected, modifications will be never be applied to this template. This can be used to quickly check a template without modifications or to adjust the modifications manually.
  • The "view template modifications" link. I'll discuss this below.
  • The "view custom changes" link. This will simply display a comparison of the parent version of the template (probably the master version) and the current version so you can identify the differences.
When you select view template modifications, you'll see an overlay like this:
ss-2013-04-12_11-43-25.webp

This shows you a comparison of how the template modifications will be applied to this template.
If you choose to manually apply modifications, the template modifications will be "materialized" into the template - they will actually be written into the template and automatic application of modifications will be disabled in this template. You can then manually edit the modifications if you wish. (Obviously if you upgrade an add-on and they've changed their modifications or you install a new add-on that changes this template, you won't be getting those new modifications so this should be used with care.)

Admin and Email Templates
These aren't left out. Add-on developers will have access to very similar systems that allow the admin and email templates to be manipulated in the same way.
We look forward to more dynamic add-ons with XenForo 1.2. :)
 
Last edited by a moderator:
Some analysis of how I currently use the template hooks. I use my blog as the example for this. I have several instances of

Code:
            case 'account_privacy_bottom':        // option to make blog private
                $contents .= $template->create('xfa_blog_account_privacy', $template->getParams());
                break;

Search and replace is a perfect candidate for this. I would just move my template to the replace and put a $0<my_template_contents> in there. I wonder if the replacement tool should just let me select a template for the replacement itself.

Power question: Can I use xen:include in the replacement?

Code:
case 'message_user_info_avatar':
                $options = XenForo_Application::getOptions();
                if ($options->xfa_blogs_showInPosts && !XenForo_Visitor::isBrowsingWith('mobile'))
                {
                    $contents = $template->create('xfa_blog_message_user_info_indicator', $hookParams) . $contents;
                }
                break;
Here things get more interesting since I am accessing some information not previously available to the template. On that case for me (add-on developer), the path would be overriding the View, and adding the "mobile" parameter so it is accessible on the relevant template. That way I can just use the variable on the replacement tool.

Code:
case 'member_view_sidebar_start':
                self::addProfileVisitors($contents, $hookParams, $template);    // reads visitor info, queries DB, builds array, etc
                break;

This one had so much logic that I even moved that to its own static function. The hook even does a database query to fetch dynamic information. Again, I think that I can do with moving all that logic to the view


And finally, I have a bunch of these...

Code:
if ($templateName == 'PAGE_CONTAINER')
        {
            $template->addRequiredExternal('css', 'xfa_blogs_nav');

I hope the template_create hook is not going away, since that is what I use to preload css, and that definitely cannot be done with a replacement



I think the system will work, and it is definitely a great idea. It will mean some rework for us to move from the hooks to the replacements or replacements+view, but that is fine. I appreciate that the hooks are not immediately removed.

I thought I was doing more complicated things, I guess I haven't needed to. And I just realized that on the worst case scenario I could just instantiate my own template on the view and add that as a template parameter. I hope I don't need to use such drastic measures.

I was not personally using TMS but I have helped some setups that have it. It is really powerful and convenient. Integrating that into the core makes sense since that way there are no page load time memory issues.
 
Great feature, however

That's unfortunate. It would be awesome to be able to add per-style modifications instead of editing style's templates. That would make maintaining styles much easier. :(
I think all of the style makers will support that. The reason why most people don't use TMS is that it's not installed everywhere and now when we have it in core I don't see a good reason not to support TMs per style.
 
Just curious Mike is planning the use for style developers to utilize this add-on down the road? This is great news... for add-on developers but would be awesome if we had an official TMS to export out with our styles we distribute. This would make upgrade time on styles next to none making it convenient for us and our customers.

Or maybe someone could post an exact tutorial on how to build an add on using only this for template edits would be useful when the time comes.
 
Some analysis of how I currently use the template hooks. I use my blog as the example for this. I have several instances of

Code:
            case 'account_privacy_bottom':        // option to make blog private
                $contents .= $template->create('xfa_blog_account_privacy', $template->getParams());
                break;

Search and replace is a perfect candidate for this. I would just move my template to the replace and put a $0<my_template_contents> in there. I wonder if the replacement tool should just let me select a template for the replacement itself.

Power question: Can I use xen:include in the replacement?

Code:
case 'message_user_info_avatar':
                $options = XenForo_Application::getOptions();
                if ($options->xfa_blogs_showInPosts && !XenForo_Visitor::isBrowsingWith('mobile'))
                {
                    $contents = $template->create('xfa_blog_message_user_info_indicator', $hookParams) . $contents;
                }
                break;
Here things get more interesting since I am accessing some information not previously available to the template. On that case for me (add-on developer), the path would be overriding the View, and adding the "mobile" parameter so it is accessible on the relevant template. That way I can just use the variable on the replacement tool.

Code:
case 'member_view_sidebar_start':
                self::addProfileVisitors($contents, $hookParams, $template);    // reads visitor info, queries DB, builds array, etc
                break;

This one had so much logic that I even moved that to its own static function. The hook even does a database query to fetch dynamic information. Again, I think that I can do with moving all that logic to the view


And finally, I have a bunch of these...

Code:
if ($templateName == 'PAGE_CONTAINER')
        {
            $template->addRequiredExternal('css', 'xfa_blogs_nav');

I hope the template_create hook is not going away, since that is what I use to preload css, and that definitely cannot be done with a replacement



I think the system will work, and it is definitely a great idea. It will mean some rework for us to move from the hooks to the replacements or replacements+view, but that is fine. I appreciate that the hooks are not immediately removed.

I thought I was doing more complicated things, I guess I haven't needed to. And I just realized that on the worst case scenario I could just instantiate my own template on the view and add that as a template parameter. I hope I don't need to use such drastic measures.

I was not personally using TMS but I have helped some setups that have it. It is really powerful and convenient. Integrating that into the core makes sense since that way there are no page load time memory issues.
<xen syntax has been confirmed to be able to used in a PC. So yes, you should be able to use <xen:include>
 
I haven't used the existing add-on TMS, only heard about it and thought I might give it a try in a few weeks... Now TM is going to the core, and that's great news!

I have a few questions- which might be very silly- regarding this new feature, please bear with me and forgive my english too:

1. If I modify a template and let it automatically apply the changes, where did the changes go? Can I know the name of the file(s) containing the changes or the file containing the complete new version of this template?

2. What does "Manually Apply Modifications" mean exactly? If you do the manual apply, does it mean it will overwrite the originally template file, and you have no way to revert to the original?

3. When editing a template and if you've saved multiple times, if you click the "Revert Template..." button, which version of template it will bring to you - the very last saved version or the original version from the install?

4. If I did some modifications to the templates via this TM on our testing site, and when it is time to apply these exact same changes to our production site, how should I go about it?


Many thanks!


Can Mike answer these basic questions? Thanks!
 
I'll just leave this here...

View attachment 44290
You're going to hate me but I really try to understand why the callback can't be more general: why can't we have the full template text then proceed search/replace directly in the callback. Did you implement something which requires to create an entry for each replacements?

Here's a truncated example of one of my callback with TMS:
PHP:
    public static function editor(&$templateText, &$applyCount, $styleId)
    {
        //Load bbcode message
        $search[] = '#<textarea name="{\$formCtrlNameHtml}".*?</textarea>#si';
        $replace[] =    '<xen:if is="{$visitor.miu_rte_reverse}">
                    <textarea name="{$formCtrlNameHtml}" id="{$editorId}_html" class="textCtrl MessageEditor MiuRevert" style="display:none; {xen:if $height, \'height: {$height};\'}">{$messageHtml}</textarea>    
                    <textarea id="{$editorId}_miu" rows="5" class="textCtrl MessageEditor MiuRevert MiuTarget" name="message" style="overflow: hidden;">{$message}</textarea>
                <xen:else />
                    $0
                </xen:if>';
        
        //MarkItUp Tools (ie: color picker)
        $search[] = '#</xen:hook>#ui';
        $replace[] = "$0\n<xen:include template=\"MarkitUpIntegrator_Tools\" />";

        $templateText = preg_replace($search, $replace, $templateText, -1, $count);
        $applyCount = $count;    
    }
 
You're going to hate me but I really try to understand why the callback can't be more general: why can't we have the full template text then proceed search/replace directly in the callback. Did you implement something which requires to create an entry for each replacements?
You can do that...? The screenshot actually shows the entire template being matched by the regex. You can then manipulate it as you wish. This is done via preg_replace_callback().

Here's a truncated example of one of my callback with TMS:
This doesn't show any benefits of using a callback except that you have it in one modification.
 
This doesn't show any benefits of using a callback except that you have it in one modification.
That was the idea

Edit - I complete the idea:
It's sometimes just easier to code directly in php than to create every time a listener or a replacement. You've got one big callback that you open in your editor and it's fast to modify.
 
1. If I modify a template and let it automatically apply the changes, where did the changes go? Can I know the name of the file(s) containing the changes or the file containing the complete new version of this template?
I don't understand what you're asking here. The changes will be applied to your template. Templates aren't files in XF. You can see how the changes are being applied via the ACP (the "view template modifications" link).

2. What does "Manually Apply Modifications" mean exactly? If you do the manual apply, does it mean it will overwrite the originally template file, and you have no way to revert to the original?
It directly writes the modifications into the template so you can manipulate them if you prefer.

3. When editing a template and if you've saved multiple times, if you click the "Revert Template..." button, which version of template it will bring to you - the very last saved version or the original version from the install?
This hasn't changed from how it works in 1.1. It deletes your version of the template and uses the appropriate version based on hierarchy.

4. If I did some modifications to the templates via this TM on our testing site, and when it is time to apply these exact same changes to our production site, how should I go about it?
You'd have to recreate them (currently) unless they're attached to an add-on, which could then be exported.
 
This is great step forward which will increase the number of addons and the possibilities. Thanks!!!
I hope that we will also see an API for XenForo to increase integration possibilties. I would love to create full integrations for an array of software.
 
This is a great addition to the core. I dont know how this will work or how the xenforo tms addon works, so I am stumbling in the dark right now. The only TMS I played with over so many years was Andreas' TMS he wrote for the vB dev community. One of its little disadvantages is/was that it don't work with unmodified templates in custom styles because they only exist as reference of their parent template. I hope this new feature works different. :-)
 
I don't understand what you're asking here. The changes will be applied to your template. Templates aren't files in XF. You can see how the changes are being applied via the ACP (the "view template modifications" link).

Isn't each template having a file or a set of files(HTML and CSS) associated with it? That is what I meant.

since you said:
"Applying a template modification does not actually modify the template, so it will not show up as customized and it will be automatically reapplied (if possible) when upgrading."
So I was asking where the changes(the template modification) go? Basically, I'd like to know if they are stored in any accessible files?

This hasn't changed from how it works in 1.1. It deletes your version of the template and uses the appropriate version based on hierarchy.

I've only had a couple of months forum licensing experience, not familiar with all 1.1 features yet. So, I'd like to know if this meant: When editing a template and if you've saved multiple times, if you click the "Revert Template..." button, the very last saved version will be brought back? Can you please correct me if I understand it wrong?

You'd have to recreate them (currently) unless they're attached to an add-on, which could then be exported.

I think this answer probably related to the first question...
Really wish the TM would allow exporting modified templates, otherwise it feels very incomplete for the feature.
 
Top Bottom