Tuesday, July 20, 2010

Ad Hoc Scripting for Drupal

Plenty of times I need to write a small script to get user input and then add a record to the Drupal 6 nodes.

Instead of creating a module, I can write a quick-n-dirty script to capture the user input and create the node.

One way of doing this would be to place the script in sites/scripts/ and bootstrap all the Drupal, js and css functions.

However, I have created a content type which I call 'Scripts'.

For this you need to enable the optional core module PHP filter.

Whenever I need a script, I create a new entry for it and enable PHP code under Input format.

As an example, the following is a script to insert a formatted node into a simplenews newsletter from a series of text input fields (also rendered as a script).

<?php
$tid = taxonomy_get_term_by_name('Company newsletter');
global $user;
// get the input from the form (also produced by a script)
// I have simply generated a script with the issue number,
// headers and urls submitted as text fields. I have simplified
// this for this example.
$nl=$_GET['fulltext'];
$issue=$_GET['issue'];
$urlm=explode(',',$_GET['urlm']);
array_pop($urlm);
$headers=explode(',',$_GET['headers']);
array_pop($urlm);

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create the string that will hold the content of the node.
// Basically, I'm just formatting the input recieved by the
// $_GET syntax above so that it fits into an HTML table
// for my newsletter
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

$s="<table border=\"0\" cellpadding=\"4\" cellspacing=\"4\">\n ";
$s.="<tr><td><img src=\"http://example.com/pic.jpg\"/></td><td align=\"right\">Issue ".$issue.", ".date("j F Y")."</td></tr>";
$s.="<tr>\n <td colspan=\"1\" rowspan=\"2\" valign=\"top\">\n <table border=\"1\" cellpadding=\"8\">\n <tr><td>";
foreach ($headers as $value){
$s.='<a href="#'.str_replace(' ','_',$value).'"><font face="Arial,Helvetica,sans-serif">'.$value."</font></a><hr>\n";
}
$s.="</td>\n </tr>\n </table>\n </td>\n";
for($i=0,$j=0;$i<count($nl);$i++){
$CellContent1="text for Left Cell goes here";
$CellContent2="text for Right Cell goes here";
$s.="<tr><td>$CellContent1</td><td>$CellContent2</td></tr>";
}
$s.="</table>\n";

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now to create the node.
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

$node = new StdClass();
$node->type = 'simplenews';
$node->uid = $user->uid;
$node->title = 'Company Newsletter Issue Number '.$issue;
$node->body=$s;
$node->format = 2;
$node->status = 0;
$node->taxonomy = $tid;
node_save($node);
$nodeID=$node->nid;
taxonomy_node_save($nodeID,$tid);
$query=db_query("UPDATE {simplenews_newsletters} SET s_format='html', tid=%d WHERE nid=%d",$tid[0]->tid,$nodeID);
print "go to send and edit newsletter <a href=\"http://example.com/node/".$nodeID.'/edit">here.</a>';
?>

Tuesday, September 8, 2009

Taxonomy menus and submenus

Here is a request for help that I posted on the Drupal Forums.



Currently, on Primary Links I have a menu item
which appears on my page.

I have defined a Taxonomy with Tags called My Tags

In my Views I have specified a table which has nodes with update date, title and teaser.

I have specified the validator as 'My Tags' and specified the Menu as Primary Links and in my Primary Links I have a menu item which has all the Tags (which are specified by the Author of the article and dynamically added) listed below it.

However, when I click the Menu Item it just takes me to a page which has the Tags across the top and then all articles listed below in a table.

When the user clicks one of the tags, then only those articles which have that tag are displayed.

What I want is for there to be a submenu from the Primary menu which will just display the relevant pages.

I'm not sure what I'm missing.





I solved this in two parts. Instead of setting up the Primary LInks in Drupal to use views I wrote a custom block within Drupal which directly accessed the Taxonomy Terms from the Drupal Database.

I have a series of articles in my website which are categorised by sport: football and cricket are categorised as 'Team Sports' and tennis and squash are categorised as 'Raquet Sports'.

Team Sports and Raquet Sports are defined in the Taxonomy menu under 'Content Management' in the Drupal admin using 'add vocabulary' and specifying the terms 'Team Sports' and 'Raquet Sports' by using 'add terms'.

These are saved to the Database table {term_data} with a category vid (presumably standing for 'vocabulary identity'), which, on my system is 6.

So to get a listing of all the terms in my sports category vocabulary I interrogate the database with the following query:

"SELECT tid,vid,name FROM {term_data} WHERE vid=6"
+-----+-----+----------------+
| tid | vid | name |
+-----+-----+----------------+
| 8 | 6 | Racquet Sports |
| 9 | 6 | Team Sports |
+-----+-----+----------------+


This will give my list of main menu items.

The actual sport which will appear as the submenu is also defined under the Taxonomy Administration section and is also checked as 'Required' when the Author creates his article, but in this case, the Author can enter any sport he likes, and, if the article concerns multiple sport, he may have a comma-separated list. These items will occur in the same database table under a different vid, in my case '3'.

"SELECT tid,vid,name FROM {term_data} WHERE vid=3"
+-----+-----+----------------+
| tid | vid | name |
+-----+-----+----------------+
| 2 | 3 | football |
| 3 | 3 | tennis |
| 4 | 3 | rugby |
+-----+-----+----------------+

These are linked to the articles in the {term_node} table.

SELECT * FROM {term_node} WHERE tid=9;
+-----+-----+-----+
| nid | vid | tid |
+-----+-----+-----+
| 9 | 9 | 9 |
| 44 | 44 | 9 |
| 45 | 45 | 9 |
+-----+-----+-----+

The nids are all the node identities associated with Team Sports (tid=9) and we can use them to find the submenu items.
SELECT * FROM {term_node} WHERE nid=44;
+-----+-----+-----+
| nid | vid | tid |
+-----+-----+-----+
| 44 | 44 | 2 |
| 44 | 44 | 9 |
+-----+-----+-----+

So, by using the tid from this (2) and looking at the term_data table, we can add 'Football' to the submenus below the menu item 'Team Sports'. Using PHP we can get a series of arrays holding the menu items and the submenus.

$categories=array();
$query=db_query('SELECT tid,name FROM {term_data} WHERE vid=6');
while($row=db_fetch_array($query)){//term id and name of the Main Menu Item
$node_query=db_query('SELECT nid FROM {term_node} WHERE tid=%d',$row['tid']);
$submenus=array();
while($nodes=db_fetch_array($node_query)){//node id of articles categorised as under Main Menu Item
$submenu_query=db_query('SELECT tid FROM {term_node} WHERE nid=%d',$nodes['nid']);
while($tids=db_fetch_array($submenu_query)){//term id of all categories referrenced by the article
$name_query=db_query('SELECT name FROM {term_data} WHERE tid=%d AND vid=3',$tids['tid']);
while($names=db_fetch_array($name_query)){//submenus which referrence the article and which belong to vocabulary '3'
$submenus[]=array('submenu'->$names['name'],'tid'->$tids['tid']);
}
}
}
$categories[]=array('menu'->$row['name'],'submenus'->$submenus);
}

In the second part, we need to use CSS to implement the drop down menus.

print '<style>';
for($i=0;$i<count($categories);$i++){
print '#expandamat'.$i.'{position: relative;}#expandamat'.$i.' ul li:hover ul{display: block;}#expandamat'.$i.' ul ul{display: none;}';
}
print '</style>';
$i=0;
foreach($categories as $row){
print '<div id="expandamat'.$i.'"><ul><li><a href="#" style="color: black !important;">'.$row['menu'].'</a>';
if(!empty($row['submenus'])){
print '<ul>';
$subs=$row['submenus'];
foreach($subs as $element){
print '<li><a href="http://sportsinterhost.com/content/news?sport='.$element['name'].'&tid='.$element['tid'].'">'.$element['name'].'</a></li>';
}
print '</ul>';
}
print '</li></ul></div>';
$i++;
}

The menu item requests a page and passes the name of the sport and it's term id which is then used in a query to select the relevant articles.

you can see this in action on sportsinterhosts.com

Please be aware that I am not an expert, and I would very much welcome comment.

I also acknowledge that my original question was badly couched, possibly because I did not understand the interaction between Primary menus and views.

Tuesday, July 14, 2009

Popular? or overhyped.

Drupal is one of the largest and most popular CMS (content management systems) on the web today. It appears to have flourished despite leaning on two pretty rickety columns namely PHP (the acronym stands for Personal Home Page) and MySQL, niether of which would appear to be serious products on their nomenclature.

However, and this is a serious point, in common with Drupal itself, both are unencumbered by proprietry software licenses.

Indeed, all three products are open source under a variety of licenses.

Drupal has a huge following said to include Barack Obama, Tim Berners-Lee, Canonical, Amnesty International and Greenpeace. NASA, NATO and the UN, AOL, Sun and Novell, Nike, Warner Brothers and 20th Century Fox are all likewise said to be hosting Drupal websites, as are MTV and Sony Music.

However, it is very interesting to observe the makeup of the people who use Drupal and compare them to other opensource communities, in particular those involved in the *nixes.

Linuxquestions.org is a large forum through which new users of the various distribution can detail their myriad problems in installing and tweaking the Linux distribution of their choice. In general, only a tiny fraction of these requests for help are unanswered.

In contrast up to a third of questions posed on the Drupal.org/forum remain unresponded to.

Indeed, I have personally posted some 40 queries, the vast majority of which were never answered.

Anyway, here's what I am planning to do; as I have delved into the workings of Drupal to get my own sites up and running, so I have found the answers to these questions that have remained unanswered. So, over the next few weeks I'm going to put together a series of tutorials to cover them.

But not tonight.

It's midnight. And I'm knackered.