theme_flag_link() is currently a stumbling block for themers, and also for me, because it contains a tangle of PHP code.
This patch (for both D5 and D6) solves this problem by rewriting it in a "template" style.
An added (and intended) bonus: The distance from here to using a real template file (for both D5 and D6) is very very short. A future patch (and a handbook page) will handle this as well.
This patch carries the new CSS class names from #280273: Enhance our HTML/CSS. If it gets accepted, I'll right away start a new handbook page describing them all.
IMPORTANT:
Don't bother looking at the patch: it's hard to learn anything from this diff. Instead look at the pastebins:
Perhaps at first glance the difference between the two isn't striking, but this new version is, IMHO, more maintainable.
| Comment | File | Size | Author |
|---|---|---|---|
| #12 | new_theming_d5.diff | 11.07 KB | mooffie |
| #12 | README.txt | 1.59 KB | mooffie |
| #12 | flag.tpl.php | 1.53 KB | mooffie |
| #11 | new_theming_d6.diff | 10.67 KB | mooffie |
| #5 | new_theming.diff | 8.7 KB | mooffie |
Comments
Comment #1
mooffie commented(I should do some benchmarking: see if include()ing a file is much slower than having the markup in the source. If it isn't much slower, we could use a template outright.)
Comment #2
mooffie commentedI have the benchmark results ready. I'll publish them soon. I benchmarked against our current code too.
Comment #3
mooffie commentedHere are the results.
The bottom line: using an external template file will make our code about 4% slower than it is today.
DETAILS:
I benchmarked three versions of the theming function (theme_flag_link):
"current": our current code.
"insource": markup embedded in the source, as in the patch above.
"template": the markup is moved to a template file and then include()'ed, similar to what D6 does.
I benchmarked using this code, and here are the results:
Most surprisingly, the "insource" is 11% faster than the current, pure PHP version. I have no explanation for this. I've heard PHP's string operators suck, but surely not to this extent.
The "template" version is ~23% slower than the non-template one ("insource"), but it's only 10% slower than our current code.
HOWEVER, benchmarking the template function directly doesn't accurately reflect how our overall code will be affected, because our code does more things besides outputting the link. So I benchmarked flag_create_link() as well, assuming it gives an indication for the overall effect:
The differences among the three become smaller because the theming function has smaller part in the overall process.
The bottom line: using an external template file will make our code slower, but, negligibly slower: it's only 4% of *our* code, and a much, much, much, much smaller fraction of the overall *page* rendering time. And, of course, an external template has significant advantages.
Comment #4
mooffie commentedI'll soon prepare a better patch: one that uses a template file. (There will be a D5 version too.)
I'll follow CCK and Views example and put it in a 'theme' sub-folder, together with a README.txt. The .css should eventually go there as well.
Comment #5
mooffie commentedHere's the patch for D6 (I'll work on the D5 one only after I get the ok. No sense in doing double and quadruple work).
Some changes:
(The theme registry must be cleared after applying the patch.)
Comment #6
mooffie commentedBTW, that patch makes using images for the links a piece of cake.
Say our flag name is 'favorites'. We drop a 'flag--favorites.tpl.php' in our theme folder, and edit it to have an {img src=...}. No need for CSS tricks.
Comment #7
mooffie commentedThis is a better title.
Comment #8
quicksketchI'm all for having a flag.tpl.php file, but I think including a version for D5 is a working outside the normal Drupal conventions. I'd much rather see the D5 version use the traditional theme system.
As for the D6 approach: the theme_flag_overall() seems clunky. Is there any way we can have a theme_flag_js() and call it from template_preprocess_flag() instead of calling theme_flag() from theme_flag_overall()?
Basically, I'd prefer that theme_flag() add the JS somehow, rather than adding a wrapper that adds the JS and then calls the theme_flag() function. There may be some difficulties surrounding the dynamic template files of D6 though, let me know if this isn't feasible.
Comment #9
mooffie commentedYes, that seems a good idea. I'll make it so.
I understand your concern, but the D5 version will use the traditional D5 system. I really want you to re-consider your stand on this. We won't need to re-educate themers.
The README.txt will include an optional phptemplate_flag() --to be copied into 'template.php'-- that instructs the theme engine to load the template file from the theme folder.[1]
This is a very conventional D5 theming.
You may reply:
"But the more common D5 theming is for the themer to copy a theme_flag() into phptemplate_flag() and change its PHP to her liking."
To this I will reply:
Themers aren't likely to use this "traditional" technique with our module. Our issue queue strongly suggests this; Modifying the PHP requires a themer to be PHP savvy. How many themers know of the 7th parameter to l()? Since most themers aren't such, they aren't going to use this technique; A thing which isn't used doesn't exist; Something which doesn't exists can't even be touted as "the traditional way".
And in fact templates are traditional in D5: they're used for nodes and blocks, and more. So it seems to me that we lose nothing by going the template way in D5.
I'm looking forward to hearing your thoughts on this.
[1] If this phptemplate_flag() isn't used, our original theme_flag() kicks in and directly include()s our official flag.tpl.php.
Comment #10
quicksketchThanks, I didn't read through your entire explanation. This is perfect. I used a similar approach for Webform's instructions for theming. I'm 100% behind the approach.
I'll mark this back down to "needs work" until you get a chance to do the JS changes. Once again, thanks for all your amazing help!
Comment #11
mooffie commentedHere's an improved patch for D6 that does what you asked for. I named the helper function _flag_add_js(), and it's called from template_preprocess_flag().
Notes:
1. 'diff' does a messy job of showing what's changed. If you really want to enjoy the beauty of my code, you'll have to apply the patch.
2. Instead of calling theme() directly, I'm now calling a theme() method on the flag object. I'm following here Views' pattern because otherwise I'll have to provide quite a lot of parameters directly to Drupal's theme().
3. I'm not attaching 'flag.tpl.php' and 'README.txt' again because I haven't changed something important in them.
I'll soon upload the D5 patch.
Comment #12
mooffie commentedAnd here's the patch for the Drupal 5 version.
(You'll notice the new theme() method, in flag.inc. This will be used for both D5 and D6 because I don't want to maintain two files.)
I'm attaching 'flag.tpl.php' for completeness sake: it's the same as that of the D6 version.
And the 'theme/README.txt' for D5 is of course differenet than that for D6. It contains the function to put in 'template.php'. I'd better move the body of that function to the module itself. First I wanted that you get an impression of it.
I'm marking both patches 'needs review'.
Comment #13
quicksketchGenerally looks pretty good. There's still a bit more cruft than I'm used to with D5/6 compatibility code in places, but I guess that's necessary when backporting things that are expected in Drupal 6. I wouldn't mind cutting out the documentation for theme_flag() out of the Drupal 6 version, maybe we could just include that all in a description flag_preprocess_flag()?
I like the new _flag_add_js(), but it should be called from a theme function rather than in a preprocess function (meaning it should probably be a public function also). While it totally pains me to put a function call in a .tpl.php file, it's necessary because users overriding the template file should be able to remove the JS file or add their own version. Once added to the page through drupal_add_js(), it's really hard to get back out again. The block-admin-display-form.tpl.php is an example of a tpl.php file doing this.
Comment #14
mooffie commentedI suggest to have the following in flag.tpl.php:
OK. I'll follow forum.module style: it just lists the input variables and directs the user to read the full documentation in the .tpl.php.
Comment #15
quicksketchEverything sounds great to me. :)
Keep in mind that anything we put in a .tpl.php file has to be the way we want to keep it. As users are likely to override it.
Comment #16
mooffie commentedSo, is this patch, for both D5 and D6, approved? :-)
(No point in me posting the patch again: the altering to flag.tpl.php, in #14, and the renaming of _flag_add_js, is pretty much all.)
Yes, I know. Note the README.txt of the D5 version, which contains a 'phptemplate_flag()' to be copied into template.php. The point you mention is the reason I want to move the body of that function to an API utility function (in the D5 branch only, of course). I see no reason not to do that. I haven't done that yet because I didn't want you to encounter many "new" things in this issue. I suggest we leave that to a subsequent refinement issue.
Comment #17
quicksketchSounds great. I hereby bless this patch. ;)
Comment #18
mooffie commentedCommitted.
Yeeeeeeeeha! :-D
I've opened a new issue for that:
#285669: Better phptemplate_flag() for D5
Comment #19
mooffie commentedI added a reminder to the homepage, "... you should clear your Drupal cache." It's needed because of the theme registry.
Comment #20
Anonymous (not verified) commentedAutomatically closed -- issue fixed for two weeks with no activity.