Auto node titles

23 views
Skip to first unread message

Stuart Ball

unread,
Oct 9, 2009, 8:06:27 AM10/9/09
to scrat...@googlegroups.com
I am designing a species account page using CCK fields (with some nod in
the direction of SPM). I want just one account per species, and the node
title to be the species name. When the page is created, the user selects
the species from a taxonomy, so I don't really want them to have to type
the name into the title field as well (and, no doubt, introduce spelling
errors which may interfere with Search finding it ...).

Enter a module called "Automatic Nodetitles"
(http://drupal.org/project/auto_nodetitle) which does exactly what I
want: for a given content type, it hides the node title in the edit form
and allows Admin to set a rule to populate it automatically. If the
Tokens module is installed (http://drupal.org/project/token), it lets
you use any available tokens for this. So, token [term-raw] does the job
I want (not sure why you need to use [term-raw] rather than [term], but
the former works and the latter doesn't!).

Anyway, all good until I noticed that when I created the node, the title
was initially blank. The species name didn't turn up as the node's title
until the node had been edited and saved. Not so good!

A bit of furkling on drupal.org showed that this is a long-standing
issue (first reported in Drupal 5). It turns out it is actually a glitch
in the Token module and a patch is available
(http://drupal.org/node/338853). However, for some reason, the fix does
not seem to have made it into the module code - even the latest
development version. The patch is for an older version, so I was unable
to get the supplied .diff file to patch the current version of
token_node.inc (i.e. from Token 6.x-1.12), but was able to apply it
manually and it is now working.

The next thing I would really like is a way to prevent people creating a
species account page if one for that species already exists. So, if the
user has gone to "Create species account" and they select "species x"
from the taxonomy, but there is already a species account for this
species, then ideally I would like it to load the existing page for
editing rather than creating a new one. Anybody got any ideas?

Stuart

_____________________________________________________________________
The Joint Nature Conservation Committee (JNCC) is the statutory adviser to Government on UK and international nature conservation, on behalf of the Council for Nature Conservation and the Countryside, the Countryside Council for Wales, Natural England and Scottish Natural Heritage. Its work contributes to maintaining and enriching biological diversity, conserving geological features and sustaining natural systems.

JNCC SUPPORT CO. Registered in England and Wales, company no. 05380206. Registered office: Monkstone House, City Road, Peterborough, Cambridgeshire PE1 1JY


This message has been checked for all known viruses by JNCC delivered through the MessageLabs Virus Control Centre. For further information visit http://www.uk.uu.net/products/security/virus/

Simon Rycroft

unread,
Oct 9, 2009, 9:44:50 AM10/9/09
to scrat...@googlegroups.com
On Fri, 2009-10-09 at 13:06 +0100, Stuart Ball wrote:
> The next thing I would really like is a way to prevent people creating
> a
> species account page if one for that species already exists. So, if
> the
> user has gone to "Create species account" and they select "species x"
> from the taxonomy, but there is already a species account for this
> species, then ideally I would like it to load the existing page for
> editing rather than creating a new one. Anybody got any ideas?

A module which implements some form of validate function is required
here. You could add the validate function to the "species account" form
using a hook_form_alter function. Then then when the form is submitted,
you can check to see if a node of type "species account" already exists
associated with the term that has been submitted, if so, add a form
error. I've no idea if you can do this without writing any code, but
given that it is only two functions it shouldn't be too hard.

Simon

--
Simon Rycroft <s.ry...@nhm.ac.uk>

Kehan Harman

unread,
Oct 9, 2009, 10:36:06 AM10/9/09
to scrat...@googlegroups.com
There's also a good module called unique_fields that lets you choose various fields within a content type (drupal core and cck, not sure about taxonomy) and specify whether those fields are unique - you can choose between unique within a content type. I've pasted it's fieldset on the edit content type form as an example below (not sure if the formatting will get garbled but holding thumbs. You can get it from http://drupal.org/project/unique_fields

Cheers,
Kehan
xxxxxxx snip xxxxxxxx

After designating that certain fields should be unique, users will not be able to submit the content form to create a new node or update an existing one if it contains values in the designated fields that duplicate others.
Choose whether the values in the specified fields must be unique among nodes of this content type, among nodes of the same language, among all nodes, or only among the fields of the present node.
For example, if you have fields for the parts of a street address (street number and name, city, and zip code) on a node, and want to allow only one node per complete address, but not only one node per city or per zip code, then you would want to choose that the fields must be unique in combination.
xxxxxxxx snip xxxxxxxx
--
kehan...@gmail.com
http://kehan.wordpress.com
skype: kehanharman
msn: kehan...@gmail.com

kehan

unread,
Oct 9, 2009, 10:38:39 AM10/9/09
to Scratchpads
There you go - it stripped the formatting, but basically indented
lines are checkboxes, everything else isn't

Stuart Ball

unread,
Oct 9, 2009, 11:10:38 AM10/9/09
to scrat...@googlegroups.com
Simon: A module which implements some form of validate function is
required here.

I had actually thought about using validation, but as far as I can see
that only kicks in when the form is submitted, which means the user has
actually typed their content - only to get it rejected. This would
certainly piss me off!!

Kehan: Unique fields (Your URL is slightly wrong - it is
http://drupal.org/project/unique_field - no "s")

I had a quick read and it looks well worth trying out. Again, it depends
on when it kicks in and objects to the new form.


I found this blog posting:
http://conceptfour.com/blog/restricing-duplicate-node-titles

The approach suggested here is a custom module to set up a menu item
"create new ..." which calls a custom form to prompts the user for their
node title (or, in my case, pick the species). It then checks whether
the node exists and redirects the user either to edit it if it does, or
add it if it doesn't. It then uses hook_form_alter() to hide the
Node.title field and to populate it with the info the user has already
entered (which it stores in a SESSION variable) so that the user does
not have to retype it (and is prevented from changing it once in the
edit/add form).

Stuart Ball

unread,
Oct 12, 2009, 7:07:01 AM10/12/09
to scrat...@googlegroups.com
Background: I am trying to build a species account page. The idea is a
custom node type ("species_account"), built using CCK, which has a
series of text fields for taxonomy and nomenclature, description,
habitat, biology, distribution, etc. (loosely based on SPM). The species
name comes from a vocabulary which contains the checklist in
hierarchical form. I want the title of the node to contain the species
name. This is hidden in the input form and automatically populated with
the term name using the "Auto node title" module so that the user just
has to select the name of the species from the taxonomy and does not
also have to type it in to the title field.

The additional point I raised last week was that I only want to allow
one account per species. So, if the user tries to create a new account
for a species for which there is already one, I want to redirect them to
edit the existing account.

I tried out the Unique fields module suggested by Kehan and found that
it essentially implements the validation function that Simon suggested -
but provides a point and click interface to set it up. It therefore
suffers from the objection I raised to Simon's suggestion: validation
does not occur until the completed form is submitted. By that time the
user may well have entered a substantial amount of text. To have their
work rejected at that stage isn't good!

So, I pursued the approach suggested in a blog post I found at
http://conceptfour.com/blog/restricing-duplicate-node-titles

I will walk you through the resulting code (much modified/simplified for
my situation).

/**
* Implements hook_menu
* Provide a menu item to add/edit species accounts
*/
function custom_menu() {
$items = array();
$items['add-vocab'] = array(
'title' => 'Add/edit species account',
'page callback' => 'custom_new_species_account',
'access arguments' => array('manage species content'),
'type' => MENU_NORMAL_ITEM,
);
return $items;
}

/**
* Page to start the process of creating a species account
*/
function custom_new_species_account() {
$output = drupal_get_form('new_species_account_form');
return $output;
}

/**
* The form to prompt user to select a species from our vocabulary (vid
= 17)
*/
function new_species_account_form() {
$form = array();
$form['tid'] = taxonomy_form(17); // this gets everything needed to
build select form item
$form['submit'] = array(
'#type' => 'submit',
'#value' => t('Continue')
);
return $form;
}

Hook_menu is used to create an "Add/edit species account" menu item (and
an access type to control access to species editing). This menu item
calls a very simple form which just allows the user to select the
species from the relevant vocabulary and then click a [Continue] button.

This turned out to be very easy. The taxonomy_form function gets
everything necessary to set up a "select" type control in the form. It
can take a number of parameters, mostly optional, but all that is needed
here is one required parameter, the ID of the vocabulary to show (vid=17
- my species checklist). You find that by looking at the vocabulary
table in the database (using phpMyAdmin or whatever database manager you
use).

When the user clicks the [Continue] button, a hook_form_submit function
gets called. This is where most of the work is done:

/**
* Check whether there is already an account for this species
* and redirect to add or edit form as appropriate
*/
function new_species_account_form_submit($form, &$form_state) {
// initialise
$tid = $form_state['values']['tid'];
$spname = '';

// query to check whether there is already a "species_account" type
node linked to the tid
$sql = 'SELECT title, {node}.nid FROM {term_node} JOIN {node} ON
{term_node}.nid = {node}.nid
WHERE tid = %d AND type = "species_account"';
$result = db_query($sql, $tid);
while ($data = db_fetch_object($result)) {
$spname = $data->title; // needed for the warning message
$nid = $data->nid; // needed to redirect to edit form
}

// Do the appropriate redirect
if ($spname) {
// found it - so show a massage to user and edit the existing
species account
$message = t('An account for ' . $spname . ' already exists.');
drupal_set_message($message, 'warning', FALSE);
$form_state['redirect'] = 'node/' . urlencode($nid) . '/edit/';
}
else {
// not found - so save tid in SESSION and redirect to add form
$_SESSION['custom'] = array('tid' => $tid);
$form_state['redirect'] = array('node/add/species-account');
}
}

First we get the ID of the species that the user selected (tid) from the
$form_state variable. Then we can query the database to find out if
there is a node of type = "species_account" linked to this tid. The two
items we need from this query, if such a node does exist, are the name
of the species (for the feedback message to the user) and the node's ID
(nid) so we can redirect to edit it.

If we found a species name - an entry already exists in the database -
then we show a message and redirect to edit the existing node (URL =
node/<nid>/edit)

If the species name remains blank - no existing entry in the database -
then we redirect the user to add a new node (URL =
'node/add/species-account' in my case). In this case, the user has
already selected the species and we don't want to make them do it again.
So we need to save the selected species ID. This can be done by putting
it in the user's $_SESSION variable. We then need to use hook_form_alter
to preselect the chosen species in the add/species-account form:

/**
* Implements hook_form_alter
* Set the default species from tid stored in SESSION
*/
function custom_form_alter(&$form, $form_state, $form_id) {
if ($form_id == 'species_account_node_form') {
// if this is a new node - preselect species (vocab 17) with the tid
from the SESSION variable
if (empty($form['#node']->nid)) {
if (!empty($_SESSION['custom']['tid'])) {
$form['taxonomy'][17]['#default_value'] =
$_SESSION['custom']['tid'];
}
}
}
}

Check whether we are using the form to add/edit a species account,
whether we are creating a new node and whether the species ID is stored
in $_SESSION. If all is OK, we set the default value for
['taxonomy'][17] to the saved tid. (Recall that 17 is the vid for the
appropriate vocabulary).

My only real problem here was finding out the internal name of the form
- which turned out to be "species_account_node_form". What I ended up
doing was to use the Drupal extension for FireBug
(https://addons.mozilla.org/en-US/firefox/addon/8370 - which also needs
the corresponding Drupal module
http://drupal.org/project/drupalforfirebug installing). Once this lot is
up and running, I added the line

firep($form_id, "Form ID");

as the first line of the custom_form_alter function. I then saw a
message in FireBug, when I visit my Drupal node/add/species-account page
showing the necessary form_id.

Finally, a bit of cleaning up:

/**
* Implements hook_init
* Clear the SESSION variable
*/
function custom_init() {
// our stored variable for new node title only lasts when going to the
next page, then it is cleared.
if (!empty($_SESSION['custom']['tid']) &&
strcmp('node/add/species-account', $GLOBALS['_GET']['q']) != 0) {
unset($_SESSION['custom']['tid']);
}
}

This clears the variable we stored in $_SESSION the next time a form is
opened that is not the node/add/species-account form - so it is not left
cluttering up the system.

This seems to do exactly what I want. The user clicks the "Add/edit
species account" menu item, chooses a species and then is redirected to
either the editing form if one exists or to the add form with the
correct species already selected so they can start entering text.

Reply all
Reply to author
Forward
0 new messages