2

I have a functional understanding of what the hook system is and how to use it in Drupal, but would like to deepen my knowledge. Normally when writing a hook, I know exactly what hook I'm using, because I've looked up what hooks were available, chosen one that suits my need, and implemented it. Sometimes though, I have a situation where I look at the THEME HOOK provided by the debugging output in the HTML, and I write a hook for that, and maybe add a couple of specifiers. For example, if I see this debugging output:

<!-- THEME DEBUG -->
<!-- THEME HOOK: 'page' -->
<!-- FILE NAME SUGGESTIONS:
   x page--user--edit.html.twig
   * page--user--555.html.twig
   * page--user--%.html.twig
   * page--user.html.twig
   * page.html.twig
-->

I might implement a hook for page__user__edit. If I am in my theme called my_theme, I know I can go into my theme file my_theme.theme and implement the hook there, and that if I do I should begin the hook with my_theme_preprocess. So all together my hook should be my_theme_preprocess_page__user__edit, and I test it, and it works, and that part is all good.

Where my confusion comes in is when I go to specify parameters or document the function. What parameters does the function take? What hook does it implement? I am usually able to guess on the parameters, since usually it is (&$variables), but sometimes they are different. Ideally I would like to look up exactly what parameters the function takes based on the documentation for the hook, rather than trying to guess, but looking up the documentation for the hook can require some guesswork itself if you don't know what hook you are implementing. Some hooks are hook_preprocess_whatever, others are template_preprocess_whatever. Other times, like for a block, I wrote the hook my_theme_preprocess_block but it turns out this is not implementing hook_preprocess_block, it is implementing hook_preprocess_HOOK (or so I believe). So, once I have written a hook implementation (i.e. my_theme_preprocess_block or my_theme_preprocess_page__user__edit), how can I definitively know what hook I have just implemented?

Currently, I just Google a few different plausible-seeming hooks that I might be implementing, and if one of my guesses is correct or I get close enough that Google gives me a suggestion, I'm all set. In the case of the hook above, I'm able to find documentation for a template_preprocess_page function, and no such hook_preprocess_page function. Sometimes the results of this Googling process are less clear though, and leave me uncertain of what hook I have just implemented (like for the block - hook_preprocess_HOOK is very generic, how can I be sure I'm not implementing something more specific that I just missed in my Googling?). So if there does exist a way to definitively tell what hook you are implementing using a debugging tool or something, I would very much like to know about it.

I've tried using kint($variables) inside of my hook implementation (e.x.

function my_theme_preprocess_page__user__edit(&$variables) {
  kint($variables);
}

) but the closest thing I could find in there was theme_hook_original, which for the above gives 'page', so doesn't resolve these ambiguities about what hook I'm implementing.

Or, if there doesn't exist a way to tell what hook you are implementing with a debugging tool, is there a better way to figure out what hook I'm using other than what I'm doing? I'm open to suggestions on any level, including ways I should revise my workflow, something I should know about the difference between template_preprocess_whatever and hook_preprocess_whatever functions that if I knew that thing I wouldn't be confused, or whatever else. Thanks!

2

Where my confusion comes in is when I go to specify parameters or document the function. What parameters does the function take? What hook does it implement?

Preprocess hooks are only provided a single parameter: $variables. The hook that you're implementing is literally hook_preprocess_HOOK. The HOOK part of it is the identifier for the theme entry, as defined in a hook_theme() implementation somewhere.

So if you have this:

function MODULE_theme() {
  return [
    'foo' => [
      'variables' => [],
    ],
  ];
}

Then, by convention, you can implement hook_preprocess_hook like so:

/**
 * Implements hook_preprocess_HOOK() for foo templates
 */
function MODULE_preprocess_foo(&$variables) {
  // ...
}

Note the docblock; the convention is to use for XXX templates, where XXX is a description of the item being preprocessed. If you search for _implements hook_preprocess_ in the core folder, you'll find a lot of these as examples.

So, once I have written a hook implementation (i.e. my_theme_preprocess_block or my_theme_preprocess_page__user__edit), how can I definitively know what hook I have just implemented?

By definition, you already know :) You created the function with a certain name, so you know which theme entry you're preprocessing variables for.

like for the block - hook_preprocess_HOOK is very generic, how can I be sure I'm not implementing something more specific that I just missed in my Googling?

Because there can only ever be one theme entry for a given identifier, you won't run into this problem.

something I should know about the difference between template_preprocess_whatever and hook_preprocess_whatever functions that if I knew that thing I wouldn't be confused

Hopefully, along with the above, this will clear things up:

  • template_preprocess_HOOK is, again by convention, used by the module implementing the theme entry, to provide the base variables. It's always run first, before hook_preprocess_HOOK is invoked, so it helps those defining theme entries to ensure important variables and processing are done up front before the rest of the system gets involved.
  • hook_preprocess_HOOK is essentially for other modules to preprocess the variables, rather than for the module implementing the theme. There's nothing to stop that module from implementing hook_preprocess_HOOK as well (it's just a naming convention and no special checking is made), but it could be undesirable to do that if some initial processing needs to be done, a la template_preprocess_HOOK.
  • Thanks for this detailed and helpful answer! Looking in core I do see a lot of "implements hook_preprocess_HOOK() for xxx templates" comments. I think part of my confusion has been coming from the fact that in the project I'm working on all of the equivalent comments take the forms "implements hook_preprocess_xxx" instead. It also seems common in contrib modules. Is it accurate that docblocks like this one: ``` /** * Implements hook_preprocess_views_view(). */ function media_entity_browser_preprocess_views_view(&$variables) { // code... ``` – kenS Aug 31 at 1:28
  • Could be more correctly rewritten as "Implements hook_preprocess_HOOK() for views_view templates" then? – kenS Aug 31 at 1:29
  • Yes I think that sounds fair. I’ve seen plenty of examples like what you’re describing in contrib/custom land too – Clive Aug 31 at 13:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.