<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>D&#039;Arcy Norman dot net &#187; howto</title>
	<atom:link href="http://www.darcynorman.net/tag/howto/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.darcynorman.net</link>
	<description>apparently much happier in person</description>
	<lastBuildDate>Fri, 20 Nov 2009 03:52:33 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.6</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Modifying the BuddyPress AdminBar</title>
		<link>http://www.darcynorman.net/2009/11/13/modifying-the-buddypress-adminbar/</link>
		<comments>http://www.darcynorman.net/2009/11/13/modifying-the-buddypress-adminbar/#comments</comments>
		<pubDate>Fri, 13 Nov 2009 22:12:22 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[general]]></category>
		<category><![CDATA[buddypress]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=3395</guid>
		<description><![CDATA[On UCalgaryBlogs, I&#8217;d modified the adminbar to include a link to the current site&#8217;s dashboard if a person was logged in, making it easy to get to the members-only side of WordPress without having to go through My Blogs and finding the right blog, then mousing over the pop-out &#8220;Dashboard&#8221; link. Most people never found [...]]]></description>
			<content:encoded><![CDATA[<p>On UCalgaryBlogs, I&#8217;d modified the adminbar to include a link to the current site&#8217;s dashboard if a person was logged in, making it easy to get to the members-only side of WordPress without having to go through My Blogs and finding the right blog, then mousing over the pop-out &#8220;Dashboard&#8221; link. Most people never found that, and it&#8217;s not very intuitive.</p>
<p>So, I hacked in a hard-coded link to Dashboard in <code>bp-core-adminbar.php</code>. This worked, but meant I had to remember to re-hack the file after running a BuddyPress update. I forgot to do that right after I ran the last upgrade, and got emails from users asking WTF?</p>
<p>I decided to figure out the best way to add in the Dashboard link without hacking the actual plugin files. Turns out, it&#8217;s drop-dead simple. Yay, WordPress.</p>
<p>In your <code>/wp-content/plugins/</code> directory, create a file called <code>bp-custom.php</code> (if it&#8217;s not there already), and drop this code into it:</p>
<pre><code>&lt;?php
  // custom functions for tweaking BuddyPress
  function custom_adminbar_dashboard_button() {
 	// adds a "Dashboard" link to the BuddyPress admin bar if a user is logged in.
 	if (is_user_logged_in()) {
 		echo '&lt;li&gt;&lt;a href="/wp-admin/"&gt;Dashboard&lt;/a&gt;&lt;/li&gt;';
 	}
   }
  add_action('bp_adminbar_menus', 'custom_adminbar_dashboard_button', 1);
 ?&gt;</code></pre>
<p>When in place, your BuddyPress adminbar will look something like this:</p>
<p><a href="http://www.darcynorman.net/wp-content/uploads/2009/11/BuddyPress-adminbar-modified.png"><img class="alignnone size-full wp-image-3396" title="BuddyPress-adminbar-modified" src="http://www.darcynorman.net/wp-content/uploads/2009/11/BuddyPress-adminbar-modified.png" alt="BuddyPress-adminbar-modified" width="691" height="26" /></a></p>
<p>Yes, I know I should do something to properly detect user levels and privileges, rather than just providing the Dashboard link all willie-nillie to anyone that&#8217;s logged in, but the link itself just provides access to whatever Dashboard features the user is allowed to see, so there&#8217;s no security risk. Better to just say that a user can see the Dashboard for any site they&#8217;re logged into, and let WordPress deal with restricting access properly.</p>
<p>I should also deal with the possibility of WPMU being configured as a subdirectory vs. subdomain (the <code>/wp-admin/</code> link will bork if you&#8217;re using subdirectories &#8211; better to use the real code to sniff out the base url of the current site&#8230;)</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=3395" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/11/13/modifying-the-buddypress-adminbar/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>The Bike Blur Photo &#8211; behind the scenes</title>
		<link>http://www.darcynorman.net/2009/10/29/the-bike-blur-photo-behind-the-scenes/</link>
		<comments>http://www.darcynorman.net/2009/10/29/the-bike-blur-photo-behind-the-scenes/#comments</comments>
		<pubDate>Thu, 29 Oct 2009 20:10:23 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[digital photography sessions]]></category>
		<category><![CDATA[photography]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=3375</guid>
		<description><![CDATA[I was asked to share how I got that Bike Blur photo yesterday. It&#8217;s really simple, once you know a couple of tricks.


(in case the video doesn&#8217;t show up in the RSS feed, here&#8217;s the link)


 ]]></description>
			<content:encoded><![CDATA[<p>I was asked to share how I got that Bike Blur photo yesterday. It&#8217;s really simple, once you know a couple of tricks.</p>
<div align="center">
<object width="640" height="505"><param name="movie" value="http://www.youtube.com/v/xtw66a8L_zQ&#038;hl=en&#038;fs=1&#038;rel=0"></param><param name="allowFullScreen" value="true"></param><param name="allowscriptaccess" value="always"></param><embed src="http://www.youtube.com/v/xtw66a8L_zQ&#038;hl=en&#038;fs=1&#038;rel=0" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="640" height="505"></embed></object></p>
<p>(in case the video doesn&#8217;t show up in the RSS feed, <a href="http://www.youtube.com/watch?v=xtw66a8L_zQ">here&#8217;s the link</a>)</p>
<p><a href="http://www.flickr.com/photos/dnorman/4053546071/" title="clix by D'Arcy Norman, on Flickr"><img src="http://farm3.static.flickr.com/2626/4053546071_9f7d4912ca.jpg" width="500" height="333" alt="clix" /></a>
</div>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=3375" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/10/29/the-bike-blur-photo-behind-the-scenes/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>how to fix Java WebStart on MacOSX 10.5.7</title>
		<link>http://www.darcynorman.net/2009/07/23/how-to-fix-java-webstart-on-macosx-10-5-7/</link>
		<comments>http://www.darcynorman.net/2009/07/23/how-to-fix-java-webstart-on-macosx-10-5-7/#comments</comments>
		<pubDate>Thu, 23 Jul 2009 16:13:04 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[aside]]></category>
		<category><![CDATA[debugging]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[java]]></category>
		<category><![CDATA[macosx]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=3243</guid>
		<description><![CDATA[I don&#8217;t know when this broke &#8211; maybe around the time Safari 4 was released? Anyway, Java WebStart stopped working. Downloading a .jnlp file and doubleclicking it brought up an editor (Dashcode) rather than the application launched via Java WebStart. I tried using Spotlight to find &#8220;Java WebStart&#8221; so I could manually launch the app. [...]]]></description>
			<content:encoded><![CDATA[<p>I don&#8217;t know when this broke &#8211; maybe around the time Safari 4 was released? Anyway, Java WebStart stopped working. Downloading a .jnlp file and doubleclicking it brought up an editor (Dashcode) rather than the application launched via Java WebStart. I tried using Spotlight to find &#8220;Java WebStart&#8221; so I could manually launch the app. But nothing was found. WTF?</p>
<p>Apparently, <a href="http://www.wowinterface.com/forums/showthread.php?t=25333">the solution</a>, of course, is to navigate in the Finder to <code>/System/Library/CoreServices</code> and click on<code> Java WebStart.app</code> &#8211; an entirely intuitive and obvious solution. This triggers some hidden magic to somehow restore access to JWS. Who knows. It works after doing this.</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=3243" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/07/23/how-to-fix-java-webstart-on-macosx-10-5-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>BuddyPress and MultiDB</title>
		<link>http://www.darcynorman.net/2009/06/25/buddypress-and-multidb/</link>
		<comments>http://www.darcynorman.net/2009/06/25/buddypress-and-multidb/#comments</comments>
		<pubDate>Thu, 25 Jun 2009 17:56:49 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[work]]></category>
		<category><![CDATA[buddypress]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[multidb]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=3199</guid>
		<description><![CDATA[I&#8217;ve been trying to get BuddyPress working on my WPMU installation that uses MultiDB for database partitioning. It&#8217;s been cranky, but I just realized I&#8217;m a complete idiot because I was overlooking the obvious (and drop dead simple) fix.
BuddyPress was acting up because it was creating tables in each blog&#8217;s database tableset. But MultiDB makes [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.darcynorman.net/wp-content/uploads/2009/06/multidb_buddypress_config.png"><img src="http://www.darcynorman.net/wp-content/uploads/2009/06/multidb_buddypress_config-300x281.png" alt="multidb_buddypress_config" title="multidb_buddypress_config" width="300" height="281" class="alignright size-medium wp-image-3200" /></a>I&#8217;ve been trying to get BuddyPress working on my WPMU installation that uses <a href="http://premium.wpmudev.org/project/multi-db">MultiDB</a> for database partitioning. It&#8217;s been cranky, but I just realized <strong>I&#8217;m a complete idiot</strong> because I was overlooking the obvious (and drop dead simple) fix.</p>
<p>BuddyPress was acting up because it was creating tables in each blog&#8217;s database tableset. But MultiDB makes it easy to declare tables as belonging to a shared global database, so they don&#8217;t get recreated for each blog and are common across the entire service.</p>
<p>Thanks to <a href="http://premium.wpmudev.org/forums/topic/how-to-install-multi-db#post-8856">a reminder by Andrew on the premium.wpmudev.org forum</a>!</p>
<p>I edited my <code>db-config.php</code> file to declare the BuddyPress tables as being global, and copied the tables from the database where they had been collecting, into the global database.</p>
<pre><code>// BuddyPress
add_global_table('bp_activity_sitewide');
add_global_table('bp_activity_user_activity');
add_global_table('bp_activity_user_activity_cached');
add_global_table('bp_friends');
add_global_table('bp_groups');
add_global_table('bp_groups_groupmeta');
add_global_table('bp_groups_members');
add_global_table('bp_groups_wire');
add_global_table('bp_messages_messages');
add_global_table('bp_messages_notices');
add_global_table('bp_messages_recipients');
add_global_table('bp_messages_threads');
add_global_table('bp_notifications');
add_global_table('bp_user_blogs');
add_global_table('bp_user_blogs_blogmeta');
add_global_table('bp_user_blogs_comments');
add_global_table('bp_user_blogs_posts');
add_global_table('bp_xprofile_data');
add_global_table('bp_xprofile_fields');
add_global_table('bp_xprofile_groups');
add_global_table('bp_xprofile_wire');
</code></pre>
<p>It seems to be working fine. I&#8217;ll do some more testing, but it&#8217;s looking promising. If it&#8217;s really working, I&#8217;ll be spending some time to BuddyPress-enable the main theme for the WPMU service, and roll it out properly.</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=3199" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/06/25/buddypress-and-multidb/feed/</wfw:commentRss>
		<slash:comments>10</slash:comments>
		</item>
		<item>
		<title>WordPress, draft/private pages, and the parent hierarchy structure</title>
		<link>http://www.darcynorman.net/2009/03/26/wordpress-draftprivate-pages-and-the-parent-hierarchy-structure/</link>
		<comments>http://www.darcynorman.net/2009/03/26/wordpress-draftprivate-pages-and-the-parent-hierarchy-structure/#comments</comments>
		<pubDate>Thu, 26 Mar 2009 20:32:16 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[general]]></category>
		<category><![CDATA[work]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp-sentry]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=2996</guid>
		<description><![CDATA[I&#8217;m working with a class of 250+ geology undergrads, split up into 53 groups. They&#8217;re using a WordPress site to publish online presentations as the product of a semester-long group project. I&#8217;m using the great WP-Sentry plugin to let them collaboratively author the pages without worrying about other students in the class being able to [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.darcynorman.net/wp-content/uploads/2009/03/pageshierarchy.png"><img src="http://www.darcynorman.net/wp-content/uploads/2009/03/pageshierarchy-269x300.png" alt="pageshierarchy" title="pageshierarchy" width="269" height="300" class="alignright size-medium wp-image-2997" /></a>I&#8217;m working with a class of 250+ geology undergrads, split up into 53 groups. They&#8217;re using a WordPress site to publish online presentations as the product of a semester-long group project. I&#8217;m using the great <a href="http://wordpress.org/extend/plugins/wp-sentry/">WP-Sentry plugin</a> to let them collaboratively author the pages without worrying about other students in the class being able to edit their work (I know &#8211; but it makes them more comfortable so it&#8217;s a good thing to add).</p>
<p>The premise is this &#8211; I created a Page called, creatively enough, &#8220;Winter 2009&#8243; &#8211; and each of the groups is to create a page (or set of pages) and add them to the site &#8211; and selecting &#8220;Winter 2009&#8243; as the parent page for the main page of their presentation. They are free to create as many other pages as they like, and can set those to use their first page as the parent, thereby generating a table of contents.</p>
<p>Works great. Except that the WP-Sentry plugin hijacks the &#8220;Private&#8221; state of pages, and the tree of Pages available in the Parent selector is based on &#8220;Published&#8221; pages.</p>
<p>Conflict. Confusion. Frustration.</p>
<p>The students could <strong>either</strong> collaborate on the pages, <strong>or</strong> organize them in the tree structure.</p>
<p>Of course they could create the pages and add them to the tree structure and THEN enable the WP-Sentry-managed group editing controls, but <strong>YOU</strong> try explaining that process to 250 undergrads, all stressed out about building web pages as part of a geology course.</p>
<p>So&#8230; I dug into the code to see what was yanking &#8220;Private&#8221; pages from the Parent list. Turns out, it&#8217;s in <code>wp-includes/post.php</code>, waaaay down on line 2618 (as of WPMU 2.7). All I did was remove the <code>" AND post_status = 'publish'"</code> bit, and it now appears to be listing all pages.</p>
<p>I&#8217;m quite sure I borked something else, but for now I&#8217;m leaving the Parent list wide open until the students are done publishing their presentations.</p>
<p><strong>Update:</strong> Unintended consequence #242: Looks like with the tweak, Private pages show up where they&#8217;re not expected. I&#8217;m disabling the tweak for now until I can find a better way (if that&#8217;s even possible).</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=2996" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/03/26/wordpress-draftprivate-pages-and-the-parent-hierarchy-structure/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>notes on converting ucalgaryblogs.ca to use multi-db</title>
		<link>http://www.darcynorman.net/2009/03/05/notes-on-converting-ucalgaryblogsca-to-use-multi-db/</link>
		<comments>http://www.darcynorman.net/2009/03/05/notes-on-converting-ucalgaryblogsca-to-use-multi-db/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 22:39:50 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[work]]></category>
		<category><![CDATA[documentation]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=2871</guid>
		<description><![CDATA[I followed Jim&#8217;s instructions to get UCalgaryBlogs.ca converted from using a single database (as is the default) to using multiple databases (17 separate databases now) via the premium.wpmudev.org Multi-DB code to prevent growing pains. The single database config is good for getting up and running, but with 300 blogs in the system, table explosion was [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/dnorman/2269901696/" title="out with the old by D'Arcy Norman, on Flickr"><img src="http://farm3.static.flickr.com/2338/2269901696_c6b0ab28d4_m.jpg" class="alignright" width="240" height="180" alt="out with the old" /></a>I followed <a href="http://bavatuesdays.com/wpmu-multi-db-tutorial/">Jim&#8217;s instructions</a> to get UCalgaryBlogs.ca converted from using a single database (as is the default) to using multiple databases (17 separate databases now) via the <a href="http://premium.wpmudev.org/project/multi-db">premium.wpmudev.org Multi-DB code</a> to prevent growing pains. The single database config is good for getting up and running, but with 300 blogs in the system, table explosion was causing grief on the shared MySQL database server &#8211; there were almost 3000 tables, which was making the automated backup script complain a bit.</p>
<p>While reading the documentation, I was rather confused by the term &#8220;global&#8221; &#8211; which appeared to be used in slightly different ways. Eventually, I plugged through, and got it working. The key is to test it all on a local copy of the database before running the migration script on the production server. Thankfully, the script doesn&#8217;t delete anything, so I was confident that if anything borked I could just back out the multi-db files and revert to single database config without losing anything.</p>
<p>&#8220;Global Tables&#8221; are tables that will be stored in a shared, common database rather than in each blog&#8217;s database in one of the 16 databases used by the multi-db code. These are things that are accessed by all blogs on the WPMU install, and include administrative stuff.</p>
<p>In the db-config-sample-16.php file that ships with multi-db, it also mentions &#8220;global-db&#8221;, &#8220;globaluser&#8221;, and &#8220;globalpassword&#8221; &#8211; those are just the database server address, username, and password to use when connecting to the &#8220;Global&#8221; database containing the &#8220;global tables&#8221;. They used &#8220;global-&#8221; in these parameters because it&#8217;s possible to configure each of the 17 databases to use different database servers, different usernames, and different passwords. For simplicity, I used the same database server and account for all 17 databases.</p>
<p>My db-config.php file was edited as follows:</p>
<pre><code>&lt;?php
//	Plugin Name: Multi-DB
//	Plugin URI: http://premium.wpmudev.org/project/Multiple-Databases
//	Author: Andrew Billits (Incsub)
//  Version: 2.7.0
//------------------------------------------------------------------------//
//---DB Scaling-----------------------------------------------------------//
//------------------------------------------------------------------------//
//	16,256,4096
define ('DB_SCALING', '16'); // use 16 databases for the blogs
//------------------------------------------------------------------------//
//---DC IPs---------------------------------------------------------------//
//------------------------------------------------------------------------//
//	Usage: add_dc_ip(IP, DC)
//	EX: add_dc_ip('123.123.123.', 'dc1');
add_dc_ip('127.0.0.1', 'dc1'); // DN: change this to the IP address of your WEB SERVER
//------------------------------------------------------------------------//
//---Global Tables--------------------------------------------------------//
//------------------------------------------------------------------------//
//	Do not include default global tables
//	Leave off base prefix (eg: wp_)
//
//	Usage: add_global_table(TABLE_NAME)
//	EX: add_global_table('something');
// DN: These are tables that will be stored in the global database configured below (wpmu_global)
//     rather than in the 16 blog databases.
add_global_table('mass_mailer');
add_global_table('registration_log');
add_global_table('reports_comment_activity');
add_global_table('reports_post_activity');
add_global_table('reports_user_activity');
add_global_table('signups');
add_global_table('support_faq');
add_global_table('support_faq_cats');
add_global_table('support_tickets');
add_global_table('support_tickets_cats');
add_global_table('support_tickets_messages');
add_global_table('domain_mapping');
add_global_table('comment_activity');
add_global_table('blog_activity');
add_global_table('user_activity');
add_global_table('post_activity');

//------------------------------------------------------------------------//
//---DB Servers-----------------------------------------------------------//
//------------------------------------------------------------------------//
//	Database servers grouped by dataset.
//	R can be 0 (no reads) or a positive integer indicating the order
//	in which to attempt communication (all locals, then all remotes)
//
//	Usage: add_db_server(DS, DC, READ, WRITE, HOST, LAN_HOST, NAME, USER, PASS)
//	EX: add_db_server('global', 'dc1', 1, 1,'global.mysql.example.com:3509','global.mysql.example.lan:3509', 'global-db', 'globaluser',  'globalpassword');
// DN: NOTE: change 'dbserver.com' to the address of the mysql server,
//   'username' to your mysql username,
//   'password' to the appropriate password.

add_db_server('global', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_global', 'username', 'password');
add_db_server('0', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_0', 'username', 'password');
add_db_server('1', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_1', 'username', 'password');
add_db_server('2', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_2', 'username', 'password');
add_db_server('3', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_3', 'username', 'password');
add_db_server('4', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_4', 'username', 'password');
add_db_server('5', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_5', 'username', 'password');
add_db_server('6', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_6', 'username', 'password');
add_db_server('7', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_7', 'username', 'password');
add_db_server('8', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_8', 'username', 'password');
add_db_server('9', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_9', 'username', 'password');
add_db_server('a', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_a', 'username', 'password');
add_db_server('b', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_b', 'username', 'password');
add_db_server('c', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_c', 'username', 'password');
add_db_server('d', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_d', 'username', 'password');
add_db_server('e', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_e', 'username', 'password');
add_db_server('f', 'dc1', 1, 1, 'dbserver.com', 'dbserver.com', 'wpmu_f', 'username', 'password');

//
//	Note: you can also place this section in a file called db-list.php in wp-content
//  EX: add_db_server('global', 'dc1', 1, 1,'global.mysql.example.com:3509','global.mysql.example.lan:3509', 'global-db', 'globaluser',  'globalpassword');
//------------------------------------------------------------------------//
//---VIP Blogs------------------------------------------------------------//
//------------------------------------------------------------------------//
//	Usage: add_vip_blog(BLOG_ID, DS)
//	EX: add_vip_blog(1, 'vip1');
// DN: I didn't add any VIP blogs.
?&gt;</code></pre>
<p>To create the databases, I used the script at http://db-tools.wpmudev.org/db.php and it generated the code below, which I ran on the MySQL server to create the databases:</p>
<pre><code>CREATE DATABASE `wpmu_global` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_0` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_1` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_2` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_3` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_4` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_5` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_6` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_7` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_8` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_9` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_a` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_b` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_c` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_d` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_e` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
CREATE DATABASE `wpmu_f` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;</code></pre>
<p>After copying the db.php and db-config.php files into place as per Jim&#8217;s instructions, it all Just Worked™. New content was being stored in the 16 blog databases, and sites were behaving as expected, but with slightly less table explosion bloat as before.</p>
<p>One thing that makes me a little nervous is that the multi-db code isn&#8217;t core to WordPress, and is part of the premium.wpmudev.org subscription. This means that it can break in the future &#8211; there is no obligation for WordPress to continue to work with it, and if for some reason premium.wpmudev.org decides to abandon the plugin or stop updating it, I&#8217;m locked into WordPress 2.7. Neither of these made me lose too much sleep. Worst case scenario, I can always recombine the tables from all 17 databases back into a single überdatabase, assuming we haven&#8217;t outgrown the physical limits of a single MySQL database by then.</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=2871" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/03/05/notes-on-converting-ucalgaryblogsca-to-use-multi-db/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>how I move stuff between servers with rsync</title>
		<link>http://www.darcynorman.net/2009/01/07/how-i-move-stuff-between-servers-with-rsync/</link>
		<comments>http://www.darcynorman.net/2009/01/07/how-i-move-stuff-between-servers-with-rsync/#comments</comments>
		<pubDate>Wed, 07 Jan 2009 18:47:02 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[general]]></category>
		<category><![CDATA[code]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[rsync]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=2685</guid>
		<description><![CDATA[A few times on Twitter, I&#8217;ve mentioned how &#8220;easy&#8221; it is to move stuff between servers using the rsync shell command. It&#8217;s actually an extremely powerful program for synchronizing two directories &#8211; even if they&#8217;re not on the same volume, or even on the same computer. To do this, you&#8217;ll need to login to one [...]]]></description>
			<content:encoded><![CDATA[<p>A few times on Twitter, I&#8217;ve mentioned how &#8220;easy&#8221; it is to move stuff between servers using the <code>rsync</code> shell command. It&#8217;s actually an extremely powerful program for synchronizing two directories &#8211; even if they&#8217;re not on the same volume, or even on the same computer. To do this, you&#8217;ll need to login to one of the servers via SSH. Once there, invoke the geeky incantation:</p>
<pre><code>rsync -rtlzv --ignore-errors -e ssh . username@hostname:/path/to/directory</code></pre>
<p>What that basically says is, &#8220;run rsync, and tell it to recursively copy all directories, preserving file creation and modification times, maintaining proper symlinks (for aliases and stuff like that), compress the files as they&#8217;re being copied in order to save bandwidth, and provide verbose updates as you&#8217;re doing it. Use SSH as the protocol, to securely transfer stuff from the current directory to the server &#8216;<code>hostname</code>&#8216; using the username &#8216;<code>username</code>&#8216;. On that destination server, stuff the files and directories into &#8216;<code>/path/to/directory</code>&#8216;&#8221;</p>
<p>What you&#8217;ll need to change:</p>
<ul>
<li><code>.</code> &#8211; if you want to specify a full path to the source directory, put it in place of the <code>.</code> (which means &#8220;here&#8221; in shellspeak)</li>
<li><code>username</code> &#8211; unless your username on the destination server is &#8220;username&#8221; &#8211; you&#8217;ll be prompted for the password for that account after hitting return and starting the program working.</li>
<li><code>hostname</code> &#8211; the IP address or domain name of the server you want to send the files to.</li>
<li><code>/path/to/directory</code> &#8211; I&#8217;m always a bit fuzzy on this. Can it be a relative path? from where? So I just specify the full path to where I want the files to go. Something like <code>/home/dnorman/</code></li>
</ul>
<p>Because it compresses files, it&#8217;s actually pretty efficient at moving a metric boatload of stuff between servers. I&#8217;ve used this technique to easily migrate from Dreamhost to CanadianWebHosting.com and I use it regularly to move files around on campus. I use a variation of this technique to regularly backup servers as well &#8211; the beauty of rsync is that it only copies files that have been added or modified, so backing up a few gigs worth of server really only involves transferring a few megabytes of files, and can be done routinely in a matter of minutes or seconds.</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=2685" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2009/01/07/how-i-move-stuff-between-servers-with-rsync/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>how I upgrade WordPress</title>
		<link>http://www.darcynorman.net/2008/09/09/how-i-upgrade-wordpress/</link>
		<comments>http://www.darcynorman.net/2008/09/09/how-i-upgrade-wordpress/#comments</comments>
		<pubDate>Tue, 09 Sep 2008 18:08:43 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[general]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[screencast]]></category>
		<category><![CDATA[upgrade]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=2266</guid>
		<description><![CDATA[I mentioned this morning on Twitter that it took me maybe 30 seconds to upgrade my blog to the latest WordPress release. I thought it might be handy to show how I do it. I&#8217;m not sure if this follows best practices, and it might be a good idea to back stuff up before upgrading, [...]]]></description>
			<content:encoded><![CDATA[<p>I mentioned this morning on Twitter that it took me maybe 30 seconds to upgrade my blog to the latest WordPress release. I thought it might be handy to show how I do it. I&#8217;m not sure if this follows best practices, and it might be a good idea to back stuff up before upgrading, but this process has served me well for the last several versions, and it&#8217;s just so quick and painless that upgrading is trivial.</p>
<p style="text-align: center;"><a href="http://www.darcynorman.net/wp-content/uploads/2008/09/upgrading_wordpress.swf" target="_blank"><img class="size-full wp-image-2271 aligncenter" title="upgrading_wordpress" src="http://www.darcynorman.net/wp-content/uploads/2008/09/upgrading_wordpress.png" alt="" width="500" height="374" /></a></p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=2266" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2008/09/09/how-i-upgrade-wordpress/feed/</wfw:commentRss>
		<slash:comments>17</slash:comments>
		</item>
		<item>
		<title>Batch adding users to a WordPress site</title>
		<link>http://www.darcynorman.net/2008/09/08/batch-adding-users-to-a-wordpress-site/</link>
		<comments>http://www.darcynorman.net/2008/09/08/batch-adding-users-to-a-wordpress-site/#comments</comments>
		<pubDate>Mon, 08 Sep 2008 19:46:53 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[work]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[ucalgaryblogs.ca]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=2259</guid>
		<description><![CDATA[I&#8217;m working with a faculty member who is using a WordPress with his students this semester as a place for them to publish and reflect as a group. To make things easier for everyone involved, it&#8217;s a good idea to batch create user accounts for the students so they don&#8217;t have to go through that [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working with a faculty member who is using a WordPress with his students this semester as a place for them to publish and reflect as a group. To make things easier for everyone involved, it&#8217;s a good idea to batch create user accounts for the students so they don&#8217;t have to go through that process (it&#8217;s easy, but every step avoided means people are more comfortable and less aggravated with a service).</p>
<p>Do support that batch creation of users, I installed the &#8220;<a href="http://www.dagondesign.com/articles/import-users-plugin-for-wordpress/">Import Users Plugin</a>&#8221; which, surprisingly, provides a way to import users into a site. All you need to provide is a username and email address for each student and it will create the account, generate a password, assign the specified user Role, and send an email to the student so they can login. It doesn&#8217;t create blogs for each student, but for our current use-case, it&#8217;s ideal &#8211; adding users to a single blog in a WordPress Multiuser service.</p>
<p>If you need to batch create a bunch of users, first enable the &#8220;Dagon Design Import Users&#8221; plugin on your blog, then follow these instructions:</p>
<p style="text-align: center;"><a href="http://www.darcynorman.net/wp-content/uploads/2008/09/importusers.png"><img class="size-full wp-image-2260 aligncenter" title="importusers" src="http://www.darcynorman.net/wp-content/uploads/2008/09/importusers.png" alt="" width="500" height="383" /></a></p>
<p>The list of users could be pulled from Blackboard or Peoplesoft, but needs to be reformatted into</p>
<blockquote><p><code>username|email address</code></p></blockquote>
<p>structure so the plugin can make use of it.</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=2259" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2008/09/08/batch-adding-users-to-a-wordpress-site/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Creating a custom compound field for CCK</title>
		<link>http://www.darcynorman.net/2008/05/02/creating-a-custom-compound-field-for-cck/</link>
		<comments>http://www.darcynorman.net/2008/05/02/creating-a-custom-compound-field-for-cck/#comments</comments>
		<pubDate>Fri, 02 May 2008 19:17:23 +0000</pubDate>
		<dc:creator>dnorman</dc:creator>
				<category><![CDATA[work]]></category>
		<category><![CDATA[cck]]></category>
		<category><![CDATA[drupal]]></category>
		<category><![CDATA[howto]]></category>
		<category><![CDATA[views]]></category>

		<guid isPermaLink="false">http://www.darcynorman.net/?p=1924</guid>
		<description><![CDATA[I&#8217;m working on a project that partially involves the development of a website in Drupal to act as a directory of people who have graduated from a given University. Seems easy. I went into the project thinking it would be a trivial application of Taxonomies, or maybe some generic CCK fields.
Nope. Turns out the problem [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m working on a project that partially involves the development of a website in Drupal to act as a directory of people who have graduated from a given University. Seems easy. I went into the project thinking it would be a trivial application of Taxonomies, or maybe some generic CCK fields.</p>
<p>Nope. Turns out the problem is much more difficult and complex than I initially thought.</p>
<p>Taxonomies won&#8217;t work, because of the need to tie a number of values together, namely the year the degree was awarded (say, &#8220;1992&#8243;), the type of degree (say, &#8220;BSc&#8221;), the specialization of the degree (say, &#8220;Zoology&#8221;), and the granting institution (say, &#8220;University of Calgary&#8221;).</p>
<p>That could be an easy thing to solve with CCK &#8211; just add four text fields. Done.</p>
<p>BUT &#8211; people can earn more than one degree. Of different types, in different years, from different institutions.</p>
<p>Taxonomies fail. Generic CCK fields fail.</p>
<p>What I came up with is a new CCK field type, cryptically named &#8220;University Degrees&#8221;, that defines the four values that describe a degree. This solves the problem quite tidily, and supports multiple values, predefined valid sets of values, and can integrate with Views to be used as filters and sorting fields.</p>
<p>In building this module, I leaned heavily on a couple of web pages (<a href="http://drupal.org/node/106716">CCK Sample</a> and <a href="http://www.lullabot.com/articles/an_introduction_to_the_content_construction_kit">What is the Content Construction Kit?</a>) that describe how parts of the module should work, and provided some sample code. In the spirit of contributing back what I learned, I&#8217;m going to document the module to help others needing to do similar things.<br />
<span id="more-1924"></span></p>
<p>To start with, I just created a new folder to hold the module, and called it &#8220;<code>universitydegrees</code>&#8220;. Into this folder, I copied the <code>.install</code> and <code>.info</code> files from another module and customized them to suit my needs (the universitydegrees.install file doesn&#8217;t actually do anything, and the universitydegrees.info file is just for listing the module in the Drupal admin page). If you want to follow along (or use the files as a starting point to make something else) the files for my lame alpha version of the module are <a href='http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_20080402.zip'>available here</a>.</p>
<p><a href='http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegres_files.png'><img src="http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegres_files-600x234.png" alt="" title="universitydegrees files" width="600" height="234" class="alignnone size-medium wp-image-1925" /></a></p>
<p>The file where all the fun stuff happens is universitydegrees.module</p>
<p>The first method, universitydegrees_field_info(), defines how the field shows up in the CCK admin interface.</p>
<pre><code>function universitydegrees_field_info() {
  return array(
    'universitydegrees' => array('label' => 'University Degree'),
  );
}</code></pre>
<p>This method works with the <code>universitydegrees_widget_info()</code> method, and will list any available widgets under the &#8220;University Degree&#8221; field type. In this case, I just added a simple widget description, like this:</p>
<pre><code>function universitydegrees_widget_info() {
  return array(
    'universitydegrees_text' => array(
      'label' => 'University degree earned',
      'field types' => array('universitydegrees'),
    ),
  );
}</code></pre>
<p>So, a new field called &#8220;University Degree&#8221; will be available, like this:</p>
<p><a href='http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_cck_field_widget_menu.png'><img src="http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_cck_field_widget_menu.png" alt="" title="universitydegrees_cck_field_widget_menu" width="500" height="392" class="alignnone size-full wp-image-1927" /></a></p>
<p>Before actually adding the field to any content type, we need to define what data it&#8217;s going to store. This happens in the <code>universitydegrees_field_settings()</code> method:</p>
<pre><code>function universitydegrees_field_settings($op, $field) {
  switch ($op) {

    case 'save':
      return array('year', 'degreetype', 'programme', 'institution');

    case 'database columns':
      $columns = array(
        'year' => array('type' => 'int', 'not null' => TRUE, 'default' => '2008', 'sortable' => TRUE),
        'degreetype' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
        'programme' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
        'institution' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE),
      );
      return $columns;

    case 'filters':
      return array(
        'default' => array(
          'list' => '_universitydegrees_filter_handler',
          'list-type' => 'list',
          'operator' => 'views_handler_operator_or',
          'value-type' => 'array',
          'extra' => array('field' => $field),
        ),
      );
  }
}</code></pre>
<p>The <code>'save'</code> portion defines what values will be saved. The <code>'database columns'</code> portion defines the MySQL code to generate the fields in the database to store each of the values. In this case,<code> 'year'</code> will be an <code>int</code> and the remaining values will be <code>varchar(255)</code> text strings.</p>
<p>Now, to define how the widget that is used to edit the values should behave. This is the <code>universitydegrees_widget()</code> method.</p>
<pre><code>function universitydegrees_widget($op, &#038;$node, $field, &#038;$items) {
    $options_year = _universitydegrees_values_year();
	$options_degreetype = _universitydegrees_values_degreetype();
	$options_institution = _universitydegrees_values_institution();

   switch ($op) {

      case 'form':
        $form = array();
        $form[$field['field_name']] = array('#tree' => TRUE);

        if ($field['multiple']) {
          $form[$field['field_name']]['#type'] = 'fieldset';
          $form[$field['field_name']]['#description'] = t('Degrees Earned');
          $delta = 0;
          foreach (range($delta, $delta + 2) as $delta) {
			$item = $items[$delta];
			$form[$field['field_name']][$delta]['#type'] = 'fieldset';
            $form[$field['field_name']][$delta]['year'] = array(
              '#type' => 'select',
              '#title' => t('Year'),
			  '#default_value' => array_search($items[$delta]['year'], $options_year),
			  '#options' => $options_year,
            );
            $form[$field['field_name']][$delta]['degreetype'] = array(
              '#type' => 'select',
              '#title' => t('Degree Type'),
			  '#default_value' => array_search($items[$delta]['degreetype'], $options_degreetype),
			  '#options' => $options_degreetype,
              '#required' => ($delta == 0) ? $field['required'] : FALSE,
            );
            $form[$field['field_name']][$delta]['programme'] = array(
              '#type' => 'textfield',
              '#title' => t('Degree, major or concentration'),
			  '#default_value' => $items[$delta]['programme'],
              '#required' => ($delta == 0) ? $field['required'] : FALSE,
            );
            $form[$field['field_name']][$delta]['institution'] = array(
              '#type' => 'select',
              '#title' => t('School'),
			  '#default_value' => array_search($items[$delta]['institution'], $options_institution),
			  '#options' => $options_institution,
              '#required' => ($delta == 0) ? $field['required'] : FALSE,
            );
          }
        }
        else {
			$form[$field['field_name']][0]['#type'] = 'fieldset';
            $form[$field['field_name']][0]['year'] = array(
              '#type' => 'select',
              '#title' => t('Year'),
			  '#default_value' => array_search($items[0]['year'], $options_year),
			  '#options' => $options_year,
			  '#required' => $field['required'],
            );
            $form[$field['field_name']][$delta]['degreetype'] = array(
              '#type' => 'select',
              '#title' => t('Degree Type'),
			  '#default_value' => array_search($items[0]['degreetype'], $options_degreetype),
			  '#options' => $options_degreetype,
              '#required' => $field['required'],
            );
            $form[$field['field_name']][0]['programme'] = array(
              '#type' => 'select',
              '#title' => t('Degree, major or concentration'),
			  '#default_value' => $items[0]['programme'],
              '#required' => $field['required'],
            );
            $form[$field['field_name']][0]['institution'] = array(
              '#type' => 'select',
              '#title' => t('School'),
			  '#default_value' => array_search($items[0]['institution'], $options_institution),
			  '#options' => $options_institution,
              '#required' => $field['required'],
            );
        }
        return $form;

      case 'process form values':

        foreach ($items as $delta => $item) {

			// don't store empty stuff.
			if (empty($items[$delta]['year']) &#038;&#038; $delta > 0 ) {
				unset($items[$delta]);
			} else {
				// do an array lookup to store the actual value of the selection, not just the number of its index position.
				$items[$delta]['year'] = $options_year[$items[$delta]['year']];
				$items[$delta]['degreetype'] = $options_degreetype[$items[$delta]['degreetype']];
				$items[$delta]['institution'] = $options_institution[$items[$delta]['institution']];
			}
        }
  }
}</code></pre>
<p>The <code>$options_year</code>, <code>$options_degreetype</code>, and <code>$options_institution</code> variables are just calling methods that return arrays of values. I did this initially to separate the options from the various places they are used so I could change where the data comes from more easily (it&#8217;d be really cool to tie these into taxonomies or something more user-editable&#8230;)</p>
<p>The <code>'form'</code> portion generates the portion of the form that is used to edit the content associated with an instance of the field. It has two sub-portions, one for handling multiple values, and one for single values. I&#8217;m really not sure why that isn&#8217;t collapsed into a single chunk that can grok both single and multiple values, but I was following a recipe and left it that way. For now&#8230; The only portion I really cared about was the multivalue stuff anyway, because that&#8217;s how I&#8217;ll be using the content type.</p>
<p>The code for that portion defines a fieldset, called &#8220;Degrees Earned&#8221; and starts pumping out chunks of forms to present editors for each value. It creates a nested fieldset for each value, and presents a Select field for &#8220;Year&#8221;, &#8220;Degree Type&#8221; and &#8220;Institution&#8221; &#8211; and a textfield for &#8220;Degree, major or concentration&#8221;.</p>
<p>One thing that I didn&#8217;t like in the out-of-the-box widget behaviour was that it stored the index of the value, rather than the actual value itself, in the database. While that worked, it wasn&#8217;t ideal &#8211; if I changed the list of options, the index values would be invalid. So I modified the code to lookup the actual value selected and store that for the select widgets. (the <code>#default_value</code> portions of the code present the current value, if any, while editing).</p>
<p>The <code>'process form values' </code>portion does any processing of the values prior to saving in the database. This is where I convert the stored values from plain, dumb, indexes to a more meaningful text string containing the actual selection.</p>
<p>Here&#8217;s what the form looks like, with the widgets in place:</p>
<p><a href='http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_node_editing_form.png'><img src="http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_node_editing_form.png" alt="" title="universitydegrees_node_editing_form" width="493" height="359" class="alignnone size-full wp-image-1928" /></a></p>
<p>Now that we have a field defined, have provided a way to save values in the database, and described how the form widgets should behave, we need to display values on the node page. I took a shortcut and only defined a single hard-coded way to present the values. I&#8217;ll eventually work in a way to customize the display using a list of formatters. In the meantime, the <code>universitydegrees_field_formatter()</code> method handles the conversion from raw data into displayable text.</p>
<pre><code>function universitydegrees_field_formatter($field, $item, $formatter, $node) {
	$text = '';

	$text = $item['degreetype'] . ' ' . $item['programme'] . ' (' . $item['institution'] . ', ' . $item['year'] . ')';
	return $text;
}</code></pre>
<p>With the formatter in place, a node with this CCK field type will look like this:</p>
<p><a href='http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_node_display.png'><img src="http://www.darcynorman.net/wp-content/uploads/2008/05/universitydegrees_node_display.png" alt="" title="universitydegrees_node_display" width="373" height="124" class="alignnone size-medium wp-image-1929" /></a></p>
<p>And that&#8217;s it. Now, I can add a University Degree to any CCK content type, and be able to define all four values that describe a degree awarded to an individual. This pattern could easily be generalized for other compound data types, as well.</p>
<p>Next, I need to expose full Views functionality, so each value can be used for filtering and sorting Views. And, I need to provide a more flexible way to display the values, using the formatters. And, I need to abstract the lists of Years, Degrees and Institutions so that they are editable by users without having to modify the source code for the module&#8230;</p>
 <img src="http://www.darcynorman.net/wp-content/plugins/feed-statistics.php?view=1&post_id=1924" width="1" height="1" style="display: none;" />]]></content:encoded>
			<wfw:commentRss>http://www.darcynorman.net/2008/05/02/creating-a-custom-compound-field-for-cck/feed/</wfw:commentRss>
		<slash:comments>47</slash:comments>
		</item>
	</channel>
</rss>
