2

I'm implementing hook_menu in my custom module. Implementation works fine except, it turns out that $GLOBALS['user']->uid returns always same value no matter which user is currently logged in. Sounds absurd! What could be the problem?

Below is a full hook_menu:

function my_tab_menu(){

    $current_user_id = $GLOBALS['user']->uid;  // $current_user_id=202 for each 

    $query = new EntityFieldQuery();
        $result = $query
                ->entityCondition('entity_type', 'node')
                ->entityCondition('bundle', 'profile')
                ->propertyCondition('status', 1)
                ->propertyCondition('uid', $current_user_id)
                ->propertyOrderBy('created', 'DESC')    
                ->range(0,1)
                ->execute();



    if (isset($result['node'])) {
        return array(
        'user/%/alumni-spotlight' => array(
                'title' => 'Alumni spotlight',
                'page callback' => 'user_tab_page',
                'page arguments' => array(1,$result['node'],$current_user_id),
                'access callback' => 'user_tab_access',
                'access arguments' => array(1),
                'type' => MENU_LOCAL_TASK,
            ),
           );
    }
}
  • 1
    hook_menu is cached, looks like the wrong place to be adding that code, especially the db_query. Use the %user load argument in your page callback instead for user pages – David Thomas Oct 16 '13 at 4:55
  • Also maybe include your full hook_menu() so we can see what you are trying to achieve and can give you a better answer for your specific problem. – rooby Oct 16 '13 at 5:37
  • @David Tomas, could you please explain further how I can use %user load argument? I tried this: $uid = arg(1); but I'm not getting user id form url? Why? – Antonio Oct 16 '13 at 6:02
  • @rooby I edited the post and included the full hook_menu(). – Antonio Oct 16 '13 at 6:09
7

Hook menu is not for non-menu functionality.

Using %user in the menu item will call user_load() with whatever is in that part of the url (in this case the uid) and then when that part of the url is used in callback or access arguments it will pass in the loaded user object instead of the user id.

See wildcard loader arguments for more info on that.

To control who sees the tab, do your database check in the access control callback and deny access if there is no result. This way the tab will only show if there is a node.

Callbacks like the access control call back and the title callback run every time, not just when the cache is refreshed, so it is ok to use them in this way.

Try

/**
 * Implements hook_menu().
 */
function MYMODULE_menu() {
  $items = array();

  $items['user/%user/alumni-spotlight'] = array(
    'title' => t('Alumni spotlight'),
    'page callback' => 'MYMODULE_user_tab_page',
    'page arguments' => array(1),
    'access callback' => 'MYMODULE_user_tab_access',
    'access arguments' => array(1),
    'type' => MENU_LOCAL_TASK,
  );

  return $items;
}

/**
 * Access callback for user alumni spotlight page.
 */
function MYMODULE_user_tab_access($user) {
  // Do something here to check access & return TRUE or FALSE to grant access or not.
  $query = new EntityFieldQuery();
  $result = $query
    ->entityCondition('entity_type', 'node')
    ->entityCondition('bundle', 'profile')
    ->propertyCondition('status', 1)
    ->propertyCondition('uid', $user->id)
    ->propertyOrderBy('created', 'DESC')    
    ->range(0, 1)
    ->execute();

  // If there is a node, allow the user to access the page.
  if (isset($result['node'])) {
    return TRUE;
  }

  // If there is no node, deny access.
  return FALSE;
}

/**
 * Page callback for user alumni spotlight page.
 */
function MYMODULE_user_tab_page($user) {
  // Return the content of the page.
}
  • Thanks robby! I think this code can't work in my scenario. Note that I need to add tab only if EntityFieldQuery() returns a result. If not, tab should not be showed at all. Makes sense? – Antonio Oct 16 '13 at 7:10
  • 1
    In that case, do your entityFieldQuery in the MYMODULE_user_tab_access($user) function and return true if there is a node and false if there is not one. - I'll tweak the answer – rooby Oct 16 '13 at 8:46
  • Wow that's awesome Roby! That is the solution I was hoping for. For some reason I couldn't realize that access callback is the key here. :) THX! – Antonio Oct 16 '13 at 17:25
3

As I can see from your hook_menu implementation, you're trying to add a tab on the user page if the user published at least one content of type 'profile'. And inside this tab you want to show the latest 'profile' the user has published.

Your implementation is wrong. First, for the reason that the other answers also mention, hook_menu will be cached. Second, you shouldn't do the logic in hook_menu, but in the page or access callback functions.

However, there is also another way to get what you want to achieve, using Views.

Using hook_menu:

function my_tab_menu() {
  return array(
    'user/%/alumni-spotlight' => array(
      'title' => 'Alumni spotlight',
      'page callback' => 'user_tab_page',
      'page arguments' => array(1),
      'access callback' => 'user_tab_access',
      'access arguments' => array(1),
      'type' => MENU_LOCAL_TASK,
    ),
  );
}

This way you register a menu item, that can be cached. In the page callback you can do the query and show the content. Note that, even if you don't want to show the menu item if there is no result, you should register it with hook_menu. With 'access callback' function you can decide where to show or not.

Using Views

  1. Create a View page and give it a path user/%/alumni-spotlight, show fields
  2. Items to display: 1, no pager.
  3. Set Menu: Menu Tab
  4. Add relationship: 'Content: Author'
  5. Add filter: 'User: Current', select relationship 'author', is the logged in user: 'yes'
  • your guess is pretty close. Everything you wrote is correct except I'm not showing a profile in the tab. Instead, I'm showing a link to specific node (profile) that I'm getting from query result. I look forward to getting you suggestions. thx a bunch! – Antonio Oct 16 '13 at 6:54
  • So the scenario: I log into your site, and if I ever had published a node (profile), I'll see an extra tab (Alumni Spotlight) on EVERY user's page, which includes a link to MY latest node. Right? – Елин Й. Oct 16 '13 at 7:27
  • That is correct! Note that I had tried return FALSE; in page callback funtion but it's not working! – Antonio Oct 16 '13 at 7:42
  • Updated my answer and deleted the option with Panels, since according to your correction on my assumptions it wouldn't make many sense to do it with Panels. But the Views option does it well. – Елин Й. Oct 17 '13 at 7:22
  • Thanks again for your help! I was considering that choice (view implementation) when I was at the beginig but later realized it would be more efficient way to get it done without view, using just a db_query. – Antonio Oct 17 '13 at 14:34
0

Can you try using

global $user;
$uid = $user->uid;

Regards`

  • 1
    It still won't work because he has the code in hook_menu(), which is cached. – rooby Oct 16 '13 at 5:36
  • I had tried that before. It is basically the same thing as $GLOBALS['user']->uid; Won't work! – Antonio Oct 16 '13 at 5:46
  • Hello. Code-only answers are hardly any better than link-only ones. They may answer how to make things work, but does not answer why, what was wrong, what mechanisms take place. Could you elaborate a bit more why you was thinking it might help? – Mołot Oct 16 '13 at 6:46
0

Try using cache_clear_all() above the global $user. This will clear the cache and the present uid can be obtained.

Note : I have not tried this hook before.

  • 1
    Tried but no effect :(. Clearing cache manually doesn't work either. – Antonio Oct 16 '13 at 6:15

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.