I was calling path_to_theme within block--system--main.tpl.php and it gave me the path to the root of the Garland theme.

I was sub-theming garland, but garland was not the 'active theme' as the documentation claims that path_to_theme should return.

Contributor tasks needed
Task Novice task? Contributor instructions Complete?
Reroll the patch if it no longer applies. Instructions
Update the issue summary Instructions
Files: 
CommentFileSizeAuthor
#31 interdiff-1026156-29-31.txt1.38 KBpixelmord
#31 Drupal-document_path_to_theme-1026156-31.patch1.53 KBpixelmord
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 66,849 pass(es). View
#29 Drupal-document_path_to_theme-1026156-29.patch1.62 KBpixelmord
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 66,910 pass(es). View
#22 core-update-documentation-1026156-22.patch2.34 KBsidharthap
PASSED: [[SimpleTest]]: [MySQL] 64,314 pass(es). View
#14 core-update-documentation-1026156-10.patch2.34 KBjameswoods
FAILED: [[SimpleTest]]: [MySQL] Repository checkout: failed to checkout from [git://git.drupal.org/project/drupal.git]. View
#1 1026156.patch2.43 KBjhodgdon
PASSED: [[SimpleTest]]: [MySQL] 31,488 pass(es). View

Comments

jhodgdon’s picture

Title: Documentation problem with path_to_theme » path_to_theme() isn't clear about which path it returns
Status: Active » Needs review
FileSize
2.43 KB
PASSED: [[SimpleTest]]: [MySQL] 31,488 pass(es). View

Yeah, the documentation isn't clear. The reason you are seeing that is that this function returns a path to a *function* only, not a path to a *template*. If the theme() call results in a call to a function like mytheme_hookname(), then it will be the path to the theme that defines that function. But if it results in a hookname.tpl.php, then it will be the path to the mytheme_hookname_preprocess() or mytheme_hookname_process() function, with precidence given to the process() function location.

The documentation needs a fix... and the function is a bit odd anyway, but that is what it does.

Here's a patch for the documentation. It should be ported to D6 if accepted, since it works the same and is equally badly documented there.

drewish’s picture

That seems like a good improvement but the capitalization in the HOOK and THEME names isn't totally obvious.

jhodgdon’s picture

Status: Needs review » Needs work

OK, let's get a new patch then.

ts145nera’s picture

I've the same problem.
I'm developing a zen subtheme.
When I call "path_to_theme" in front page it's work fine, but when I call it in region-sidebar_second it return path to zen theme.

ts145nera’s picture

Same problem in region--header and region--footer templates file

ts145nera’s picture

Version: 7.x-dev » 7.0
jhodgdon’s picture

Version: 7.0 » 8.x-dev
Issue tags: +needs backport to D7

Actually, this issue now needs to be in version 8.x-dev. We fix issues in the latest version, then backport to previous versions of Drupal.

Still needs a new patch.

jhodgdon’s picture

wrong tag

ts145nera’s picture

What's the issue in D8?

jhodgdon’s picture

The 8.x issue is exactly the same as the 7.x issue, since the 8.x doc is currently exactly the same as the 7.x doc.

droplet’s picture

I think 99% of Drupaler expected it returns a PATH OF CURRENT THEME. Only 1%, the CORE developer knows it isn't.

I would suggest to make it what 99% drupaler expected or rename it or give a real solution there.

jhodgdon’s picture

If you want to change the function or the function name, that would be a different issue -- please feel free to file an issue to request this. This issue here is about updating the documentation so that it matches the function.

jameswoods’s picture

Assigned: Unassigned » jameswoods

I'm going to be applying jhodgdon's updated documentation text per comment #10

jameswoods’s picture

Status: Needs work » Needs review
FileSize
2.34 KB
FAILED: [[SimpleTest]]: [MySQL] Repository checkout: failed to checkout from [git://git.drupal.org/project/drupal.git]. View

Here's a patch using jhodgdon's wording.

jameswoods’s picture

Assigned: jameswoods » Unassigned
jhodgdon’s picture

precidence is misspelled, oops!

Anyway, since I wrote the original patch here, someone else needs to review it for accuracy and clarity.

Status: Needs review » Needs work
Issue tags: -needs backport to D7

The last submitted patch, core-update-documentation-1026156-10.patch, failed testing.

jameswoods’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, core-update-documentation-1026156-10.patch, failed testing.

superspring’s picture

Issue summary: View changes
Issue tags: +Novice
sidharthap’s picture

Status: Needs work » Needs review
FileSize
2.34 KB
PASSED: [[SimpleTest]]: [MySQL] 64,314 pass(es). View

patch re rolled from #14 with spelling correction.

jhodgdon’s picture

Issue tags: +Twig

Thanks for the reroll and spelling fix!

Looking at this patch today as opposed to years ago when the original patch was written, I don't think this documentation is very accurate for the current Drupal 8. For one thing, the theme() function itself is rarely called now and may have already been eliminated... It does look accurate for 7. Maybe we can get someone in the Twig group to review this for 8?

jhodgdon’s picture

Status: Needs review » Needs work

The theme() function no longer exists, so this documentation is definitely not OK now for 8.x.

Cottser’s picture

Thanks for tagging this @jhodgdon!

+++ b/core/includes/theme.inc
@@ -755,14 +755,33 @@ function theme($hook, $variables = array()) {
+ * In calls to theme() that result in a template file being used, the "theming
+ * function" is the process or preprocess function that is called to set up the
+ * variables (with precedence given to the process function, if one exists). So,
+ * the "theming function" could be the template_process_HOOK() reference
+ * implementation from a module, a THEME_process_HOOK() override from a base
+ * theme or the active theme, etc. Note that the "theming function" may not be
+ * part of the same theme that contains the template file being used for
+ * theming in this case.

Also process functions no longer exist in D8.

This might need a bit of a rewrite because _theme() is now for internal use only. Not to say that we can't use it in documentation but important to note.

jhodgdon’s picture

Yeah, we should never talk about calling _theme() and theme() does not exist in D8 now. So we probably need to add something like "... During rendering, elements in the render array tree are eventually passed to the internal _theme() function, which decides which theme function or template to use to render the element. ..." to the documentation?

Anyway, let's step back and see what this function would actually return.

Looking at the code, it is basically just returning the value of the global variable $theme_path. Grepping in core, ... it looks like $theme_path is set up initially in drupal_theme_initialize() to be the path to the active theme. And then in _theme(), it is set to

  $info = $theme_registry->get($hook);
  $theme_path = $info['theme path'];

and then it is set back to whatever it was at the end of _theme(), just before it returns the themed output.

Looking at how the theme registry is built, the 'theme_path' element of the info arrays is set to:
- drupal_get_path('module', $module) if the theme hook is registered in a module's hook_theme() implementation
- dirname($base->filename) if the theme hook is registered in a base theme's hook_theme() implementation or its theme engine's hook_theme() implementation.
- dirname($theme->filename) if the theme hook is registered in the active theme's hook_theme() implementation or its theme engine's hook_theme() implementation.

After that, _theme() invokes hook_theme_suggestions*, calls the preprocess functions, and then either calls the theme function, or renders with Twig. So, during all of those steps, path_to_theme() is going to have the value of $theme_registry->get($hook).

So. It looks like path_to_theme() in D8 is always going to be set to the directory of the module or the theme that registers the theme hook with hook_theme(), if you're inside a call to _theme(), and it will be set to the directory of the active theme if you're not.

That seems like what we should document for 8. 7.x I think works differently.

Cottser’s picture

Issue tags: +documentation

I know the documentation tag is redundant but I'm just adding it so that this issue shows up on http://drupaltwig.org/issues/documentation which I just set up, hope that doesn't mess anyone up.

pixelmord’s picture

Assigned: Unassigned » pixelmord
Issue tags: +sprint

I will see to do the needed updates mentioned in #26

pixelmord’s picture

Status: Needs work » Needs review
FileSize
1.62 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 66,910 pass(es). View

Attached there is a patch for an updated doc

jhodgdon’s picture

Status: Needs review » Needs work

Thanks! This is pretty good!

A few things to fix:

a) We still need a one-line, <= 80 character description for the first line of the doc block.

b) I think the first sentence could use some commas or needs to be split into multiple sentences. It is very long as it is and a bit hard to follow.

c) HOOK_theme() should be hook_theme().

d)

+ * template to use to render the element. In this context the return value of
+ * path_to_theme() will be the directory path of the theme or module, that
+ * exposed the information about the particular theme hook to be used for
+ * rendering via HOOK_theme(). This information will be retrieved by the
+ * _theme() function from the theme registry.

- Add comma after "context" in the first line.
- No comma before "that" in the second line.

e) But actually... this whole second paragraph seems redundant to the first paragraph. Do we need it at all?

pixelmord’s picture

Status: Needs work » Needs review
FileSize
1.53 KB
PASSED: [[SimpleTest]]: [PHP 5.4 MySQL] 66,849 pass(es). View
1.38 KB

Here is an updated patch with shorter sentences and the recommended comma changes and a hopefully better last paragraph

jhodgdon’s picture

Status: Needs review » Needs work

OK... but:

+ * The path points either to the current active theme or during a rendering
+ * process the path points to the theme or module that registered the theme
+ * function or template by implementing hook_theme().
+ *
+ * During rendering, elements in the render array tree are eventually passed to
+ * the internal _theme() function, which decides which theme function or
+ * template to use. In this context, the return value of path_to_theme() will be
+ * the directory path of the theme or module that did register this particular
+ * theme hook.

I do not think we need this second paragraph at all?

Anyway... Gosh this issue is bothering me... My read of the code in #26 can't be right. In D7, path_to_theme() would return the path to the module/theme that was actually providing the override of the theme hook, not the module/theme that declared it with hook_theme(). I wonder if this really changed in D8? I probably missed something when I looked at the code for building the theme registry.

Let's see.

_theme() is using the theme registry returned from this function:
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Theme!Registry.ph...

It is built in this function:
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Theme!Registry.ph...
which calls
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Theme!Registry.ph...
to do the work if it's not already built/cached, which calls
https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Theme!Registry.ph...
for each module/theme/engine implementation of hook_theme().

So... looking at tihs last function again, for what $info['theme path'] is set to (that is what path_to_theme() returns):
- Initially in the top loop, it is set to the path to the module/theme that implemented hook_theme().
- Then there is another loop at the bottom, which I missed when I looked earlier. This is really crazy. What it does is at the time that the particular theme/module that implemented hook_theme() is being evaluated, it goes through the current cache of theme hooks, and checks to see if there is a function called $name . "_preprocess_" . $hook (where $name is the module/theme name), and if there is, it sets the theme path for that hook to the path to $name (module or theme).

Wow that is really... interesting.

So:
- If path_to_theme() is called outside of theme rendering, it returns the path to the current theme.
- If path_to_theme() is called within rendering, it returns either:
a) The path to the module, theme, or engine that declared the theme hook in its hook_theme() implementation.
b) The path to the last module, theme, or engine detected during the build of the theme registry that declared a preprocess function for the hook. The order of detection is: modules (in order returned by getImplementations(), and only modules that implement hook_theme() are even checked), base themes (for each, processing their engine and then the base theme), engines, and the current theme. And then modules can alter this with hook_theme_registry_alter().

How is this function even useful in any way?

I also noticed that the docs at the top of core/lib/Drupal/Core/Theme/Registry.php that talk about path_to_theme() are mis-formatted. Something got deleted there.

Sigh. Sorry about the misdirection in #26. I guess we need to put all of this information into the documentation in some way, highlighting how really totally stupid and useless this function is.

pixelmord’s picture

oh I overlooked that during debugging.

I would just say that the important information is:
* that the return value is a path to a theme or module that provides theme hooks or preprocessing.
* The value is determined by looking into the theme registry.
* During run time of _theme() the value will change because more than one module or theme can be involved in the rendering process @see preprocess.

Does that make sense to you?

jhodgdon’s picture

Priority: Minor » Normal

RE #33, not only that, but a lot of the time, theming is nested, so it is always relative to the inner-most theming operation in progress.

I don't think we need to mention the theme registry at all in the function docs. That is not (in my opinion) relevant to people who are calling the function.

I am also not sure what you mean in #33 by "During run time of _theme() the value will change because more than one module or theme can be involved in the rendering process @see preprocess." ? For a given call to _theme(), you are just going to have the one module/theme that has been designated as the "path" for that particular theme hook. The value of path_to_theme() will only change if there is another nested call to _theme() triggered. Right?

c4rl’s picture

How is this function even useful in any way?

Exactly.

This function is called sparingly in core. Once to set a $vars['directory'] and once in \Drupal\system\Form\ThemeSettingsForm.

Seems to me that the end-user functionality (and perhaps all functionality) can be easily accomplished via drupal_get_path('theme', $name_of_theme).

How do people feel about getting rid of path_to_theme() in favor of drupal_get_path() ?

iMiksu’s picture

Assigned: pixelmord » iMiksu
Issue tags: +drupalcampfi
iMiksu’s picture

Assigned: iMiksu » Unassigned

I'm having troubles running tests, so I won't be working on this anymore :/

jackbravo’s picture

Issue summary: View changes
Issue tags: +Needs issue summary update, +Needs reroll

As a mentor, preparing for the sprint on Friday on the DrupalCon.

jhodgdon’s picture

Issue tags: -Novice, -Needs reroll

I am not sure at all that this is a good Novice issue, since we really need to decide whether this function is even useful, which is not really a good decision for a novice contributor.

sun’s picture

To some extent, path_to_theme() isn't clear about what it returns, because it's buggy + returns bogus paths in various situations. It returns the path to the theme in some cases, or the path to the directory containing the template file of a module in other cases.

The $directory variable in templates is more reliable. It returns the directory of the template.

For 100% reliability, always use drupal_get_path('theme', 'mytheme'). It is guaranteed to return the path to the theme.
(which happens to be the confusing name of the function in question)

path_to_theme() has been a constant pain for themers for more than a decade already, we never really fixed it.

/me actually hoped that path_to_theme() would simply die and vanish in D8...

jhodgdon’s picture

> /me actually hoped that path_to_theme() would simply die and vanish in D8...

Me too! Can't we just get rid of it?

iMiksu’s picture

Issue tags: -drupalcampfi

Cleaning up drupalcampfi tags.

jhodgdon’s picture

Version: 8.0.x-dev » 7.x-dev
Issue tags: -needs backport to D7, -Twig, -documentation, -sprint

Well, my wish happened: there is no path_to_theme() in Drupal 8 now. Moving this to 7.