I have read the documentation of the menu system on the Drupal API website, but I can't quite figure out how to use it for my module. I think I am missing something basic, and I hope someone out there can help.

What I want to do:
My module ('foo') sets a session variable but does not create any content to output. When a user visits foo/node/1 the foo module should be called. It will set a session variable, and then the content of node/1 will be displayed as normal.

Where I am stuck:
When a user visits a URL beginning with /foo/ the foo module gets called. But how do I then output the node/1 content?. Should the function specified by the foo_menu callback somehow take care of outputting node/1 itself? Or can it simply pass control back to the functions that would normally take care of rendering node/1?

I am currently using drupal_goto as a workaround. After foo does its thing, it redirects users to /node/1 . But I really want the user to see /foo/node/1 as the final URL, rather than redirecting them to /node/1.

THANK YOU for your help!

Comments

evui’s picture

I have the same problem. I defined a custom node type and i want to access
a single node from a url like /code/001 where 001 is a custom field of my node type.

Currently i have set up a callback to get the needed arg(1) part, do a query to get the correspondent nid and then redirect to /node/nid.

I haven't tried mass url aliasing http://drupal.org/node/23708, but i don't think it can work since the aliasing definition goes in settings.php and i don't think that db_layer functions are available at that time, plus i don't think it's a clean approach.

I'm afraid the solution is to output the node ourselves. I hope to be proved wrong :)

isaac77’s picture

in a way that is understandable for new users. Anyone out there who can help us out? Consider it a good deed for drupal-dom, and something that will encourage more people to stick with drupal.

An additional question:
- I want module "foo" to handle visits to any page with a URL foo/*
- after modifying a variable, the page foo/* should be displayed as normal
- in many cases, the url will be an alias... foo/bar will be aliased to node/7 etc. Can the foo module still handle the request for foo/bar, then allow the url alias module to figure out where to get content from and how to display it?

coreyp_1’s picture

First question: Yes, you need to output the node yourself. Something ending with:

print theme('page', $content);

$content should be the node body. You will also have to set the page title.

For your second question, let me give a quick overview of how the aliasing system works:

  1. A page is requested by the user (suppose it is "www.example.com/do_it_my_way").
  2. First, Drupal takes the requested page ("do_it_my_way"), and looks for an alias.
  3. Suppose that an alias exists for "do_it_my_way" pointing to "node/4". Drupal then changes the request string to "node/4", and proceeds happily. It is important to note that, from this point on, the rest of the code will see the page requested as "node/4".
  4. If no alias can be found, then Drupal simply proceeds to the next step.
  5. After attempting to un-alias the request, Drupal then looks through the menu system for the appropriate callback to handle the request string. "node/4" will be handled by the callback defined for "node", and "4" will be passed to the function as an argument.
  6. If no match is found, an error is generated.

You stated that "foo/bar" will be an alias to "node/7". If you mean this literally, then you must realize that your module will never see the request for "foo/bar", because Drupal has already changed your request to "node/7", and is processing it as such. If you mean this figuratively (meaning the foo module will do it's thing, but appear to be doing the same thing as the original node module), then I think there is a better way of handling the situation.

Why are you making a module duplicate the actions of another module? It would be simpler to simply attach your functionality to the normal viewing of a node page (perhaps via the hook_menu() function). This way, all normal actions are carried out normally, and you can attach the necessary functionality when needed.

Let me know if that didn't make sense...

- Corey

evui’s picture

Your explanations confirm what i was thinking about url aliasing, in the end outputting the node it's not a hard task :)
Thanks for clarifying how the aliasing system works.

isaac77’s picture

Corey, thanks very much for your help!

attach your functionality to the normal viewing of a node page (perhaps via the hook_menu() function

After looking at the api docs for hook_menu, I was under the impression that it has to be used as a callback for a completely separate module. Can you point me toward an explanation / example of how to "attach" the functionality to the normal viewing of a node page? That definintely sounds more like what I was trying to do.

You stated that "foo/bar" will be an alias to "node/7". If you mean this literally, then you must realize that your module will never see the request for "foo/bar"

So how do functions ever get to handle requests based on URL? I guess I'm still missing part of the concept. The system obviously can't require hard coding specific URL's (node/5, node/7, etc) that should be sent to a particular module... so how is it supposed to work?

Why are you making a module duplicate the actions of another module?

I was attempting to write an extremely simple module to allow a multilingual site. I am doing this partly because it seems like i18n module and the alternatives are all fairly buggy (and have more features and complexity than I need); partly as a learning exercise.

I now have a working set up... Visits to a page with a URL alias that begins with /en set a "language" session variable to "en", visits to pages that have a URL alias starting with /ar switch the language to "ar" etc. [ This is accomplished by testing $_SERVER['REQUEST_URI') .]

The correct navigation menu block is then displayed based on that variable. This works, but the code is in page.tpl.php Getting all the code into a module seemed like the right thing to do, and hopefully with your help I'll figure out how to accomplish that...

Thanks again, and any further clarification would be appreciated!

coreyp_1’s picture

Let's see if I remember what I was talking about.

  • hook_menu()

    You are right in that hook_menu() is used to associate callbacks with certain request strings. But that's not all it can be used for. Since hook_menu() is called for every page request (whether it be a node page or a module generated page), it is commonly used to carry out other tasks. It may or may not be necesssary for your implementation, but I mentioned it because I wasn't entirely sure of everything you needed to do.

    The reason I probably wouldn't use hook_nodeapi() is because it is often called numerous times in a page view, whereas hook_menu() is only called once. Then again, I guess it depends on what you are trying to accomplish.

    I did use hook_nodeapi() here (http://drupal.org/node/79209) in the module I posted in comment # 6. Although obviously it is not written to do what you need to do, it will suffice to demonstrate how the hook can be used to modify node contents on the fly.

  • As for the aliasing stuff:

    All I am trying to say is that if you set up an alias in the alias table which replaces "foo/bar" with "node/7", then all function handling goes to the node module, rather than the foo module. After reading your last post, I see that this is not what you meant.

I'm sorry, but I doubt I've answered your question fully. I probably gave too much info on things that ended up not applying to your situation. Please let me know what I need to clarify.

Then again, after reading all of this, I think I need more caffine!!!

- Corey

isaac77’s picture

I appreciate your help. I'll look at the example you reference and see if that clears things up a bit.

In general, it would be useful to have some docs that give an overview of how the different parts of Drupal work together... something a bit more in-depth than the current docs provide, but targeted at new users who need to understand the underlying concepts and structure of drupal (before digging into the code).