'radios', '#title' => t('NodeAPI Example Rating'), '#default_value' => variable_get('nodeapi_example_'. $form['#node_type']->type, 0), '#options' => array(0 => t('Disabled'), 1 => t('Enabled')), '#description' => t('Should this node have a rating attached to it?'), ); } // If the type and node field are set this may 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_'. $form['type']['#value'], 0)) { // Note that $form['nodeapi_example_rating'] will become // $node->nodeapi_example_rating in hook_nodeapi validate op // This also means that if there is a fieldgroup defined, // $form['group']['field'], that it will become $node->field. $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, ); } } } /** * Implementation of hook_nodeapi(). * * We will implement several node API operations here. This hook allows us to * act on all major node operations, so we can manage our additional data * appropriately. */ function nodeapi_example_nodeapi(&$node, $op, $teaser, $page) { switch ($op) { // When the content editing form is submitted, we need to validate the input // to make sure the user made a selection, since we are requiring the rating // field. We have to check that the value has been set to avoid showing an // error message when a new blank form is presented. Calling form_set_error() // when the field is set but zero ensures not only that an error message is // presented, but also that the user must correct the error before being able // to submit the node. case 'validate': if (variable_get('nodeapi_example_'. $node->type, TRUE)) { if (isset($node->nodeapi_example_rating) && !$node->nodeapi_example_rating) { form_set_error('nodeapi_example_rating', t('You must rate this content.')); } } break; // Now we need to take care of loading one of the extended nodes from the // database. An array containing our extra field needs to be returned. case 'load': // we match against vid in order to keep up with the current revision $rating = db_result(db_query('SELECT rating FROM {nodeapi_example} WHERE vid = %d', $node->vid)); return array('nodeapi_example_rating' => $rating); break; // Insert is called after the node has been validated and saved to the // database. It gives us a chance to create our own record in the database. case 'insert': if (variable_get('nodeapi_example_'. $node->type, 0)) { db_query('INSERT INTO {nodeapi_example} (nid, vid, rating) VALUES (%d, %d, %d)', $node->nid, $node->vid, $node->nodeapi_example_rating); } break; // Update is called when an existing node has been changed. Here, we use a // DELETE then an INSERT rather than an UPDATE. The reason is that a node // created before this module was installed won't already have a rating // saved so there would be nothing to update. case 'update': if (variable_get('nodeapi_example_'. $node->type, 0)) { db_query('DELETE FROM {nodeapi_example} WHERE vid = %d', $node->vid); db_query('INSERT INTO {nodeapi_example} (nid, vid, rating) VALUES (%d, %d, %d)', $node->nid, $node->vid, $node->nodeapi_example_rating); } break; // Delete is called when the node is being deleted, it gives us a chance // to delete the rating too. // This will delete all revisions as well. case 'delete': db_query('DELETE FROM {nodeapi_example} WHERE nid = %d', $node->nid); break; // When a node revision is deleted, we need to remove the corresponding // record from our table. The only way to handle revision deletion is by // implementing hook_nodeapi(). case 'delete revision': // Notice that we're matching a single revision based on the node's vid. db_query('DELETE FROM {nodeapi_example} WHERE vid = %d', $node->vid); break; // 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 nodeapi('view') is more appropriate than using a filter here, because // filters transform user-supplied content, whereas we are extending it with // additional information. case 'view': if (variable_get('nodeapi_example_'. $node->type, 0)) { $node->content['nodeapi_example'] = array( '#value' => theme('nodeapi_example_rating', $node->nodeapi_example_rating), '#weight' => -1, ); } break; } } /** * Implementation of hook_theme(). * * This lets us tell Drupal about our theme functions and their arguments. */ function nodeapi_example_theme() { return array( 'nodeapi_example_rating' => array( 'arguments' => array('rating'), ), ); } /** * 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($rating) { $options = array( 0 => t('Unrated'), 1 => t('Poor'), 2 => t('Needs improvement'), 3 => t('Acceptable'), 4 => t('Good'), 5 => t('Excellent')); $output = '
'; return $output; } /** * @} End of "defgroup nodeapi_example". */