0

Its been quite a while since I worked on Drupal 7, but I'm hitting a snag.

First please understand I only have access to the theme, I cannot create a bunch of custom modules.

Now, I want to add a page, on the URL my.domain.com/authorization, this page should only be available for administrators and I want to provide some custom markup for the "innards" of the page.

since I know that my theme's template.php can use the hook_theme hook. I declare my route and template as so :

function mytheme_theme(){
    return array(
        'authorization' => array(
            'variables' => array('var' => null),
            'template' => 'my_authorization'
        )
    );
}

so, I can add my markup easily to my_authorization.tpl.php which exists.

however when I navigate to my URL I get a Page not found.

I figured I need to add a MENU_CALLBACK to the menu for my route, I understand I can not use hook_menu from a theme but I can use hook_menu_alter, so I write this function (which also takes care of my access issue) :

function mytheme_menu_alter(&$items){
    //die("mytheme_menu_alter");
    $items['authorization'] = array(
        'type' => MENU_DEFAULT_LOCAL_TASK,
        'title' => t('Authorization'),
        'page callback' => 'page_callback',
        'access callback' => true //'mytheme_auth_access',
    );
    return $items;
}

Problem here is that even if I uncomment the die and clear the cache it never hits this function! What have I done wrong?

you'll see I've added an access callback function but for testing I've just set to true (anyone can see it), you'll also see I've added it as a MENU_DEFAULT_LOCAL_TASK not a MENU_CALLBACK, again just for testing.

the page_callback function exists (returns a test string) but its never called, because the hook_menu_alter dfoesn't seem to be called from my theme.

Any assistance would be greatly received!

PS> I also read on t'internet that I need might need to implement hook_module_implements_alter which according to comments on drupal.org for a theme is implimented as hook_theme_registry_alter but I'm not sure what this is about (a single line reply comment, with no example or explanation!)

To be clear, my outcome is simply, for the theme I am working on (only), if the URL is my.domain.com/authorization, and the logged in user is an administrator, display a link on the page (to an oauth endpoint). Thats it.

Any advise please?

Edit 1

Thanks for all the responses guys, indeed I am familiar with the common case of hook_form_alter, I have in fact used it (specific and the general hook_form_alter) to disable comment previewing and fix some translation issues.

I have to admit you have confused me though @Clive when you say that "Clear all caches" does not clear all caches? I'm coming from the bad old days of Drupal 5 and I've never seem an issue of hook_alter's not being cleared or hooks in template.php not being refreshed when you "Clear all caches". Indeed inspecting the core code on menu.inc tells you when the hooks are called. I'd appriciate a link on drupal's site that explains what you mean though (there's always more to learn/understand).

Regardless, the only reason I want a custom page/route is because there is a JS API involved in the front theme (and only that theme) that requires an OAuth2 Authorisation to get an access token when the site is first placed/migrated on a server. Becasue it shows the Clients secret keys its not safe to serve it unprotected (as it is now) and it is literally only a link to the API Providers OAuth "This app requires access to X,Y,Z" page. Pretty simple really, strikes me as pretty stupid to need to create a stand alone module for this (especially if that module should only act on the custom theme, not globally).

Regardless, I shall just accept that hook_menu_alter does not work in a theme's template.php, as counter intuative as it seems (the theme is initialised, as I'm on front end pages and all my preprocess, form_alter and hook_theme functions are working).

I guess as my resolution I will take a different tack and either display the auth link under the "Sorry, this service is not available" message where the API is used, if the logged in user is an admin, or if the user is an admin add a global message with the link. I do have a "system is authorised" flag in my site variables so I can use that.

PS> I would love some links or official documentation on any of the topics @Clive or @googletorp have covered, i.e. when clearing caches doesn't clear caches, when menu_alter hooks arn't called when rebuilding the menu and when theme initialisation happens if as you say, it isn't initialised before the menu router is built?

PPS> @googletorp, what happens if I do actually google "torp"? LOL :D

  • 2
    Presumably you're clearing the cache from the admin section of the site? Unless you're using mytheme as your admin theme, the alter hook isn't going to be executed. You would need to clear the cache whilst on a page that uses your custom theme, but then obviously when the cache is cleared from a page where your custom theme isn't involved, the new route will be lost. Which should go some way to convincing you that it's a bad idea to try to add routes from the presentation layer. This code simply has to be in a module if you want the behaviour to be consistent and predictable – Clive Sep 26 '18 at 12:41
  • 1
    @Clive The hook will never invoked in a theme (to my knowledge) – googletorp Sep 26 '18 at 12:52
  • 1
    @googletorp It's invoked fine (all alter hooks are without exception, I just tested to be sure). Adding an item also works fine. Maintaining that item through menu rebuilds, though, is basically impossible. Or in-sensible at least – Clive Sep 26 '18 at 12:53
  • Thanks for the comments guys, see my edit above for detail. @Clive when would the menu be rebuilt except via Clear all Caches? – Blatant Sep 26 '18 at 15:20
2

Short version

What you are trying to do is not possible. The only way to create a menu callback is to use a module.

Longer version

Themes are called for alter hooks, but only after they have been initialized. The idea is that if you need to alter a small piece of markup, it's pretty stupid to have to make a module for this. This is how it worked in Drupal 6, but in Drupal 7 themes could be called for alter hooks.

There are some details attached to this. The alteration can only happen after a certain point in time in the code (the theme has to be initialized). This means that hook_menu_alter will never work in a theme since it will never be invoked when any theme is initialized.

The most common use case for alter hooks in themes is hook_form_alter where it's possible the change appearance of a form. So if you fx want to make a field required or not required a theme can change the appearance of the form (add/remove the little *). The actual requirements imposed the form wont change, since the form processing happens before the theme is initialized. This means that if you make a field not required in a theme via form_alter you will get field required validation errors if you don't input a value in that field. The * showing that the field is required will not be visible though.

  • 1
    This means that hook_menu_alter will never work in a theme since it will never be invoked when any theme is initialized. That's a bit inaccurate - if you clear the cache via the admin menu on a front-end page, for example, THEME_menu_alter is definitely invoked, and will allow you to add new items. But of course they won't persist when the router is rebuilt in another context where the theme isn't initialised – Clive Sep 26 '18 at 12:57
  • To clarify, the authorization page I want to create is specific to the theme, as is the JS APi being included, I would not imagine anyone would rebuild the router table on a different theme and I would not want the authorization page/hook to be in that context any way... – Blatant Sep 26 '18 at 15:22
  • @Clive You are wrong - give it a try ;) Theme initialization happens after form submission, so anything going on in a form submission (like cache clear from admin interface) will never use theme hooks – googletorp Sep 29 '18 at 14:14
  • @googletorp Sorry but I’m not ;) I did try it, these are the steps so you can too: implement THEME_menu_alter in template.php, put die(‘in theme’); , go to the front end of your site, clear the cache from the admin menu, not from a form, and you’ll see the message as expected. You could also clear via Drush then load a front end page, the same thing will happen – Clive Sep 29 '18 at 14:21
  • @Clive ah admin menu as in the module, thought you were talking about the menu item in the admin interface that allows cache clear. If you write custom code almost anything is possible. I was talking about how Drupal behaves out of the box. This OP specifically stated modules was not possible, which means that from a theme (alone) you can never use hook_menu_alter. – googletorp Sep 29 '18 at 14:30
0

I solved this as so (for info).

First a bit more background. This is basically a REST/SOAP Web Service that integrates some business info into some pages on the specific theme, part of the service is an OAuth2 layer that authenticates the server/site with the Web Service.

The Web service is not available in any other theme (indeed there are no other themes), obviously the OAuth requires exchange of secret keys and ID's so should not be exposed to the front of the site (unless the user is an authenticated admin).

My solution, firstly due to the poor coding the previous freelancer put down (he left the API and secret keys exposed, hard coded domains, no "Service Unavailable" messages, ect) I implemented a simple "Service Unavailable, please contact us or come back later" message should the web service be unavailable.

Because all this happens on specific pages of the site, I also put a block under the code that is displayed if the logged in user is an administrator.

Originally I wanted this to be a link to this supposed page that explains the Web Service is not authorized and offer the link to auth it. As this is not possible I skipped this step, shortened the explanation and present the link and explanation under the "Service is Unavailable" message, thus the admin can visit any page with the Web Service on it, see the "Unavailable" message and as an admin initialize the auth process from there.

Definitely the path of least resistance!

That solves the issue, now all that remains is for me to dig into the core for a better understanding of the way the routing table and page callbacks are built. After all, the more you know....

Finally, big thanks to everyone who took the time to stop by, read and/or comment on my query. I and SE appreciate it!

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.