Tuesday 28 October 2008

Drupal: Broken RSS feeds

In Drupal 5, the path www.example.com/rss.xml will produce an RSS feed of the most recent nodes (the number of items can be customised in the RSS publishing options; the default is ten), and other core modules provide feeds, such as taxonomy, via www.example.com/taxonomy/term/1/0/feed. I had a problem recently where this functionality appeared to stop working. RSS feeds would not be displayed, and a ‘page not found᾿ (404) error would appear instead.

At first, I suspected a module might have been to blame. After all, the RSS functionality worked on a simple site, but not the one I was working on, which had been customised with lots of modules. I disabled all the modules that could have possibly affected the RSS feeds, but this did not help at all.

It turns out that URL aliasing was to blame. I had inserted some rows manually into the {url_alias} table, but I had put the values into the wrong columns. The two columns in question were src and dst. The dst column is the column containing the URL the user goes to, and the src column is the one that it is aliases to, ie the ‘real’ URL. I had put the values into these columns the wrong way around, so when requesting the RSS feed's URL, Drupal was redirecting to a gibberish URL that did not exist!

Friday 24 October 2008

Drupal: Allowing users to edit roles

In Drupal 5, I needed some way of giving users with a specific role permission to set the roles of others. It turns out that by default, the administrator is the only one who can assign roles to users. I also found the user_selectable_roles module by Bacteria Man, which allows users to assign themselves roles, but this was not quite what I wanted.

After some digging around in the core, specifically user.module, I found that when the user edit page is displayed, the system checks whether the user (the user who is seeing the edit page, not the user being edited) has permission to administer access control, and if so, grants them the ability to edit roles.

It turns out that in order to edit roles, the user must be given privileges to edit the access rights of all the roles, which is not really the same thing! In my opinion, there should be sufficient granularity between assigning roles to users and deciding what permissions those roles have. Perhaps this is something for a future Drupal release? It might even exist in Drupal 6 or Drupal 7, but not having played with them yet, I don't know.

Wednesday 22 October 2008

Drupal: Search indexing manually imported nodes

Recently I was required to import about 7000 nodes into Drupal 5. I was not entirely sure how to achieve this, but I decided to use SQL scripting. As it turns out, a more proper method would have been to use a PHP script to build nodes and use node_save() to accomplish the import.

That aside, I ran into a problem where none of the manually imported nodes were appearing in search results. Nodes created within Drupal worked fine, appearing in search results as expected. My manually imported nodes worked fine on the site itself: by nagivating to node/1234 it was possible to view the node as expected, and they worked fine with Views, but there was nothing in the search results.

My first stop was to tell Drupal to regenerate the search index, by visiting admin/settings/search and using the functionality there. The correct number of nodes was reported on this page, but after clicking the reindex button and running cron.php, it reported that 97% of the nodes had been indexed. This was far too short a time for this to happen, and a quick search showed that the manually imported nodes were still not appearing in search results.

I began to speculate that because the manually imported nodes were last modified (the changed column in the database) before the last time that the indexer was run, they weren't being ‘seen’ by the indexer, since it only pays attention to things that have changed since last time.

I did try backing up the {node} table, setting the changed timestamp for all nodes to something after the last time the indexer was run, then reindexing everything again, but this seemed to make no difference. If I didn't know better, I would have said that Drupal was taking one look at the sheer amount of stuff it was going to have to index, and freaking out!

In the end, my solution was to create a simple module that took advantage of the _node_index_node() function from Drupal 6. This seemed to work with no compatibility issues (I was using Drupal 5 for this), and my simple module checked to see if the node's nid existed in the {search_dataset} table (as a sid, not a nid), and if it didn't, called _node_index_node() to forcibly index it. It was a very slow process but it appears to have done the trick.

I suppose the question I am left with after this project is: why didn't Drupal reindex these nodes? Was my suspicion about the indexer not ‘seeing’ them correct? Should one always import nodes using PHP and Drupal's node_save()? While my method works, it is cumbersome and I would always seek the most efficient way of doing this, so please leave a comment if you can elaborate on this!

Download the completed module (2K).