0

I need to limit node creation to one item for a specific content_type (photography contest), and to redirect the user to its photography if he already posted one. The snippet below is almost working as expected.

function mymodule_menu_alter(&$items) {
  $items['node/add/slide']['access callback'] = '_mymodule_limit_slide';
}

function _mymodule_limit_slide () {
  global $user;
  if(user_access("create slide content")) {
    $allowed_limit = variable_get('allowed_limit', 1);
    $slides = db_query("SELECT nid, count(*) ct FROM {node} WHERE type = :type AND uid = :uid", array(':type' => 'slide' ,':uid' => $user->uid))->fetchAssoc();
    if ($slides['ct'] < $allowed_limit || in_array('administrator', $user->roles)) {
      return TRUE;
    }
    else {
      drupal_set_message('You cannot post more than one photography. But you can edit the one you posted below if yo wish to.');
      drupal_goto(drupal_get_path_alias('node/'.$slides['nid']));
    }
  }
  return FALSE;
}

If I dpm(slides), it returns the correct array and data.

But, as far as I could debug, if I try to connect a user who :

  • already posted at least one node of other content type
  • whether he posted or not a slide

Drupal tries to go to node/'.$slides['nid'] and that creates an infinite loop.

Summary : I don't understand why my function _mymodule_limit_slide () would be called out of node/add/slide url, or what else is wrong ?

4
  • Couple of things I would try: remove the drupal_get_path_alias and maybe put a drupal_exit(); under that line. I can't see anything wrong with your logic though. Commented Apr 10, 2017 at 14:09
  • Thank you, Indeed I'm redirected to path alias without calling drupal_get_path_alias, but unfortunately this did not help.
    – Kojo
    Commented Apr 10, 2017 at 14:36
  • I believe you want to hook into the node add form instead of the menu access. I believe this is why Drupal runs your _limit_slide function every time it displays the menu. Commented Apr 10, 2017 at 14:54
  • Thank you. I need the user to be stopped and redirected before the node edit form is displayed. How would you implement your idea then ?
    – Kojo
    Commented Apr 10, 2017 at 15:01

2 Answers 2

0

I think if you add the access login in the form_alter, the user should be redirected properly. IOW something like this:

function yourmodule_form_alter(&$form, $form_state, $form_id) {  if($form_id == 'CONTENT-TYPE_node_form') {  global $user;
  if(user_access("create slide content")) {
    $allowed_limit = variable_get('allowed_limit', 1);
    $slides = db_query("SELECT nid, count(*) ct FROM {node} WHERE type = :type AND uid = :uid", array(':type' => 'slide' ,':uid' => $user->uid))->fetchAssoc();
    if ($slides['ct'] < $allowed_limit || in_array('administrator', $user->roles)) {
      return TRUE;
    }
    else {
      drupal_set_message('You cannot post more than one photography. But you can edit the one you posted below if yo wish to.');
      drupal_goto(drupal_get_path_alias('node/'.$slides['nid']));
    }
  }
}
4
  • Thanks for your answer. Putting these checks into form_alter ends with same loop behaviour.
    – Kojo
    Commented Apr 10, 2017 at 16:39
  • I still think form alter is a better way, because this fires only when somebody goes to the form page, as opposed to checking things on every node prepare... but there are many right solutions here :) Glad you resolved it Commented Apr 10, 2017 at 16:52
  • Well, $slides and subsequent $slides['nid'] are set outside/before the if statement, and I get the right nid value. But I could not get yours working. On the other hand, it would fire each time form_alter is run. Which one will be used more, form_alter or node_prepare ? You pointed a good question, but I don't have the answer. :) Cheers
    – Kojo
    Commented Apr 10, 2017 at 17:03
  • Yeah, which usage is higher depends on the site, iow if there are a lot of nodes or a lot of forms lol But back to your original problem, my guess is that since Drupal executed your access function every time it loaded a page and built the menu, it would then find the user couldnt access, and redirect to node/$slides['nid'] but on that node page Drupal would have to again rebuild the menus, check access, redirect and the process would repeat in a loop. Commented Apr 11, 2017 at 4:20
0

I got it working that way :

function mymodule_node_prepare($node) {
  if ( empty($node->nid) && $node->type == 'slide' && !in_array('administrator', $user->roles)) {
    global $user;
    $slides = db_query("SELECT nid, count(*) ct FROM {node} WHERE type = :type AND uid = :uid", array(':type' => 'slide' ,':uid' => $user->uid))->fetchAssoc();
    $allowed_limit = variable_get('allowed_limit', 1);    

    if ($slides['ct'] >= $allowed_limit  ) {
      drupal_set_message('You cannot post more than one photography. But you can edit the one you posted below if yo wish to.');
      drupal_goto('node/'.$slides['nid']);
    }
  }
}

Sounds more elegant than menu_alter(), but I couldn't figure out what was wrong in question logic.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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