Post content in current Organic group

This week, I started using the Organic groups Drupal module for the first time in Drupal 7. This article is about how to provide a link to post in the currently viewed Organic group. The link could be added in one of several ways, e.g. in a context-sensitive block, but I prefer to add another tab along with View and Edit for the group. This is how I did it.

To start off with I added a menu item for the tab. (I often wish that menu-items and their paths were distinct objects in the Drupal API. I find that the current system can make discussing menu items ... uh, paths ... a little awkward.) Here's the implementation of hook_menu:

function my_module_menu() {

    $items['node/%node/post'] = array(

      'type' => MENU_LOCAL_TASK,
      'title' => 'Post',
      'description' => 'Post a my_content_type for this group.',
      'access callback' => '_my_module_access_post_page',
      'access arguments' => array(1),
      'page callback' => '_my_module_post_page',
      'page arguments' => array(1),
    );

    return $items;
}

Obviously, I don't want this link to appear on every node, so I need to restrict it to nodes of my_group_type. Additionally, I only want group members to see the link. Here's the access callback:

 function _my_module_access_post_page( $node ) {
    return ($node->type == 'my_group_type') && og_is_member( 'node', $node->nid );

}

I could have done a one-line page callback in order to redirect to /node/add/my_content_type. I chose not to do this because I wanted to customise the form and I find it easy to use the current path to control this. Instead, I've "embedded" the node form. Here's the page callback:

function _my_module_post_page( $node ) {
    module_load_include( 'inc', 'node', 'node.pages' );
    $form = node_add( 'my_content_type');
    return $form;
}

Now comes the node form customisation. I needed to cope with several circumstances:

  1. When created through a group, set the group audience field automatically and hide it from the user.
  2. When edited by an admin, allow the group audience to be edited, and
  3. when edited by anyone else, do not allow the group audience to be edited.

This way, most users will never manually set the group audience of a piece of content. That's one less concept that they have to grok in order to use the site. Here's the Form customisation:

/**
 * Implements hook_form_FORM_ID_alter()
 *
 * In the my_content_type node form, strictly control group choice.
 */
function my_module_form_my_content_type_node_form_alter( &$form, &$form_state  ) {
    if ( arg(0) == 'node' && is_numeric( arg(1) ) && arg(2) == 'post' ) {
        // Posting a my_content_type from within a specific group.
        // Automatically select the relevant group audience.
        $form['#validate'][] = '_my_module_force_group';
        $form['og_group_ref']['#access'] = FALSE;
        $form['preset-group'] = array(
            '#type' => 'value',
            '#value' => arg(1),
        );
    }
    elseif ( arg(0) == 'node' && is_numeric( arg(1) ) && arg(2) == 'edit' ) {
        // Editing an existing my_content_type.
        // Only allow powerful admins to change group audience.
        if ( ! user_access( 'Bypass content access control' ) ) {
            $form['og_group_ref']['#access'] = FALSE;
        }
    }
}

Finally, as you may see in the form customisation code, I've added a custom validation function to the form. Technically speaking it would more properly be a submit function as I'm not validating anything. Instead, I'm setting the group audience from the group node ID which I saved during the form customisation. By making it a validation function I did not need to think about whether the new node had already been saved when my function ran. I assume that those clever Drupal folks have already dealt with this but, as I'm not saving anything myself, I figured I'd save time by not finding out. Here's the custom validation function:

function _my_module_force_group($form, &$form_state) {
    $form_state['values']['og_group_ref']['und'][0]['target_id'] =
        $form_state['values']['preset-group'];
    return TRUE;
}

And that's it. Group members can now post within their groups with minimum hassle.

Justin Hellings

"Justin? Hell of a guy! We would have kept him but you know how it is. Genius like that is always restless ... Eh? ... Oh, him ... No, I thought you meant someone else."



comments powered by Disqus