Is it possible to make visible to the theme in what order the different theme layers are called? Beyond html/body its a bit bewildering what gets called next..for example in Display template: its visible - sort of - what comes next by looking at the actual output in the page, but it would be nice to know exactly what comes next.
The problem for me is that I want to collect several smaller subtemplates into a overall markup tag for special layout purposes. Right now it is a bit hit and miss without knowing this structure(and indeed if any mods add to it later on).
I see $context has some stuff listed..but it does not appear to list the subtemplates in the correct order...
Look at the Template Layers class and the output of getLayers. I think that contains what you are looking for.
Also here; https://github.com/elkarte/Elkarte/blob/f358500749637aeff933dfffc00e0b71139c3ed2/sources/subs/TemplateLayers.class.php#L119
This https://github.com/elkarte/Elkarte/wiki/Template-layers may also help .. but please note that has not been updated that for 1.1, you know how documentation goes, so there will be some inconsistencies. Perhaps @emanuele
will provide a few more details as well.
Great! :) I see the class can list the layers in the public getLayers() function. Only have to find out what the variable which use this class is called..and if its possible to reach it from the theme.
Ok, still confused..as I see $context gets all the info I need (I think) but again, the ordering is strange:
[layers:protected] => Template_Layers Object
[_error_safe_layers:Template_Layers:private] => Array
 => html
 => body
[_all_general:protected] => Array
[quickreply] => 0
[pages_and_buttons] => 100
[_all_after:protected] => Array
[_all_before:protected] => Array
[_all_end:protected] => Array
[messages_informations] => 10000
[_all_begin:protected] => Array
[html] => -10000
[body] => -9900
[_general_highest_priority:protected] => 200
[_end_highest_priority:protected] => 10100
[_begin_highest_priority:protected] => -9800
[_sorted_entities:protected] => Array
 => html
 => body
 => quickreply
 => pages_and_buttons
 => messages_informations
Here quick-reply is listed BEFORE pages_buttons and messages_information, which all correspond to the subtemplates named the same..but its not how its presented on the page(only markup, no css shown). So how does the script go from that to whats showing?
That’s handled in the Theme file.
Although I think that Elkarte is moving away from the $context global variable. So it might not be that useful to rely on that going forward.
What is it you’re trying to do?
Really simple really..I want to add the numerous subtemplates like pages/quickreply/modbuttons etc. into a dedicated sidebar. So I need to know where to put the start of the container tag - and the end tag. Right now I am not sure where things begin and end...
I can already do this with just CSS - that is, put all those in a grid so it goes on the right. The trouble begins once I want to target all those as one item, for example to make it stop scrolling once they reach the top ..or just make it a sidebar that can fly out when called(mainly for phones). Currently i can't do this just with minor changes in markup + CSS.
You can reorder the items sorted entities by changing their priority.
Then insert your template to add the required start container tag and then another template to add your end container tag.
That's probably the best way to implement it.
If you know what the templates are called anyway.
Ok, thanks. For now I think I just leave it be, pending a deeper look into how the theme system works. :D
the layers are sorted only just before being used.
You can forcefully sort them with:
$layers = Template_Layers::getInstance()->prepareContext();
Though you may want to do it as late as possible before the output, just to avoid missing something.
That said, probably you don't even need to sort them, I mean, you could just hook up somewhere before template_header being called (I guess call_integration_buffer is as good as any other), get all the layers defined up until that moment, filter those you want to move somewhere else, remove them, add your sidebar and render the layers in the sidebar.
$interested_in_layers = ['quickreply', 'pages', 'moderation', 'etc.'];
$existing_layers = ;
$layer_obj = Template_Layers::getInstance();
foreach ($layer_obj->getLayers() as $layer)
if (in_array($layer, $interested_in_layers))
$existing_layers = $layer;
echo '<your sidebar markup>';
// Sort to whatever order you want them to be
foreach ($existing_layers as $layer)
loadSubTemplate($layer . '_above', 'ignore');
// Reverse the sorting
foreach ($existing_layers as $layer)
loadSubTemplate($layer . '_below', 'ignore');
echo '</your sidebar markup>';
I can't guarantee it works (even more because I just wrote it here without any kind of validation nor testing, so...), but that should be the general idea.
Thanks , I will test this out. :)
I am trying to 1) avoid rewriting the whole template and 2) avoiding having to target all those subtemplates with CSS..which I already do, but some things are just not possible without collecting them somehow.
One other aspect is that I might be able to do this with other templates too, anywhere where stuff should go in that custom sidebar, without rewriting them too. At least for this theme anyway.
I have to note one small issue in script.js: the "jump_to" code there have a single inserted. I could not figure where it was coming from since the inline js seems to disregard me removing it from there. It would seem it just took it from script.js regardless..so I had to copy over the entire script.js to my theme just to change it(..). Why is it there? Well, I guess to add some natural distance to the submit button..but it really hinders anyone wanting to control that distance by CSS. Particulary if you want a vertical placement of the input/select/submit and don't want that distance there. It also affects using display: grid and grid-template-areas , as its regarded as a single item by the grid ..but possible to style since its not a markup tag(...)
But, as said, a small issue. :) I might just leave it out anyway, depends if I find other stuff in script.js that I need to change.
That's worth a bug report. ;)
I checked and there are a total of (9)   in the JS files in of course (9) different files.
I have to be honest, injecting an occasional   is one of my favorite tricks to fix things O:-)
I'll log this to fix (remove) what we can in 2.0, thanks for reporting.
Great :) You can of course use those still..but it would be better to use spans around them - or better yet, JUST use a span with a "breaking space" dedicated class. :D
New question..is there a way to add a hook only to be executed when a theme is run? That is, not permanently added.
I'd like to try adding the sidebar code but am a bit lost as to how the theme would be able to integrate with hooks. I don't want to make a mod for this either.
I've seen from the source code that adding Theme.php inside the custom theme apparantly makes Elkarte use that..and that seems to be interesting as a way to customize the theme engine(possibly), but it still calls the Templatelayers.class which seems not be fecthed from anywhere else that Sources anyway.
I am kind of deterred by the fact the subtemplates is not so easily managed by the theme in Elkarte. I mean, I see the reasons for it, but it does limit what a theme could do. You are kind of stuck with the order they are presented in. But I acknowledge that there is probably not a high demand for it ...other than for myself :) ..so I guess its a non-priority. I'll keep tugging at it until I find a work-around because I think Elkarte is by far the better of all forked SMF scripts, including SMF(2.1) itself.
You can probably use the integrate_theme hook and check there to see if the theme matches the one you want then add a temporary hook via the add_integration_hook function.
If you think about it, the moment you have access to swap the parent object, you are basically in control of anything that happens inside of it, so you can just replace the theme class with one of your own and instantiate a Templates class of your choice picked from wherever you want.
TBH I'm kind of confused here.
If you read the code I presented you above, you have all the answers you need already: you can get the list of layers/subtemplates, you can remove them, you can add them. Do you need anything else?
When adding, you have all the options and flexibility of the Priority class, so you can add (at the) "beginning", (at the) "end", after or before another one, you can specify a level of priority (not if after/before, of course), etc.
You can do anything you want and be way less concerned by side-effects than you are with a simple array. shrugs
Worst case, you can even remove everything and insert only whatever you want, basically killing any addon that would be brave enough to provide an interface for adding some content, just because you want your theme to be the only ruler of the game.
If this is not freedom I'm not sure what it is.
Well, thank you for providing a way with adding this to layers - I am not ungrateful for that. I am however, confused as to how to do it..after all, I am not at the coding level you guys are. :(
But to adress one of your arguments: I am not at all trying to take control over everything in the theme, including any brave addon's attemtps at providing an interface. I just want to be able to at least be aware over whats coming so the theme can take steps to theme that in any way possible. I find it fun to experiment with designs and thats why I asked for guidance to be able to do that.
But I am less interested nowadays to fight for this.... so I'll just acknowledge its hard to do in Elkarte and move on.
I think what @emanuele
is saying is that’s it’s the opposite of hard, it’s actually quite easy. You have an template layers object which you can query and manipulate how ever you see fit. It’s not an array, but that makes it more powerful and useful as you can easily inject or remove segments without needing to rebuild your array.
I’m struggling to see where you’re not understanding so it’s hard to explain, but the current implementation (imo) is very powerful and will allow you to do anything you want.
I make sure I ask in here if I am confused of anything in theming or coding addon as I am also more to a not so advanced user of Elkarte.
So far it is really easy to theme or code with Elkarte, once you understand it of course, if compared to its predecessor.
If I were as good as you @Bloc
, I may even make plenty of wonderful themes with Elkarte.
As for age, yeah, I am also feeling old as well, and FYI I just ceased practising as an advocate and solicitor in Malaysia after 20 years.
So I know what you mean by no more figthing, but that doesn't mean I cannot change, learn or adapt.
I am now a director of my own IT Services private limited company, or so to say, I also changed, learned and adapted.
The only similarities between the two services and the businesses, I used logic and common sense to make them work for me.
So good luck in whatever you choose to endeavour @Bloc
Ahrasis, learning new things is not the problem for me..
Using the word "fight" is probably not best word to use here, its nothing to be upset about - I, and probably most people here, do this in our leisure time and in that case choose actively to learn and use it(Elkarte or SMF scripts that is).
Yeah, it may be indeed easy to accomplish this(relatively speaking). But if the functionality of being able to change layer positions from the theme - or even just see the layer positions and subseqently the subtemplate ordering - is not there in a straight-forward way its clearly not something themes are meant to do in the first place.
For me it means an obstacle that will prevent me from creating a theme the way I envision it, that is all.
, I don’t see how it’s not there in an easy to see way. You take the object and read the data back, if you want you can turn that into an array locally manipulate that how you want it then write it back to the object. It’s all contained within one ‘item’ which can be used how you see fit.
, emanuele gave me a code example that means using a hook, preferably the integrate_buffer hook. Well, to be painfully aware of my own limitations: how the heck do I do that from the theme? template_init function? Tried that, did not work.
Its probably not hard to do this from any source file, but I 'd like to do it from the theme itself - so to not 1) turning the theme into a addon/mod 2) keep theme separated (although arguably I don't by doing it this way anyway) from Sources code and files.
As mentioned before, my intention is not to make the theme "the ruler of all".(but I can see that may be what you think, based on my objections towards themes before, mostly in SMF. Though again, there too, I never meant themes should tell Sources what to do, rather have a little more freedom in deciding what goes where. Not what goes *nowhere*..) Being able to make choices on the layout that cannot be done through CSS alone gives that freedom.
I don’t think you want to theme to be ruler of all, I can largely grasp what you’re trying to do.
I’ve not done any theme development work really other than playing with css and changing the layers and pointing them to my own layer instead. So it’s slightly different.
Can you send me what you have so far? Or even a small template of what you’re trying to achieve. I’ll have a play and see if I can get it working.
If I add this
add_integration_function('integrate_buffer' , 'TestHook', __FILE__, false);
To template_init in the index.template.php function it appears in my hook list and get's executed as I would expect. Although that hook is probably a bit late for you to do anything with the template order.
You mentioned integrate_theme hook earlier...will that execute early enough to inject a new layer(or sidebar code as emanuele suggested)? I am not at home atm, but will test more once I get there. Thanks! :)
Honestly I don’t know, that’s where I have to hand over to @Spuds
You really want the one just before the templates are called and rendered. It does appear you can add them from a theme only though, which is good.
Will the custom theme index.template be loaded when the hook is executed I wonder...or can you add a path to index.template.php within the add_integration_function call? I am thinking to add the hook code there.
The template_init seems to be run quite early in the execution path. So you’d want to aim for just before the _above template is called, I’d think.
The FILE points to the current file btw, so in this instance it's the file I edited index.template.php.
The hook code itself is a function I assume - but I get a blank page when just adding it. If the function does not exist, all is fine..
So the hook code/function must perhaps do something or return something specific? (I am so out of tune on hook code lol)
The hook I used?
It’s in the buffer so it takes the buffer as an argument and manipulates the rendered page data then returns that.
It’s not the one you’d want to use I think as everything is rendered by that point. You could check it in the html_above function and switch things around in that section I’d guess without the need for a hook.
Honestly, I couldn’t tell you what is the best one, I’d be looking at the one just before the _above templates were called.
Yeah, I tried using that integrate_buffer hook but emanuele's code doesn't take it seems. Perhaps it happens before that.
Oh well, putting this aspect on the backburner for now, its plenty to work on elsewhere in the theme.
No promises but If I get to see the theme I'll see if there is a way to use the layers to juggle things around. I've used them before to inject things in the profile page so I know you can do some cool things with them but TBH I have a lot to learn about their use in situ (so to speak) Sometimes there can be a disconnect in capabilities programmed in vs how the folks you need those capabilities would use them. Hope that makes sense LOL