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 ?

  • 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. – Ruben Beekman Apr 10 '17 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 Apr 10 '17 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. – longboardnode Apr 10 '17 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 Apr 10 '17 at 15:01
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']));
    }
  }
}
  • Thanks for your answer. Putting these checks into form_alter ends with same loop behaviour. – Kojo Apr 10 '17 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 – longboardnode Apr 10 '17 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 Apr 10 '17 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. – longboardnode Apr 11 '17 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, privacy policy and cookie policy

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