background image

Content tagged with: CCK

Eric's picture

I created a Drupal site to host my photography in CCK Imagefield nodes and used Lucene to enhance my search functionality. By default Drupal's search results are text-based so I decided to add some code to show image thumbnails in my search results. I checked out Drupal Lucene's hooks and decided to implement a hook_luceneapi_result_alter() function in my existing module.

<?php
function MYMODULE_luceneapi_result_alter(&$result, $module, $type = NULL) {
 
 
// check for node results
 
if ($type == 'node') {
 
   
// check node type
   
if ($result['node']->type == 'image') {
   
     
// define an imagecache image path for image thumbnail
     
$imagecache_path_thumbnail = file_directory_path() . '/imagecache/thumbnail' . str_replace(file_directory_path(),'',$result['node']->field_image[0]['filepath']);     
     
     
// define an imagecache image path for image (large)
     
$imagecache_path_large = file_directory_path() . '/imagecache/large' . str_replace(file_directory_path(),'',$result['node']->field_image[0]['filepath']);
   
     
// define theme_image() variables
     
$alt = check_plain($result['node']->title);
     
$title = check_plain($result['node']->title);
     
// add rel=lightbox to enable lightbox2 module
     
$attributes = array(
       
'rel' => 'lightbox',
      );
     
// let imagecache define the size
     
$getsize = FALSE;
     
// generate the image hml
     
$image_html = theme('image', $imagecache_path_thumbnail, $alt, $title, $attributes, $getsize);     
   
      if (
$image_html) {
               
       
// define lightbox link
       
$image_link = l(
         
$image_html,
         
$imagecache_path_large,
          array(
           
'html' => true,
           
'attributes' => array(
             
'rel' => 'lightbox',
            )
          )
        );

       
// add data to the result variable, passed by reference
       
$result['image_thumbnail'] = $image_link;
       
      }
   
    }
 
  }

}
?>

The above code adds additional data to my search results variables. I then implemented a hook_preprocess_search_result() function in my theme's template.php file to pass this data to the search-result.tpl.php template file.

<?php
function MYTHEME_preprocess_search_result(&$variables) {

 
// ...snip...

  // check for lucene node search results
 
if ($variables['type']=='luceneapi_node') {

   
// check for image
   
if ($variables['result']['image_thumbnail']) {   

     
// pass additional data to theme template file
     
$variables['image_thumbnail'] = $variables['result']['image_thumbnail'];

    }
   
  }

}
?>

And in my theme's search-result.tpl.php template file, I added the following PHP to show the new variable.

<div class="search-result <?php print $search_zebra; ?>">

  <?php if($image_thumbnail): ?>
    <?php print $image_thumbnail; ?>
  <?php endif; ?>

  <!-- ...snip... -->

I also added a few lines of CSS in my theme's style.css file to tidy up the layout.

.search-results.luceneapi_node-results .search-result {
  clear: both;
}

.search-results.luceneapi_node-results .search-result img {
  float: left;
  margin: 0px 20px 20px 0px;
}

The visual results can be seen here on my photo gallery.

Visual search results

Eric's picture

In this tutorial I'll show you how to upload an image using the Forms API, create a new node, and attach the image to the CCK (filefield/imagefield) field. I wrote this code to work with the modules I primarily use for image processing: cck, filefield, imageapi, imagecache, imagefield, mimedetect, and transliteration.

After I installed those modules, I created a new node type (admin/content/types/add) called "Image" and added a single imagefield field.

Image node fields

Next, I created a custom module with a hook_menu() implementation:

<?php
// NOTE: this variable is used through the code,
// so I thought it would be better to put it in a constant
define('IMAGE_UPLOAD_CONTAINER', 'image_upload');

/**
* Implements hook_menu()
*/
function helper_menu() {

 
// create a blank array of menu items
 
$items = array();
 
 
// define page callback for upload form
  // NOTE: you'll want to restrict permission better [see: access arguments]
 
$items['upload'] = array(
   
'title' => t('Upload'),
   
'description' => t('Upload'),
   
'page callback' => 'drupal_get_form',
   
'page arguments' => array('helper_page_callback_upload_form'),
   
'access arguments' => array('access content'),
   
'type' => MENU_CALLBACK,
  );
 
 
// return menu items
 
return $items;

}
?>

I defined the form function page callback:

<?php
/**
* Implements page callback for upload form
*/
function helper_page_callback_upload_form() {

 
// create an empty form array
 
$form = array();
 
 
// set the form encoding type
 
$form['#attributes']['enctype'] = "multipart/form-data";
 
 
// add a file upload file
 
$form[IMAGE_UPLOAD_CONTAINER] = array(
   
'#type' => 'file',
   
'#title' => t('Upload an image'),
  );
  
 
// add a submit button
 
$form['submit'] = array(
   
'#type' => 'submit',
   
'#value' => 'Submit',
  );
 
 
// return form array
 
return $form;

}
?>

This page callback function results in the following form:

Image node form

Then I added the form validation and submit handler functions:

<?php
/**
* Implements form validation handler
*/
function helper_page_callback_upload_form_validate($form, &$form_state) {

 
// if a file was uploaded, process it.
 
if (isset($_FILES['files']) && is_uploaded_file($_FILES['files']['tmp_name'][IMAGE_UPLOAD_CONTAINER])) {

   
// validate file extension
    // NOTE: you can ellaborate on this code and add additional validation
   
if ($_FILES['files']['type'][IMAGE_UPLOAD_CONTAINER] != 'image/jpeg') {
     
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Invalid file extension.');
      return;
    }

   
// attempt to save the uploaded file
   
$file = file_save_upload(IMAGE_UPLOAD_CONTAINER, array(), file_directory_path());

   
// set error if file was not uploaded
   
if (!$file) {
     
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Error uploading file.');
      return;
    }
      
   
// set files to form_state, to process when form is submitted
   
$form_state['storage'][IMAGE_UPLOAD_CONTAINER] = $file;
      
  }
  else {
   
// set error
   
form_set_error(IMAGE_UPLOAD_CONTAINER, 'Error uploading file.');
    return;  
  }

}

/**
* Implements form submit handler
*/
function helper_page_callback_upload_form_submit($form, &$form_state) {
 
 
// create new node object
 
$new_node = (object) array(
   
'type' => 'image',
   
'uid' => $GLOBALS['user']->uid,
   
'name' => $GLOBALS['user']->name,
   
'title' => t('YOUR NODE TITLE'),
   
'status' => 1,
   
'field_image' => array(
      (array)
$form_state['storage'][IMAGE_UPLOAD_CONTAINER],
    ),
  );
   
 
// save node
 
node_save($new_node);
 
 
// clear form storage, to allow form to submit
 
$form_state['storage'] = array();
 
 
// redirect user, set message, etc!

}
?>

After using the form to upload an image, the following node was created:

New image node

Eric's picture

In this blog entry I'll show how you can create a Google map showing where your users are located using CCK, Content Profile, Views, GMap, and Location modules. Once you've downloaded and extracted those modules, enable the following modules (and set permissions accordingly):

Content
Location
Location CCK
Content Profile
GMap
GMap Location
Views
Views UI

Next you'll need to configure these new modules. On the GMap settings page (admin/settings/gmap) you'll need to add your API Key and enable the setting to Use AutoZoom. On the Location settings page (admin/settings/location) enable the checkbox to use a Google Map to set latitude and longitude and enable JIT geocoding. On the geocoding settings page (admin/settings/location/geocoding), you'll have to enable Google Maps for the desired countries.

The Content Profile module creates a new content type called "Profile". You'll need to add a new field to this content type for the user's location (admin/content/node-type/profile/fields). Enter a label for the node type (Location), enter a field name (field_location), choose "Location" for the field type, and choose "Location Field" for the widget.

On the next screen edit the Locative information sections (Collection and Display) to your liking, and save the field settings. For my example, I enabled Street location, Additional, City, State, Postal code, Country, and Coordinate Chooser.

Now if you create your profile node (node/add/profile) you can enter your location information and save the new node. If all is working at this point, if you return to the profile node edit screen and scroll down to the location information, you should now see a marker on map for your location and the geocoded information will be shown.

Now you can add a new view (admin/build/views/add) to show the user's profile locations. Enter a name for your view, choose node for the view type, and click the next button. Add a new filter for "Node: Published" is true and "Node: Type" is one of "Profile". Add a new relationship for Content: Location (field_location). Add fields for "Location: Latitude" (using the Location relationship), "Location: Longitude" (using the Location relationship), and any additional fields you'd like to display in the GMap marker (title, parts of the address, etc). For the Style of the view choose "GMap". For the GMap style settings, select "Choose latitude and longitude fields" for the Data Source and ensure the Latitude and Longitude fields as set.

Lastly, I added a page view so I could see the results in action..

ps> special thanks to everyone at CommonPlaces for their great technical discussions about these modules!

Eric's picture

Last year I wrote a quick code snippet to Prevent the user from creating more than one node of a certain type for Drupal 5. I received a comment request to update this code for Drupal 6.

<?php
function MYMODULE_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {

 
// define node type that a user will only be allowed to create one instance of
 
$singleNodeType = 'YOUR-NODE-TYPE';
 
 
// test for node/add/NODETYPE page
 
if ($node->type==$singleNodeType && $op=='prepare' && arg(0)=='node' && arg(1)=='add') {

   
// define sql to create node table
   
$sql = "select nid from {node} where type='%s' and uid='%d'";
   
   
// execute sql
   
$resource = db_query($sql, $singleNodeType, db_escape_string($GLOBALS['user']->uid));
   
$result = db_result($resource);

   
// test for result
   
if (!empty($result)) {
     
     
// set a message
     
drupal_set_message("Sorry, you are only allow to create one $singleNodeType.");
     
     
// redirect the user
     
drupal_goto('node/add');
     
    }
       
  }
 
}
?>

The above code tests if the user is on the node/add/NODETYPE page and if the user has already created an instance of the node type, sets a message and redirects them away from the node/add page.

Eric's picture

This article will show you how to establish parent and child relationships between nodes. To start, you'll need to install and enable the CCK module, and node reference (which comes with CCK). Next, you'll need to create two node types (admin/content/types/add). For my example, I created two node types: Organization (parent) and Department (child), both consisting of a title and body (of course, you can add as many fields as you'd like).

Next, you'll want to add a new field to the parent node (organization) by editing the content type (admin/content/node-type/organization) and clicking on the "Manage fields" tab. Enter the information to add a new reference field on this screen. Add a label (ex: "Department Reference"), enter a field name (ex: field_ref_department), choose "Node reference" as the field type, and choose "Autocomplete text field" as the form element as shown below.

node reference add field 1

On the next screen you can choose the field options. For this example, I changed "Number of values" to "Unlimited" (to allow a one to many relationship), selected "Department" in the list of content types that can be referenced, and saved these settings.

node reference add field 2

Now, if you create a new parent node (Organization: node/add/organization), you'll have the option of adding pre-existing child (Department) nodes. As you start typing the title of the child nodes in the node reference auto-complete field, it will automatically populate the field with nodes that match. Of course this will only work if you have already created child nodes. At this point adding relationships is a two step process.

node reference add parent node 1

To improve usability, you can install the Popups API (http://drupal.org/project/popups) and Add and Reference (http://drupal.org/project/popups_reference) modules which allow you to add child nodes without leaving the node/add/PARENT-NODE screen. After installing and configuring these modules, you'll be able to add child nodes directly from the node/add/PARENT-NODE screen by clicking on the "Add new: Add Child Node link", which spawns a lightbox window to add a child node.

node reference add parent node 2

Here is a screenshot of a parent node view after adding child relationships:

node reference parent node view