'fieldset', '#title' => t('Rating settings'), '#collapsible' => TRUE, '#collapsed' => TRUE, '#group' => 'additional_settings', '#weight' => -1, ); $form['rating']['nodeapi_example_node_type'] = array( '#type' => 'radios', '#title' => t('NodeAPI Example Rating'), '#default_value' => variable_get('nodeapi_example_node_type_' . $form['#node_type']->type, FALSE), '#options' => array( FALSE => t('Disabled'), TRUE => t('Enabled'), ), '#description' => t('Should this node have a rating attached to it?'), ); } // Here we check to see if the type and node field are set. If so, it could // be a node edit form. elseif (isset($form['type']) && isset($form['#node']) && $form['type']['#value'] . '_node_form' == $form_id) { // If the rating is enabled for this node type, we insert our control // into the form. $node = $form['#node']; if (variable_get('nodeapi_example_node_type_' . $form['type']['#value'], FALSE)) { $form['nodeapi_example_rating'] = array( '#type' => 'select', '#title' => t('Rating'), '#default_value' => isset($node->nodeapi_example_rating) ? $node->nodeapi_example_rating : '', '#options' => array(0 => t('Unrated'), 1, 2, 3, 4, 5), '#required' => TRUE, '#weight' => 0, ); } } } /** * Implements hook_node_validate(). * * Check that the rating attribute is set in the form submission, since the * field is required. If not, send error message. */ function nodeapi_example_node_validate($node, $form) { if (variable_get('nodeapi_example_node_type_' . $node->type, FALSE)) { if (isset($node->nodeapi_example_rating) && !$node->nodeapi_example_rating) { form_set_error('nodeapi_example_rating', t('You must rate this content.')); } } } /** * Implements hook_node_load(). * * Loads the rating information if available for any of the nodes in the * argument list. */ function nodeapi_example_node_load($nodes, $types) { // We can use $types to figure out if we need to process any of these nodes. $our_types = array(); foreach ($types as $type) { if (variable_get('nodeapi_example_node_type_' . $type, FALSE)) { $our_types[] = $type; } } // Now $our_types contains all the types from $types that we want // to deal with. If it's empty, we can safely return. if (!count($our_types)) { return; } // Now we need to make a list of revisions based on $our_types foreach ($nodes as $node) { // We are using the revision id instead of node id. if (variable_get('nodeapi_example_node_type_' . $node->type, FALSE)) { $vids[] = $node->vid; } } // Check if we should load rating for any of the nodes. if (!isset($vids) || !count($vids)) { return; } // When we read, we don't care about the node->nid; we look for the right // revision ID (node->vid). $result = db_select('nodeapi_example', 'e') ->fields('e', array('nid', 'vid', 'rating')) ->where('e.vid IN (:vids)', array(':vids' => $vids)) ->execute(); foreach ($result as $record) { $nodes[$record->nid]->nodeapi_example_rating = $record->rating; } } /** * Implements hook_node_insert(). * * As a new node is being inserted into the database, we need to do our own * database inserts. */ function nodeapi_example_node_insert($node) { if (variable_get('nodeapi_example_node_type_' . $node->type, FALSE)) { // Notice that we are ignoring any revision information using $node->nid db_insert('nodeapi_example') ->fields(array( 'nid' => $node->nid, 'vid' => $node->vid, 'rating' => $node->nodeapi_example_rating, )) ->execute(); } } /** * Implements hook_node_delete(). * * When a node is deleted, we need to remove all related records from our table, * including all revisions. For the delete operations we use node->nid. */ function nodeapi_example_node_delete($node) { // Notice that we're deleting even if the content type has no rating enabled. db_delete('nodeapi_example') ->condition('nid', $node->nid) ->execute(); } /** * Implements hook_node_update(). * * As an existing node is being updated in the database, we need to do our own * database updates. * * This hook is called when an existing node has been changed. We can't simply * update, since the node may not have a rating saved, thus no * database field. So we first check the database for a rating. If there is one, * we update it. Otherwise, we call nodeapi_example_node_insert() to create one. */ function nodeapi_example_node_update($node) { if (variable_get('nodeapi_example_node_type_' . $node->type, FALSE)) { // Check first if this node has a saved rating. $rating = db_select('nodeapi_example', 'e') ->fields('e', array( 'rating', )) ->where('e.vid = (:vid)', array(':vid' => $node->vid)) ->execute()->fetchField(); if ($rating) { // Node has been rated before. db_update('nodeapi_example') ->fields(array('rating' => $node->nodeapi_example_rating)) ->condition('vid', $node->vid) ->execute(); } else { // Node was not previously rated, so insert a new rating in database. nodeapi_example_node_insert($node); } } } /** * Implements hook_node_view(). * * This is a typical implementation that simply runs the node text through * the output filters. * * Finally, we need to take care of displaying our rating when the node is * viewed. This operation is called after the node has already been prepared * into HTML and filtered as necessary, so we know we are dealing with an * HTML teaser and body. We will inject our additional information at the front * of the node copy. * * Using node API 'hook_node_view' is more appropriate than using a filter here, * because filters transform user-supplied content, whereas we are extending it * with additional information. */ function nodeapi_example_node_view($node, $build_mode = 'full') { if (variable_get('nodeapi_example_node_type_' . $node->type, FALSE)) { // Make sure to set a rating, also for nodes saved previously and not yet // rated. $rating = isset($node->nodeapi_example_rating) ? $node->nodeapi_example_rating : 0; $node->content['nodeapi_example'] = array( '#markup' => theme('nodeapi_example_rating', array('rating' => $rating)), '#weight' => -1, ); } } /** * Implements hook_theme(). * * This lets us tell Drupal about our theme functions and their arguments. */ function nodeapi_example_theme() { return array( 'nodeapi_example_rating' => array( 'variables' => array('rating' => NULL), ), ); } /** * A custom theme function. * * By using this function to format our rating, themes can override this * presentation if they wish; for example, they could provide a star graphic * for the rating. We also wrap the default presentation in a CSS class that * is prefixed by the module name. This way, style sheets can modify the output * without requiring theme code. */ function theme_nodeapi_example_rating($variables) { $options = array( 0 => t('Unrated'), 1 => t('Poor'), 2 => t('Needs improvement'), 3 => t('Acceptable'), 4 => t('Good'), 5 => t('Excellent'), ); $output = '
'; $output .= t('Rating: %rating', array('%rating' => $options[(int) $variables['rating']])); $output .= '
'; return $output; } /** * @} End of "defgroup nodeapi_example". */