<?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>MaisonBisson.com &#187; wordpress</title>
	<atom:link href="http://maisonbisson.com/blog/post/tag/wordpress/feed/" rel="self" type="application/rss+xml" />
	<link>http://maisonbisson.com</link>
	<description>A bunch of stuff I would have emailed you about.</description>
	<lastBuildDate>Sat, 14 Nov 2009 20:14:03 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.5.2</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>My WordCamp NYC Talks</title>
		<link>http://maisonbisson.com/blog/post/14151/my-wordcamp-nyc-talks/</link>
		<comments>http://maisonbisson.com/blog/post/14151/my-wordcamp-nyc-talks/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 20:13:44 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[presentation]]></category>
		<category><![CDATA[scriblio]]></category>
		<category><![CDATA[WordCamp]]></category>
		<category><![CDATA[WordCamp NYC]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14151</guid>
		<description><![CDATA[

Authentication Hacks
My first talk was on User Authentication with MU in Existing Ecosystems, all about integrating WP with LDAP/AD/CAS and other directory authentication schemes, as well as the hacks I did to make that integration bi-directional and deliver new user features. My slides are online (.MOV / .PDF), and you can read earlier blog post [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14151"><!-- &nbsp; --></abbr>
<p><a title="WordCampNYC – Nov 14-15" href="http://2009.newyork.wordcamp.org"><img class="alignright" src="http://2009.newyork.wordcamp.org/files/2009/10/wcnyc-speaking-250.jpg" alt="WordCampNYC – Nov 14-15" width="250" height="250" /></a></p>
<h3 id="14151_authentication-hacks_1">Authentication Hacks</h3>
<p>My first talk was on <a href="http://2009.newyork.wordcamp.org/2009/11/01/hacking-authentication/">User Authentication with MU in Existing Ecosystems</a>, all about integrating WP with LDAP/AD/CAS and other directory authentication schemes, as well as <a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/">the hacks I did to make that integration bi-directional</a> and deliver new user features. My slides are online (<a href="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Authentication-2009Nov13.mov">.MOV</a> / <a href="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Authentication-2009Nov13.pdf">.PDF</a>), and you can read earlier <a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/">blog post summing up the project</a>.</p>
<h4 id="14151_plugins-mentioned_1">Plugins Mentioned</h4>
<ul>
<li><a href="http://wordpress.org/extend/plugins/wpcas/">wpCAS</a> (<a href="http://maisonbisson.com/projects/wpcas/">long description</a>)</li>
<li><a href="http://wordpress.org/extend/plugins/alternate-contact-info/">Alternate Contact Info</a></li>
<li><a href="http://wordpress.org/extend/plugins/wp-ticket-framework/">WordPress Ticket Framework</a></li>
<li><a href="http://wordpress.org/extend/plugins/wpsms/">wpSMS</a> (<a href="http://maisonbisson.com/projects/wpsms/">long description</a>)</li>
</ul>
<h3 id="14151_scriblio_1">Scriblio</h3>
<p>I was most excited, however, to talk about <a href="http://about.scriblio.net/">Scriblio</a>, a plugin that turns WordPress into a library catalog with faceted searching and browsing. Those slides are online as well (<a href="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Scriblio-2009Nov13.mov">.MOV</a> / <a href="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Scriblio-2009Nov13.pdf">.PDF</a>). The <a href="http://wordpress.org/extend/plugins/scriblio/">core plugin is in the repository</a>, but I&#8217;d recommend people <a href="http://groups.google.com/group/scriblio/">join the mail list</a> if they&#8217;re thinking of diving in to it.</p>
<h4 id="14151_scriblio-sites-i-dem_1">Scriblio Sites I Demoed</h4>
<ul>
<li><a href="http://collingswoodlib.org/">Collingswood Public Library</a></li>
<li><a href="http://archives.colby-sawyer.edu/">Colby-Sawyer College Archives</a></li>
<li><a href="http://beyondbrownpaper.plymouth.edu/browse">Beyond Brown Paper photo archive</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14151/my-wordcamp-nyc-talks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
<enclosure url="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Authentication-2009Nov13.mov" length="19541483" type="video/quicktime" />
<enclosure url="http://oz.plymouth.edu/~cbisson/presentations/WordCampNYC-Scriblio-2009Nov13.mov" length="29105170" type="video/quicktime" />
		</item>
		<item>
		<title>Spell Checking</title>
		<link>http://maisonbisson.com/blog/post/14163/spell-checking/</link>
		<comments>http://maisonbisson.com/blog/post/14163/spell-checking/#comments</comments>
		<pubDate>Thu, 12 Nov 2009 15:03:37 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[After the Deadline]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[dictionary]]></category>
		<category><![CDATA[online dictionaries]]></category>
		<category><![CDATA[Spell checker]]></category>
		<category><![CDATA[spell checking]]></category>
		<category><![CDATA[spelling]]></category>
		<category><![CDATA[Wordnik]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14163</guid>
		<description><![CDATA[
Matt demanded accent-aware spell checking for the WordPress spell checking plugin his company acquired earlier this year. And just a little more than a month later, After the Deadline delivered. Now Beyoncé, café, coöperate, and even my resumé look prettier.
Separately, Wordnik offers a new take on online dictionaries, and they just launched an API.
]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14163"><!-- &nbsp; --></abbr>
<p><a href="http://blog.afterthedeadline.com/2009/09/24/top-ignored-phrases-on-wordpress-com/#comment-229">Matt demanded accent-aware spell checking</a> for the <a href="http://wordpress.org/extend/plugins/after-the-deadline/">WordPress spell checking plugin</a> his company acquired earlier this year. And just a little more than a month later, <a href="http://blog.afterthedeadline.com/2009/11/10/accent-your-writing-with-atd/">After the Deadline delivered</a>. Now Beyoncé, café, coöperate, and even my resumé look prettier.</p>
<p>Separately, <a href="http://www.wordnik.com/">Wordnik</a> offers a new take on online dictionaries, and they just launched <a href="http://docs.wordnik.com/">an API</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14163/spell-checking/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>The WordPress Way</title>
		<link>http://maisonbisson.com/blog/post/14138/the-wordpress-way/</link>
		<comments>http://maisonbisson.com/blog/post/14138/the-wordpress-way/#comments</comments>
		<pubDate>Tue, 06 Oct 2009 14:42:18 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[coding]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[links]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14138</guid>
		<description><![CDATA[
Plugin Development
Will Norris&#8216; talk at WordCamp PDX introduces WordPress coding standards, common functions, and constants to would be plugin developers (and smacks those who&#8217;ve already done it wrong). Also notable: functions, classes, variables, and constants in the WordPress trunk.
Custom Installations
Just as WordPress has a number of hooks and filters that plugins can use to modify [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14138"><!-- &nbsp; --></abbr>
<h3 id="14138_plugin-development_1">Plugin Development</h3>
<p><a href="http://willnorris.com/">Will Norris</a>&#8216; talk at <a href="http://www.wordcampportland.org/">WordCamp PDX</a> introduces <a title="Will Norris: How NOT to Build a WordPress Plugin « WordPress.tv" href="http://wordpress.tv/2009/09/20/will-norris-building-plugins-portland09/">WordPress coding standards, common functions, and constants</a> to would be plugin developers (and smacks those who&#8217;ve already done it wrong). Also notable: <a title="PHP Cross Reference (PHPXref) of: WordPress Trunk - Provided by Yoast" href="http://xref.yoast.com/trunk/nav.html?_functions/index.html">functions</a>, <a title="PHP Cross Reference (PHPXref) of: WordPress Trunk - Provided by Yoast" href="http://xref.yoast.com/trunk/nav.html?_classes/index.html">classes</a>, <a title="PHP Cross Reference (PHPXref) of: WordPress Trunk - Provided by Yoast" href="http://xref.yoast.com/trunk/nav.html?_variables/index.html">variables</a>, and <a title="PHP Cross Reference (PHPXref) of: WordPress Trunk - Provided by Yoast" href="http://xref.yoast.com/trunk/nav.html?_constants/index.html">constants</a> in the WordPress trunk.</p>
<h3 id="14138_custom-installations_1">Custom Installations</h3>
<p>Just as WordPress has a number of hooks and filters that plugins can use to modify and extend behavior, it also has <a title="Automating WordPress customizations – the install.php way « WordPress Bits" href="http://wpbits.wordpress.com/2007/08/10/automating-wordpress-customizations-the-installphp-way/">a cool way to customize the installation process</a>.</p>
<h3 id="14138_extending-the-wysiwy_1">Extending The WYSIWYG Editor</h3>
<p><a title="TinyMCE - Home" href="http://tinymce.moxiecode.com/">TinyMCE</a>, the WYSIWYG editor in WordPress has a rich API to allow adding buttons and stuff, but <a href="http://tinymce.moxiecode.com/documentation.php">the docs are hard to get into</a>. We can get a jump on that by looking at how it&#8217;s implemented in other WP plugins.  <a title="/vipers-video-quicktags/trunk/resources/tinymce3/editor_plugin.js – WordPress Plugin Repository" href="http://plugins.trac.wordpress.org/browser/vipers-video-quicktags/trunk/resources/tinymce3/editor_plugin.js">This code creates the buttons</a>, while the function that <a title="/vipers-video-quicktags/trunk/vipers-video-quicktags.php – WordPress Plugin Repository" href="http://plugins.trac.wordpress.org/browser/vipers-video-quicktags/trunk/vipers-video-quicktags.php#L658">responds to the button click and does the work</a> is defined within the plugin. The <a title="/tags/2.8.4/wp-includes/js/tinymce/plugins – WordPress Trac" href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-includes/js/tinymce/plugins">TinyMCE plugins in core</a> are also informative.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14138/the-wordpress-way/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Hacking WordPress Login and Password Reset Processes For My University Environment</title>
		<link>http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/</link>
		<comments>http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/#comments</comments>
		<pubDate>Tue, 29 Sep 2009 16:16:16 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[CAS]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[identity]]></category>
		<category><![CDATA[identity management]]></category>
		<category><![CDATA[idm]]></category>
		<category><![CDATA[login]]></category>
		<category><![CDATA[single sign on]]></category>
		<category><![CDATA[university portal]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[WordPress MU]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14110</guid>
		<description><![CDATA[
ny university worth the title is likely to have a very mixed identity environment. At Plymouth State University we&#8217;ve been pursuing a strategy of unifying identity and offering single sign-on to web services, but an inventory last year still revealed a great number of systems not integrated with either our single sign-on (AuthN) or authorization [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14110"><!-- &nbsp; --></abbr>
<div class="contents innerindex"><h3>Contents</h3><ol><li><a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/#14110_platform-choices_1">Platform Choices</a></li><li><a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/#14110_our-needs-vs-wordpre_1">Our Needs vs. WordPress</a></li><li><a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/#14110_what-we-did_1">What We Did</a></li><li><a href="http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/#14110_what-it-looks-like_1">What It Looks Like</a></li></ol></div>Any university worth the title is likely to have a very mixed identity environment. At <a href="http://www.plymouth.edu/">Plymouth State University</a> we&#8217;ve been pursuing a strategy of unifying identity and offering single sign-on to web services, but an inventory last year still revealed a great number of systems not integrated with either our single sign-on (<a title="Authentication - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Authentication">AuthN</a>) or authorization systems (<a title="Authorization - Wikipedia, the free encyclopedia" href="http://en.wikipedia.org/wiki/Authorization">AuthZ</a>, see <a href="http://en.wikipedia.org/wiki/Authentication#Authentication_vs._authorization">difference</a>). And in addition to the many application/system specific stores of identity information (even for those systems integrated into our single sign-on environment), we also use both LDAP and AD (which we try to synchronize at the application level). Worst of all, the entire environment is provisioned solely from our <a href="http://en.wikipedia.org/wiki/Management_information_system">MIS database</a>, which is good if you want to make sure that students and faculty get user accounts, but bad if you want to provision an account for somebody who doesn&#8217;t fit into one of those roles.</p>
<p>The one way relationship between our user accounts and the MIS database also makes it difficult to engage with new users online. If you can&#8217;t get an account until you become a student, how do you allow potential students to apply online if all your systems are integrated with single sign-on? And if you can&#8217;t authenticate the online identity of your users, how do you set initial passwords into your system? Or allow them to reset a forgotten password online?</p>
<p>Internet companies never struggled with this issue, as their customers could only approach them online, but most universities built systems around paper applications and have fond (and relatively recent) memories of offering their students their first internet experience. It&#8217;s still not unusual for universities to offer their students their campus computing account with a default password based on supposedly secret data shared between the user and the school. But your SSN, birth date, and mother&#8217;s name are no longer secret. A proposed change in FERPA policy (see the <a href="http://edocket.access.gpo.gov/2008/pdf/E8-5790.pdf">the top of page 15586 in the NPRM</a>) would have barred the use of “a common form user name (e.g., last name and first name initial) with date of birth or SSN, or a portion of the SSN, as an initial password to be changed upon first use of the system” in systems that store academic data. The final rule excluded that provision, much to the relief of those schools with more lobbying clout than brains.</p>
<p><span id="more-14110"></span></p>
<h3 id="14110_platform-choices_1">Platform Choices</h3>
<p>Rather than wait to see how the ruling played out last year, we went to work trying to improve security while easing access to our systems (no, that is not self-contradictory). Our challenges were thus:</p>
<ul>
<li>Fix initial password assignment</li>
<li>Fix password resets</li>
<li>Allow users with a loose or undefined relationship to the institution to create limited accounts for the purpose of interacting with the institution or its members</li>
</ul>
<p>We considered a number of paths to a solution, including hacking of our university portal (which hosts the CAS single sign-on in our environment), expansion of a limited home-built solution, and a review of commercial and open source products and frameworks. We simplified the problem by confirming that the FERPA rule did not require us to authenticate the “real life” identity of a person; rather, we had only to validate the online identity of a person (saving us from needing to do things like send confirmation PINs by postal mail to a person&#8217;s home address).</p>
<p>In the end, we chose WordPress MU. Significant factors were our experience with the software (all the MIS developers use it personally), the extensibility of it as an application platform, the development focus on user experience (especially in recent versions), and our interest in using it as a framework for other user-facing services (especially BuddyPress).</p>
<h3 id="14110_our-needs-vs-wordpre_1">Our Needs vs. WordPress</h3>
<ul>
<li>The system must serve as the front end to our single sign-on environment, using our AD and LDAP password stores to authenticate users who have accounts in those systems.</li>
<li>External email addresses, once verified with some challenge/response, can be used to reset a password.</li>
<li>Users who are presently affiliated with the school have a school-provided email address, but no external address with which to reset their lost passwords.</li>
<li>Users who are not presently affiliated with the school have no school-provided email address, and must verify their external email address before their account is activated. They can then set their own password once they verify their email address.</li>
<li>The ability to send password reset codes via SMS would be nice (especially considering the number of long-time employees of the university who do not have personal email accounts), though that also requires the verification of the user&#8217;s cell phone number.</li>
</ul>
<p>After reviewing what we wanted to do, we surveyed WordPress&#8217; code to develop an implementation plan. And, because a number of aspects of our application process were changing, we decided to focus on allowing current users to self-reset their password and postpone development of account self-creation features for new users. Still, a few issues quickly emerged:</p>
<ul>
<li>WordPress requires a username be assigned to each user, rather than relying on email address (this is <a href="http://core.trac.wordpress.org/ticket/9568">likely to change in WP 2.9</a>) Creating a new username for our users is unacceptable, but adding a large number of new users to our existing username space will quickly deplete the “good” usernames. And changing a user&#8217;s username as their affiliation with the institution is unacceptable.</li>
<li>The <a href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-includes/pluggable.php#L456">core user authentication function</a> can be replaced with our own function. (And in 2.8 it became filterable)</li>
<li><a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wp-admin/includes/mu.php#L250">WordPress MU will validate email addresses</a>, but the system isn&#8217;t built to be extensible.</li>
<li>WordPress only stores <a href="http://codex.wordpress.org/Database_Description#Table:_wp_users">one email address per user</a>, but the <a href="http://codex.wordpress.org/Function_Reference/update_usermeta">user meta system</a> can be used to store a second one. Unfortunately (and in a manner inconsistent with post meta), <a href="http://core.trac.wordpress.org/ticket/7540">only one value per meta key per user is allowed</a>, making it difficult to allow users to have an arbitrary number of email addresses associated with their account.</li>
<li>The function that <a href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-includes/pluggable.php#L211">identifies a user by a given email address</a> can be replaced with a function that also checks the secondary address.</li>
<li><a href="http://codex.wordpress.org/Users_Your_Profile_SubPanel">WordPress user profiles</a> have no phone field, but the user meta system can be used to store one. A function to identify a user by a given phone number must also be created.</li>
<li>Unlike <a href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-admin/options-privacy.php">some settings pages</a>, the fields on the user profile editor cannot be changed simply by modifying the <code>$wp_settings_fields</code> array.</li>
<li>Upon doing a password reset, the user is <a href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-login.php#L203">sent a temporary password</a>, rather than being allowed to set a new password. This contradicts University policy about how passwords are used and communicated and could train users that sending passwords by mail is acceptable.</li>
<li>The various functions in <code><a href="http://core.trac.wordpress.org/browser/tags/2.7/wp-login.php">wp-login.php</a></code> <em>cannot</em> be replaced, and in WP 2.7 the code had no way to add or replace various login actions (<a href="http://core.trac.wordpress.org/browser/tags/2.8.4/wp-login.php#L307">WP 2.8 changed that</a>).</li>
<li><a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wp-includes/wpmu-functions.php">WPMU-specific functions</a> don&#8217;t always follow WP coding standards or models.</li>
</ul>
<p>(Note that we began our work and deployed the system under WPMU 2.7. WPMU 2.8 included a few changes that made the process easier. I&#8217;m proud to say that some of those changes were a result of code we offered back to WP during our development.)</p>
<h3 id="14110_what-we-did_1">What We Did</h3>
<ul>
<li>We decided that email addresses (both PSU addresses and external addresses), as well as PSU usernames would be acceptable identifiers for an account, and that a person should be able to log in to our web services using any of those identifiers. So&#8230;</li>
<li>We replaced <code>wp_autenticate()</code> with our own function that accepts either email address or university username, checks to see if the user exists locally, checks to see if they exist in AD or LDAP, confirms their password, provisions their WordPress account (for university users who&#8217;ve not logged in via this method yet), establishes a session with our university portal and redirects them there (unless $redirect is set to something more specific that the dashboard).</li>
<li>We decided to replace WordPress&#8217; usernames with a random string matching a pattern we established. This became the WPID. Doing this required us to hide references to username (easy if you set a preferred display name)</li>
<li>To store phone numbers and secondary email addresses, and allow users to edit those within their profile, I created the <a href="http://wordpress.org/extend/plugins/alternate-contact-info/">Alternate Contact Info plugin</a> (<a href="http://plugins.trac.wordpress.org/browser/alternate-contact-info/trunk/altcontact.php">browse source</a>). This requires more use of <a href="http://php.net/ob_start">output buffering</a> than I&#8217;d like, but it gets the job done.</li>
<li>To confirm email addresses and phone numbers via a challenge/response message (and support other interactions), I created the <a title="WordPress › WordPress Ticket Framework « WordPress Plugins" href="http://wordpress.org/extend/plugins/wp-ticket-framework/">WordPress Ticket Framework plugin</a> (<a href="http://maisonbisson.com/blog/post/13862/wordpress-action-ticketing-api/">my introduction</a>, <a title="/wp-ticket-framework/trunk/ticket-framework.php – WordPress Plugin Repository" href="http://plugins.trac.wordpress.org/browser/wp-ticket-framework/trunk/ticket-framework.php">browse source</a>).</li>
<li>To send messages via SMS, we used my <a title="» wpSMS MaisonBisson.com" href="http://maisonbisson.com/projects/wpsms/">wpSMS plugin</a> (<a title="WordPress › wpSMS « WordPress Plugins" href="http://wordpress.org/extend/plugins/wpsms/">in the plugin directory</a>, <a title="/wpsms/trunk/wpsms.php – WordPress Plugin Repository" href="http://plugins.trac.wordpress.org/browser/wpsms/trunk/wpsms.php">browse source</a>).</li>
<li><a href="http://borkweb.com/">Matther Batchelder</a> <a href="https://connect.plymouth.edu/wp-login.php">re-skinned the login screen</a> via a plugin that inserts our custom CSS.</li>
<li>After determining that our university portal could not be made to authenticate via CAS, I gave up work on my <a href="http://plugins.trac.wordpress.org/browser/wpcas-server/trunk/wpcas-server.php">wpCAS Server plugin</a> and developed another method to initiate the portal session (which then establishes a CAS session using the portal&#8217;s CAS server).</li>
<li>We replaced most of the functionality of the <code>wp-login.php</code> page (by hacking core at first, then taking advantage of the action hook in 2.8). In doing so we were able to change the password reset behavior to allow users to immediately change their password after entering their reset code (which was sent to their email address or phone via SMS).</li>
</ul>
<p>Over time we extended the system to <a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/">host multiple domains</a> and <a href="http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/">replace our CMS</a>. Soon we&#8217;ll consolidate our  <a href="http://blogs.plymouth.edu/">public blogging instance</a> into it, and we&#8217;re building an invite system that we can use to invite people to join our community.</p>
<h3 id="14110_what-it-looks-like_1">What It Looks Like</h3>
<p><div id="attachment_14121" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/login.png"><img class="size-medium wp-image-14121" src="http://maisonbisson.com/files/2009/09/login-300x159.png" alt="The re-skinned WordPress login" width="300" height="159" /></a><p class="wp-caption-text">The re-skinned WordPress login</p></div>
<div id="attachment_14122" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/password-recovery.png"><img class="size-medium wp-image-14122" src="http://maisonbisson.com/files/2009/09/password-recovery-300x179.png" alt="Entering an email address or username to get a password reset code" width="300" height="179" /></a><p class="wp-caption-text">Entering an email address or username to get a password reset code</p></div>
<div id="attachment_14129" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/sms-text.PNG"><img class="size-medium wp-image-14129" src="http://maisonbisson.com/files/2009/09/sms-text-300x126.PNG" alt="SMS text with password reset code" width="300" height="126" /></a><p class="wp-caption-text">SMS text with password reset code</p></div>
<div id="attachment_14123" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/password-reset.png"><img class="size-medium wp-image-14123" src="http://maisonbisson.com/files/2009/09/password-reset-300x268.png" alt="Enter the password reset code from the SMS text message here, or follow the link from the email" width="300" height="268" /></a><p class="wp-caption-text">Enter the password reset code from the SMS text message here, or follow the link from the email</p></div>
<div id="attachment_14124" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/personal-profile.png"><img class="size-medium wp-image-14124" src="http://maisonbisson.com/files/2009/09/personal-profile-300x201.png" alt="Your extended contact information in the WordPress profile" width="300" height="201" /></a><p class="wp-caption-text">Extended contact information in the WordPress profile</p></div>
<p>And that&#8217;s how we replaced our authentication system with WordPress, gained self-service password resets, and built the foundation to invite new users into our system.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14110/wordpress-user-authentication-hacks/feed/</wfw:commentRss>
		<slash:comments>7</slash:comments>
		</item>
		<item>
		<title>WordPress Hacks: Nested Paths For WPMU Blogs</title>
		<link>http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/</link>
		<comments>http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/#comments</comments>
		<pubDate>Tue, 15 Sep 2009 16:23:10 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Libraries & Networked Information]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[hack]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[information architecture]]></category>
		<category><![CDATA[url path]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[WordPress MU]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14052</guid>
		<description><![CDATA[
Situation: you&#8217;ve got WordPress Multi-User setup to host one or more domains in sub-directory mode (as in site.org/blogname), but you want a deeper directory structure than WPMU allows&#8230;something like the following examples, perhaps:

site.org/blogname1
site.org/departments/blogname2
site.org/departments/blogname3
site.org/services/blogname3

The association between blog IDs and sub-directory paths is determined in wpmu-settings.php, but the code there knows nothing about nested paths. So a [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14052"><!-- &nbsp; --></abbr>
<p><strong><span style="font-weight: normal"><div class="contents innerindex"><h3>Contents</h3><ol><li><a href="http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/#14052_hack-the-path-mappin_1">Hack The Path Mapping</a><ol><li><a href="http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/#14052_optimization-note_1">Optimization note</a></li></ol></li><li><a href="http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/#14052_setting-up-new-blogs_1">Setting Up New Blogs</a></li><li><a href="http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/#14052_hack-the-htaccess_1">Hack The .htaccess</a></li></ol></div></span>Situation:</strong> you&#8217;ve got WordPress Multi-User setup to <a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/">host one or more domains</a> in sub-directory mode (as in <code>site.org/blogname</code>), but you want a deeper directory structure than WPMU allows&#8230;something like the following examples, perhaps:</p>
<ul>
<li><code>site.org/blogname1</code></li>
<li><code>site.org/departments/blogname2</code></li>
<li><code>site.org/departments/blogname3</code></li>
<li><code>site.org/services/blogname3</code></li>
</ul>
<p>The association between blog IDs and sub-directory paths is determined in <a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wpmu-settings.php"><code>wpmu-settings.php</code></a>, but the code there knows nothing about nested paths. So a person planning to use WordPress MU as a CMS must either flatten his/her information architecture, or do some hacking.<br />
<span id="more-14052"></span><br />
<strong>Challenge: hacking WordPress MU to support arbitrary directory paths for each blog<br />
</strong></p>
<p>As with my <a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/">multi-domain hack</a>, the following assumes that you’re using the <code>vhost=no</code> setting, that you have access to and know how to manipulate your MySQL, that you have control over your DNS and know how to use it, and that you know how to configure Apache or similar. You’d also be smart to turn off any object caching you may have running, at least until we’re done doing direct database manipulation. The following also assumes that your <code>wp-config.php</code> sets the <code>DOMAIN_CURRENT_SITE</code> and <code>PATH_CURRENT_SITE</code> constants &#8212; if you&#8217;ve done a fresh install recently, it probably does, or you can <a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_reconfigure-wp-confi_1">check my domain mapping hack</a>.</p>
<h3 id="14052_hack-the-path-mappin_1">Hack The Path Mapping</h3>
<p>Right at the top of <a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wpmu-settings.php#L28"><code>wpmu-settings.php</code></a> you can see how it strips all but the base of the URL path, but rather than mod that file, we can take advantage of an obscure MU hack: <code>sunrise.php</code>, which gets executed after some important WordPress components like the database class get loaded and before <a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wpmu-settings.php"><code>wpmu-settings.php</code></a>. </p>
<p>To use <code>sunrise.php</code>, create a PHP file at <code>/wp-content/sunrise.php</code> and set <code>define('SUNRISE', TRUE);</code> in your <code>wp-config.php</code>.</p>
<p>Here&#8217;s the <code>sunrise.php</code> code I&#8217;m using:</p>
<pre class="brush: php;">if( defined( 'DOMAIN_CURRENT_SITE' ) &amp;&amp; defined( 'PATH_CURRENT_SITE' ) ) {
	$current_site-&gt;id = (defined( 'SITE_ID_CURRENT_SITE' ) ? constant('SITE_ID_CURRENT_SITE') : 1);
	$current_site-&gt;domain = $domain = DOMAIN_CURRENT_SITE;
	$current_site-&gt;path  = $path = PATH_CURRENT_SITE;
	if( defined( 'BLOGID_CURRENT_SITE' ) )
		$current_site-&gt;blog_id = BLOGID_CURRENT_SITE;

	$url = parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH );

	$patharray = (array) explode( '/', trim( $url, '/' ));
	$blogsearch = '';
	if( count( $patharray )){
		foreach( $patharray as $pathpart ){
			$pathsearch .= '/'. $pathpart;
			$blogsearch .= $wpdb-&gt;prepare(&quot; OR (domain = %s AND path = %s) &quot;, $domain, $pathsearch .'/' );
		}
	}

	$current_blog = $wpdb-&gt;get_row( $wpdb-&gt;prepare(&quot;SELECT *, LENGTH( path ) as pathlen FROM $wpdb-&gt;blogs WHERE domain = %s AND path = '/'&quot;, $domain, $path) . $blogsearch .'ORDER BY pathlen DESC LIMIT 1');

	$blog_id = $current_blog-&gt;blog_id;
	$public  = $current_blog-&gt;public;
	$site_id = $current_blog-&gt;site_id;
	$current_site = sl_get_current_site_name( $current_site );
}

function sl_get_current_site_name( $current_site ) {
	global $wpdb;
	$current_site-&gt;site_name = wp_cache_get( $current_site-&gt;id . ':current_site_name', &quot;site-options&quot; );
	if ( !$current_site-&gt;site_name ) {
		$current_site-&gt;site_name = $wpdb-&gt;get_var( $wpdb-&gt;prepare( &quot;SELECT meta_value FROM $wpdb-&gt;sitemeta WHERE site_id = %d AND meta_key = 'site_name'&quot;, $current_site-&gt;id ) );
		if( $current_site-&gt;site_name == null )
			$current_site-&gt;site_name = ucfirst( $current_site-&gt;domain );
		wp_cache_set( $current_site-&gt;id . ':current_site_name', $current_site-&gt;site_name, 'site-options');
	}
	return $current_site;
}</pre>
<p>The first few lines of the code do pretty much the same as the start of the <a href="http://trac.mu.wordpress.org/browser/tags/2.8.4a/wpmu-settings.php#L44"><code>wpmu_current_site()</code></a> function in <code>wpmu-settings.php</code>, but starting with line 8 it takes a big departure.</p>
<p>That&#8217;s where it splits the requested URL path like <code>/path/to/blog/and/stuff/</code> into pieces and constructs an SQL query against the <code>wp_blogs</code> table to identify the correct blog to serve the request. The following example shows how:</p>
<pre class="brush: sql;">SELECT *, LENGTH( path ) as pathlen
	 FROM wp_blogs
	 WHERE domain = 'domain.org' AND path = '/'&quot;
	  	 OR (domain = 'domain.org' AND path = '/path/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/and/')
	 	 OR (domain = 'domain.org' AND path = '/path/to/blog/and/stuff/')
	 ORDER BY pathlen DESC
	 LIMIT 1</pre>
<h4 id="14052_optimization-note_1">Optimization note</h4>
<p>Setting a maximum depth (and <code>array_slice( $patharray, 0, $maxdepth )</code>) would allow the query to be cached up to that depth. Otherwise, the query must be executed for every page load. The <code>$maxdepth</code> could either be set arbitrarily, or could be determined automatically based on the maximum path length of registered blogs.</p>
<h3 id="14052_setting-up-new-blogs_1">Setting Up New Blogs</h3>
<p>Once you&#8217;ve hacked the path mapping (and tested that it didn&#8217;t break your current site), you can add a new blog at a nested path.</p>
<div id="attachment_14063" class="wp-caption aligncenter" style="width: 553px"><a href="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.37.24-AM.png"><img src="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.37.24-AM.png" alt="Create a new blog in the MU blog admin." width="543" height="235" class="size-full wp-image-14063" /></a><p class="wp-caption-text">Create a new blog in the MU blog admin.</p></div>
<p>Unfortunately, MU strips the slashes from the URL path you just tried to set.</p>
<div id="attachment_14064" class="wp-caption aligncenter" style="width: 499px"><a href="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.39.02-AM.png"><img src="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.39.02-AM.png" alt="The new blog you just tried to create, but with a very different path." width="489" height="125" class="size-full wp-image-14064" /></a><p class="wp-caption-text">The new blog you just tried to create, but with a very different path.</p></div>
<p>Fortunately, you can set the path correctly in the MU blog editor, and it won&#8217;t break the path when you save there.</p>
<div id="attachment_14065" class="wp-caption aligncenter" style="width: 497px"><a href="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.39.42-AM.png"><img src="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-12-at-10.39.42-AM.png" alt="Set the blog path in the MU blog editor, MU won&#39;t break it when you save it this time." width="487" height="123" class="size-full wp-image-14065" /></a><p class="wp-caption-text">Set the blog path in the MU blog editor, MU won't break it when you save it this time.</p></div>
<p>Once you create the new blog, try to load it in your browser. You&#8217;ll quickly notice the stylesheet is missing, though the blog works and functions properly.</p>
<h3 id="14052_hack-the-htaccess_1">Hack The .htaccess</h3>
<p>WPMU uses the following <code>.htaccess</code> rewrite rule to properly direct requests for files on the real filesystem:</p>
<pre class="brush: plain;">RewriteRule  ^([_0-9a-zA-Z-]+/)?(wp-.*) $2 [L]</pre>
<p>Obviously, that rule won&#8217;t work for deep paths, so I&#8217;ve replaced it with this rule:</p>
<pre class="brush: plain;">RewriteRule  ^(.+)?/(wp-.*) /$2 [L]</pre>
<p>And with that, you should be done.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14052/wordpress-hacks-nested-paths-for-wpmu-blogs/feed/</wfw:commentRss>
		<slash:comments>6</slash:comments>
		</item>
		<item>
		<title>WordPress Hacks: Serving Multiple Domains</title>
		<link>http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/</link>
		<comments>http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#comments</comments>
		<pubDate>Thu, 03 Sep 2009 17:41:57 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[authentication]]></category>
		<category><![CDATA[cms]]></category>
		<category><![CDATA[cookies]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[sub-domains]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[WordPress MU]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=14028</guid>
		<description><![CDATA[
strong>Situation: using WordPress MU (possibly including BuddyPress) on multiple domains or sub-domains of a large organization with lots of users.
WordPress MU is a solid CMS to support a large organization. Each individual blog has its own place in the organization&#8217;s URL scheme (www.site.org/blogname), and each blog can have its own administrators and other users. Groups [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-14028"><!-- &nbsp; --></abbr>
<div class="contents innerindex"><h3>Contents</h3><ol><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_challenge-setting-up_1">Challenge: setting up service on multiple (sub-) domains</a><ol><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_set-up-your-web-serv_1">Set up your web server</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_set-up-your-dns_1">Set up your DNS</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_create-a-new-blog-in_1">Create a new blog in WPMU</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_reconfigure-wp-confi_1">Reconfigure wp-config.php</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_set-up-your-new-site_1">Set up your new Site</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_set-up-the-admins-of_1">Set up the admins of the new site</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_sub-domains-or-just-_1">Sub-domains or just different domains?</a></li></ol></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_challenge-unified-lo_1">Challenge: unified log in cookies</a><ol><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_set-your-cookie-path_1">Set your cookie path</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_avoid-conflicts-with_1">Avoid conflicts with other WordPress installations at your domain</a></li></ol></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_challenge-unified-lo_2">Challenge: unified log in location/URL</a><ol><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_filter-login_url-and_1">Filter login_url and logout_url</a></li><li><a href="http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/#14028_filter-allowed_redir_1">Filter allowed_redirect_hosts</a></li></ol></li></ol></div><strong>Situation:</strong> using WordPress MU (possibly including BuddyPress) on multiple domains or sub-domains of a large organization with lots of users.</p>
<p>WordPress MU is a solid CMS to support a large organization. Each individual blog has its own place in the organization&#8217;s URL scheme (<code>www.site.org/blogname</code>), and each blog can have its own administrators and other users. Groups of blogs in WPMU make up a &#8220;Site&#8221; and one or more Sites can be hosted with a single implementation. (I&#8217;m capitalizing Site for the same reason WordPress docs capitalize <a href="http://codex.wordpress.org/Pages">Page</a>) Each Site has a defined set of administrators and options controlling various features. You might, for instance, lock down the plugins on your <code>blogs.site.org</code>, while keeping it open on your <code>www.site.org</code>. Or maybe you&#8217;d like to let your helpdesk staff create new blogs at <code>blogs.site.org</code>, but not at <code>www.site.org</code>. That&#8217;s what WPMU&#8217;s notion of Site can help you control.<br />
<span id="more-14028"></span></p>
<h3 id="14028_challenge-setting-up_1">Challenge: setting up service on multiple (sub-) domains</h3>
<p>WordPress MU makes it easy to host both blogs.site.org and www.site.org within a single implementation, but there&#8217;s little documentation for how to do it.</p>
<p>Once you get WPMU up and running on one of your domains you can add another. The following assumes that you&#8217;re using the <code>vhost=no</code> setting (correct: I really mean vhost=no), that you have access to and know how to manipulate your MySQL, that you have control over your DNS and know how to use it, and that you know how to configure Apache or similar. You&#8217;d also be smart to turn off any object caching you may have running, at least until we&#8217;re done doing direct database manipulation.</p>
<p>Some might ask why I&#8217;m not simply using <a href="http://wordpress.org/extend/plugins/wordpress-mu-domain-mapping/">Donncha&#8217;s plugin</a>, and the answer is simple: it only works for <code>vhost=yes</code> sites. For my own use, I find that sub-directories are easier for users to make sense of (go ahead, try to tell your mom to go to &#8220;<code>myblog.sub.domain.org</code>&#8220;).</p>
<h4 id="14028_set-up-your-web-serv_1">Set up your web server</h4>
<p>If you&#8217;re using Apache, you&#8217;ll either need to create an <a href="http://httpd.apache.org/docs/2.2/vhosts/ip-based.html">IP-based virtual host</a> or <a href="http://maisonbisson.com/blog/post/12781/apache-virtual-hosting-black-magic/">manually configure</a> your name-based virtual host for every (sub-)domain you plan to serve. Why: WordPress will handle the domain mapping for you, so it&#8217;s better to keep Apache out of the way and let WPMU own the entire IP.</p>
<h4 id="14028_set-up-your-dns_1">Set up your DNS</h4>
<p>Point each subdomain you plan to host in WordPress to your webserver. You can use a wildcard domain, but you don&#8217;t have to.</p>
<h4 id="14028_create-a-new-blog-in_1">Create a new blog in WPMU</h4>
<p>It doesn&#8217;t matter what you call it or what the path is, just create one. Now go edit it in the Site Admin:</p>
<p><div id="attachment_14029" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-02-at-8.41.56-PM.png"><img class="size-medium wp-image-14029" src="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-02-at-8.41.56-PM-300x69.png" alt="edit blog 1" width="300" height="69" /></a><p class="wp-caption-text">Change the domain and path to match your new domain.</p></div>
<p style="text-align: left">One quirk of WPMU is that it strips &#8220;www&#8221; from any domain name you enter (or is requested), so don&#8217;t bother trying to enter it (unless you&#8217;re willing to do some hacking to make it work). WPMU stores domain and path information in three locations: the wp_#_options table for the blog, the wp_blogs table, and the wp_sites table. When you edit a blog in the Site Admin, you&#8217;ll get a chance to edit the domain and path for both the wp_#_options and the wp_blogs tables. Clicking the helpful checkbox above will do most of that for you, but you&#8217;ll need to manually update the Upload Path.</p>
<div id="attachment_14030" class="wp-caption aligncenter" style="width: 310px"><a href="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-02-at-8.42.34-PM.png"><img class="size-medium wp-image-14030" src="http://maisonbisson.com/files/2009/09/Screen-shot-2009-09-02-at-8.42.34-PM-300x48.png" alt="Now make sure the new domain is shown in the blog's options as well." width="300" height="48" /></a><p class="wp-caption-text">Now make sure the new domain is shown in the blog&#39;s options as well.</p></div>
<p>You might be able to load the blog at the new URL as soon as you update those settings, but recent versions of WPMU set some constants in <code>wp-config.php</code> that can get in your way.</p>
<h4 id="14028_reconfigure-wp-confi_1">Reconfigure wp-config.php</h4>
<p>Your <code>wp-config.php</code> might have something like this:</p>
<pre class="brush: php;">$base = '/';
define('DOMAIN_CURRENT_SITE', 'sub.site.org' );
define('PATH_CURRENT_SITE', '/' );
define('SITE_ID_CURRENT_SITE', 1);
define('BLOGID_CURRENT_SITE', '1' );</pre>
<p>Those constants override the database checking that goes on in <code>wpmu-settings.php</code> to map the requested domain to a site. You have three choices: leave it as it is (and use only one &#8220;Site&#8221;), remove it and have WPMU do the mapping against the database, or expand the hard-coded mapping to include other sites.</p>
<p>I&#8217;ve used code like the following to do just that:</p>
<pre class="brush: php;">if( preg_match( '/(.+?\.)?([^\.]+?)\.site.org/i', 'www'. $_SERVER['SERVER_NAME'] , $matchedsubdomains ))
{
	switch( array_pop( $matchedsubdomains )){
		case 'connect':
			define('DOMAIN_CURRENT_SITE', 'blogs.site.org' );
			define('PATH_CURRENT_SITE', '/' );
			define('BLOGID_CURRENT_SITE', '1' );
			break;
		case 'www':
		default:
			define('DOMAIN_CURRENT_SITE', 'site.org' );
			define('PATH_CURRENT_SITE', '/' );
			define('BLOGID_CURRENT_SITE', '2' );
			break;
}
}
else
{
	define('DOMAIN_CURRENT_SITE', 'site.org' );
	define('PATH_CURRENT_SITE', '/' );
	define('BLOGID_CURRENT_SITE', '2' );
}</pre>
<h4 id="14028_set-up-your-new-site_1">Set up your new Site</h4>
<p>Once you have your new sub-domain working with one blog, you can create your new Site. Even if you don&#8217;t plan to create separate management policies for the different sites, it&#8217;s easier to create new blogs at each sub-domain if they each have their own Site.</p>
<p>Go in to your MySQL tool of choice and browse the <code>wp_site</code> table. There you&#8217;ll see just one row, but if you&#8217;ve made it this far you can also probably figure out how to create a new row representing the site at the new sub-domain. And once you do that, you can change the entry in the <code>wp_blogs</code> table to associate it with your new Site.</p>
<h4 id="14028_set-up-the-admins-of_1">Set up the admins of the new site</h4>
<p>Creating the new entry in <code>wp_site</code> doesn&#8217;t set the options for the new Site, and that means there are no Site administrators yet. Once again in your MySQL tool of choice, open up the <code>wp_sitemeta</code> table and look for an entry with <code>meta_key = 'site_admins'</code>. The <code>meta_value</code> for that entry is a serialized array containing WordPress usernames of the people who have site-wide administration privileges on the first Site. I&#8217;m assuming that if you have MySQL access you&#8217;re also a Site admin, so the easy thing to do is copy that row and change the <code>site_id</code> to match the auto-increment value from the new <code>wp_site</code> entry you made in the last step.</p>
<p>With the database manipulation done, you should now be able to go to the WP dashboard at your new Site, visit the WPMU admin options screen, and set the other options as necessary. You could decide to make one of your Sites open registration (remember, however, that users are shared across all Sites), while making other Sites more closed. And, obviously, you can delegate different Site admins for each Site. </p>
<h4 id="14028_sub-domains-or-just-_1">Sub-domains or just different domains?</h4>
<p>It&#8217;s worth noting that the instructions so far apply to both sub-domains and domains. You can use a single implementation of WPMU to manage content at both <code>lolzors.org</code> and <code>tehsite.org</code>. The detail about sub-domains really only applies to the next part. It&#8217;s also worth noting that you can support an arbitrary number of blogs, sites, and domains; I&#8217;m just using two sub-domains as an example.</p>
<h3 id="14028_challenge-unified-lo_1">Challenge: unified log in cookies</h3>
<p>What&#8217;s the point of hosting multiple sub-domains with one WPMU implementation if you&#8217;ll need to log in separately at each one?</p>
<h4 id="14028_set-your-cookie-path_1">Set your cookie path</h4>
<p>Setting a cookie path that that&#8217;s broad enough to cover the entire domain will solve this:</p>
<pre class="brush: php;">define('COOKIE_DOMAIN', 'site.org');
define('ADMIN_COOKIE_PATH', '/');
define('COOKIEPATH', '/');
define('SITECOOKIEPATH', '/');</pre>
<h4 id="14028_avoid-conflicts-with_1">Avoid conflicts with other WordPress installations at your domain</h4>
<p>But having such a broad cookie domain can interfere with other WordPress implementations. You&#8217;ll have to solve that by setting a unique cookiehash:</p>
<pre class="brush: php;">define( 'COOKIEHASH', 'asdf_arbitrary_string' );</pre>
<p>You&#8217;d do better to keep it shorter than that, though.</p>
<h3 id="14028_challenge-unified-lo_2">Challenge: unified log in location/URL</h3>
<p>WordPress MU is happy to handle authentication requests wherever it hosts a blog, but some organizations prefer to funnel all authentication requests through a single location. The idea is to provide some protection against fishing (assuming users can ever be taught to look at URLs) and make it easer to integrate external applications.</p>
<h4 id="14028_filter-login_url-and_1">Filter login_url and logout_url</h4>
<p>Set the log in and log out path to whatever you want, just make sure the destination knows how to create (or destroy) the WordPress cookies.</p>
<pre class="brush: php;">
$hack_base_domain = 'site.org';

function hack_login_url( $path ){
	global $hack_base_domain;

	return preg_replace( '/^.+?\/wp-login.php/' , 'https://login.'. $hack_base_domain .'/wp-login.php', $path );
}
add_filter( 'login_url' , 'hack_login_url' , 10 );
add_filter( 'logout_url' , 'hack_login_url' , 10 );
</pre>
<h4 id="14028_filter-allowed_redir_1">Filter allowed_redirect_hosts</h4>
<p>WP will normally block redirects outside the web root of the active blog, so you&#8217;ll need to tell it about your other sub-domains.</p>
<pre class="brush: php;">
function hack_allowed_redirect_hosts( $allowed_domains ){
	global $hack_base_domain;

	$allowed_domains[] = $hack_base_domain;
	$allowed_domains[] = 'www.'. $hack_base_domain;
	$allowed_domains[] = 'blogs.'. $hack_base_domain;

	return $allowed_domains;
}
add_filter( 'allowed_redirect_hosts' , 'hack_allowed_redirect_hosts' , 10 );
</pre>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/14028/wordpress-hacks-managing-multiple-sub-domains/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>What is David McNicol&#8217;s URL Cache Plugin?</title>
		<link>http://maisonbisson.com/blog/post/13953/what-is-david-mcnicols-url-cache-plugin/</link>
		<comments>http://maisonbisson.com/blog/post/13953/what-is-david-mcnicols-url-cache-plugin/#comments</comments>
		<pubDate>Wed, 10 Jun 2009 16:13:11 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Blink]]></category>
		<category><![CDATA[Libraries & Networked Information]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[cache]]></category>
		<category><![CDATA[perm-permalinks]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[web archiving]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wordpress plugin]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13953</guid>
		<description><![CDATA[
The description to David McNicol&#8217;s URL Cache Plugin raises more questions than it answers:
Given a URL, the url_cache() function will attempt to download the file it represents and return a URL pointing to this locally cached version.
Where did he plan to use it? Does he envision the cache as an archive, or for performance? Why hasn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13953"><!-- &nbsp; --></abbr>
<p>The description to David McNicol&#8217;s <a href="http://wordpress.org/extend/plugins/url-cache/">URL Cache Plugin</a> raises more questions than it answers:</p>
<blockquote><p>Given a URL, the url_cache() function will attempt to download the file it represents and return a URL pointing to this locally cached version.</p></blockquote>
<p>Where did he plan to use it? Does he envision the cache as an archive, or for performance? Why hasn&#8217;t it been updated since 2005?</p>
<p>It caught my interest because I&#8217;ve long been interested in a solution to link rot in my blog. A real &#8220;perma-permalink&#8221; would be very useful.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13953/what-is-david-mcnicols-url-cache-plugin/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Too Bad The Hanzo Archives Wordpress Plugin Is Caput</title>
		<link>http://maisonbisson.com/blog/post/13955/too-bad-the-hanzo-archives-wordpress-plugin-is-caput/</link>
		<comments>http://maisonbisson.com/blog/post/13955/too-bad-the-hanzo-archives-wordpress-plugin-is-caput/#comments</comments>
		<pubDate>Tue, 09 Jun 2009 16:12:46 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Blink]]></category>
		<category><![CDATA[Libraries & Networked Information]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[archive]]></category>
		<category><![CDATA[Hanzo Archives]]></category>
		<category><![CDATA[link rot]]></category>
		<category><![CDATA[perma-permalink]]></category>
		<category><![CDATA[permalink]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[web archive]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13955</guid>
		<description><![CDATA[
The Hanzo Archives Wordpress plugin is something I&#8217;d be very excited to use. Ironically, it&#8217;s disappeared from the web (though the blog post hasn&#8217;t):
We’ve released a Wordpress Plugin which automatically archives anything you link to in your blog posts; it also adds a ‘perma-permalink’ for the archived version adjacent to each original link.
An Amazon Web [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13955"><!-- &nbsp; --></abbr>
<p>The <a href="http://www.hanzoarchives.com/">Hanzo Archives</a> <a href="http://www.hanzoarchives.com/blog/2006/05/16/wordpress-plugin/">Wordpress plugin</a> is something I&#8217;d be very excited to use. Ironically, it&#8217;s disappeared from the web (though the blog post hasn&#8217;t):</p>
<blockquote><p>We’ve released a Wordpress Plugin which automatically archives anything you link to in your blog posts; it also adds a ‘perma-permalink’ for the archived version adjacent to each original link.</p></blockquote>
<p>An <a href="http://aws.amazon.com/solutions/case-studies/hanzo/">Amazon Web Services case study</a> put me on to Hanzo a while ago, and in May 2008 I actually spoke with <a href="http://twitter.com/hanzoman">Mark Middleton</a> (the markm who posted the entry above). Mark revealed that community take-up on the plugin and other general purpose web archiving services was below expectations. The company has since refocused on legal matters (even their blog tag-line has changed to &#8220;web archiving for compliance and e-discovery&#8221;).</p>
<p>I wonder if, now that the number of people and companies that have been blogging for years has grown, there might be more of a market for such a service.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13955/too-bad-the-hanzo-archives-wordpress-plugin-is-caput/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Customizable Post Listings</title>
		<link>http://maisonbisson.com/blog/post/13951/customizable-post-listings/</link>
		<comments>http://maisonbisson.com/blog/post/13951/customizable-post-listings/#comments</comments>
		<pubDate>Mon, 08 Jun 2009 14:13:13 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Blink]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[post listings]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wordpress plugin]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13951</guid>
		<description><![CDATA[
Lorelle is a big fan of Scott Reilly&#8217;s  Customizable Post Listings:
Display Recent Posts, Recently Commented Posts, Recently Modified Posts, Random Posts, and other post, page, or draft listings using the post information of your choosing in an easily customizable manner. You can narrow post searches by specifying categories and/or authors, among other things.
]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13951"><!-- &nbsp; --></abbr>
<p><a href="http://lorelle.wordpress.com/">Lorelle</a> is a big fan of Scott Reilly&#8217;s <a href="http://coffee2code.com/wp-plugins/customizable-post-listings/"> Customizable Post Listings</a>:</p>
<blockquote><p>Display Recent Posts, Recently Commented Posts, Recently Modified Posts, Random Posts, and other post, page, or draft listings using the post information of your choosing in an easily customizable manner. You can narrow post searches by specifying categories and/or authors, among other things.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13951/customizable-post-listings/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Video or Audio Comments in WordPress with Riffly</title>
		<link>http://maisonbisson.com/blog/post/13948/video-or-audio-comments-in-wordpress-with-riffly/</link>
		<comments>http://maisonbisson.com/blog/post/13948/video-or-audio-comments-in-wordpress-with-riffly/#comments</comments>
		<pubDate>Fri, 05 Jun 2009 15:56:46 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Blink]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[audio]]></category>
		<category><![CDATA[audio comments]]></category>
		<category><![CDATA[comments]]></category>
		<category><![CDATA[podcast comments]]></category>
		<category><![CDATA[Riffly]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13948</guid>
		<description><![CDATA[
In line with yesterday&#8217;s discovery of the Viddler WP plugin, Riffly Webcam Video Comments also supports video or audio comments within WordPress:
Riffly is a free service that easily plugs into your site allowing visitors to create video and audio comments.
The service is advertising supported. We cover all the costs for bandwidth, servers, and maintenance. Optionally, we [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13948"><!-- &nbsp; --></abbr>
<p>In line with <a href="http://maisonbisson.com/blog/post/13945/video-comments-with-viddler-wordpress-plugin/">yesterday&#8217;s discovery of the Viddler WP plugin</a>, <a href="http://wordpress.org/extend/plugins/riffly/">Riffly Webcam Video Comments</a> also supports video or audio comments within WordPress:</p>
<blockquote><p><a href="http://riffly.com/">Riffly</a> is a free service that easily plugs into your site allowing visitors to create video and audio comments.</p>
<p>The service is advertising supported. We cover all the costs for bandwidth, servers, and maintenance. Optionally, we also offer Premium Riffly accounts that provide you with additional benefits, such as advertising removal, control panel access, analytics, and much more.</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13948/video-or-audio-comments-in-wordpress-with-riffly/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Video Comments With Viddler WordPress Plugin</title>
		<link>http://maisonbisson.com/blog/post/13945/video-comments-with-viddler-wordpress-plugin/</link>
		<comments>http://maisonbisson.com/blog/post/13945/video-comments-with-viddler-wordpress-plugin/#comments</comments>
		<pubDate>Thu, 04 Jun 2009 15:21:49 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Blink]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[comments]]></category>
		<category><![CDATA[Viddler]]></category>
		<category><![CDATA[video]]></category>
		<category><![CDATA[video comments]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13945</guid>
		<description><![CDATA[
The Viddler Wordpress plugin promises to &#8220;Enrich your site&#8217;s commenting experience by enabling video comments&#8230;.&#8221; Users can record direcly from a web cam or choose a video they&#8217;ve previously uploaded to Viddler.com.
Viddler evangelist Colin Devroe has it on his site, where I can see it requires would-be commenters have a Viddler account. That last bit [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13945"><!-- &nbsp; --></abbr>
<p>The <a href="http://wordpress.org/extend/plugins/the-viddler-wordpress-plugin/">Viddler Wordpress plugin</a> promises to &#8220;Enrich your site&#8217;s commenting experience by enabling video comments&#8230;.&#8221; Users can record direcly from a web cam or choose a video they&#8217;ve previously uploaded to Viddler.com.</p>
<p><a href="http://www.viddler.com/">Viddler</a> evangelist <a href="http://cdevroe.com/notes/testing-wolframalpha/">Colin Devroe has it on his site</a>, where I can see it requires would-be commenters have a Viddler account. That last bit is too bad. I like Viddler, but I can&#8217;t force my readers to like it and get accounts as a prerequisite to commenting.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13945/video-comments-with-viddler-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Systems Wrangling Session At WordCamp Developer Day</title>
		<link>http://maisonbisson.com/blog/post/13938/systems-wrangling-session-at-wordcamp-developer-day/</link>
		<comments>http://maisonbisson.com/blog/post/13938/systems-wrangling-session-at-wordcamp-developer-day/#comments</comments>
		<pubDate>Sun, 31 May 2009 21:13:21 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[systems]]></category>
		<category><![CDATA[WordCamp]]></category>
		<category><![CDATA[WordCamp 2009]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13938</guid>
		<description><![CDATA[
What is the current status of web servers&#8230;Is Apache 2.x “fast enough?”
Automattic uses Lightspeed (for PHP), nginx (for static content), and Apache (for media uploads). For WordPress-generated content, all server options are approximately the same speed.
What about APC?
Automattic uses beta versions of APC, and provides a 3-5x performance increase. It&#8217;s tied closely to the PHP [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13938"><!-- &nbsp; --></abbr>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-2">What is the current status of web servers&#8230;Is Apache 2.x “fast enough?”</a><br />
Automattic uses Lightspeed (for PHP), nginx (for static content), and Apache (for media uploads). For WordPress-generated content, all server options are approximately the same speed.</p>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-3">What about APC?</a><br />
Automattic uses beta versions of APC, and provides a 3-5x performance increase. It&#8217;s tied closely to the PHP version, so Automattic recently switched from PHP 4 to PHP 5.</p>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-4">Databases?</a><br />
MySQL scales well and is easy enough to use that there&#8217;s little reason to consider other DBs for WordPress content. Other applications may have different needs. Note: <a title="How FriendFeed uses MySQL to store schema-less data - Bret Taylor's blog" href="http://bret.appspot.com/entry/how-friendfeed-uses-mysql">FriendFeed uses MySQL to store schema-less data</a>. Single-table key lookups in MySQL are faster than getting the data from Memcached.</p>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-7">Caching?</a><br />
Automattic uses <a title="WordPress › Batcache « WordPress Plugins" href="http://wordpress.org/extend/plugins/batcache/">Batcache</a> for full-page caching (.002 to .003 second), <a title="Revision 121652: /memcached" href="http://svn.wp-plugins.org/memcached/">Memcached</a> persistent object cache, very limited MySQL query cache (never larger than 256MB), sufficiently large key buffer.</p>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-14">HyperDB?</a><br />
<a title="WordPress › HyperDB « WordPress Plugins" href="http://wordpress.org/extend/plugins/hyperdb/">HyperDB</a> solves DB scaling problems.</p>
<p><a title="Ask your questions here « Server Q&amp;A — WordCamp Dev Day" href="http://serverqa.wordpress.com/2009/05/31/ask-your-questions-here/#comment-25">Backups</a><br />
User-data backed up every hour, if something changed. Every blog backed up every 12 hours. Dedicated MySQL slaves do LVM snapshots for backups.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13938/systems-wrangling-session-at-wordcamp-developer-day/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Andy Peatling on BuddyPress</title>
		<link>http://maisonbisson.com/blog/post/13931/andy-peatling-on-buddypress/</link>
		<comments>http://maisonbisson.com/blog/post/13931/andy-peatling-on-buddypress/#comments</comments>
		<pubDate>Sun, 31 May 2009 15:25:36 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[BuddyPress]]></category>
		<category><![CDATA[social software]]></category>
		<category><![CDATA[WordCamp]]></category>
		<category><![CDATA[WordCamp 2009]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13931</guid>
		<description><![CDATA[
Why BuddyPress? “Build passionate users around a specific niche.”
Do you have to become a social network? “No, look at GigaOM Pro,” a recently launched subscription research site based on BuddyPress.
But, yo do get “BYOTOS: bring your own terms of service.” That is, you get to control content and interactions. And your service won&#8217;t be subject [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13931"><!-- &nbsp; --></abbr>
<p>Why <a title="BuddyPress.org - A WordPress MU Based Social Network Platform" href="http://buddypress.org/">BuddyPress</a>? “Build passionate users around a specific niche.”</p>
<p>Do you have to become a social network? “No, look at <a title="GigaOM Pro" href="http://pro.gigaom.com/">GigaOM Pro</a>,” a <a title="GigaOM Pro launches on WordPress and BuddyPress « Mark on WordPress" href="http://markjaquith.wordpress.com/2009/05/28/gigaom-pro-launches-on-wordpress-and-buddypress/">recently launched</a> subscription research site based on BuddyPress.</p>
<p>But, yo do get “BYOTOS: bring your own terms of service.” That is, you get to control content and interactions. And your service won&#8217;t be subject to the whims of a larger network like FaceBook (or vagaries of their service &#8212; <a title="What really happened at Ma.gnolia and lessons learned | FactoryCity" href="http://factoryjoe.com/blog/2009/02/16/what-really-happened-at-magnolia-and-lessons-learned/">think Ma.gnolia</a>)</p>
<p>It&#8217;s pretty easy, Andy says, to <a href="http://codex.buddypress.org/how-to-guides/creating-a-custom-buddypress-component/">create a custom BuddyPress component</a>, and there are already a number at the <a title="BuddyPressDEV Community" href="http://bp-dev.org/">BuddyPressDEV Community</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13931/andy-peatling-on-buddypress/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress 2.8 Script Handling</title>
		<link>http://maisonbisson.com/blog/post/13929/wordpress-28-script-handling/</link>
		<comments>http://maisonbisson.com/blog/post/13929/wordpress-28-script-handling/#comments</comments>
		<pubDate>Sun, 31 May 2009 15:16:36 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[performance]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[WordPress 2.8]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13929</guid>
		<description><![CDATA[
jQuery 1.3.2 is in WordPress 2.8, but the most exciting changes are in the automatic concatenation and compression of scripts via the script loader.
Andrew Ozz says “This feature can easily be extended to include scripts added by plugins and to use server side caching, however that would require some changes to the server settings (.htaccess [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13929"><!-- &nbsp; --></abbr>
<p><a title="/trunk/wp-includes/js/jquery/jquery.js – WordPress Trac" href="http://core.trac.wordpress.org/browser/trunk/wp-includes/js/jquery/jquery.js">jQuery 1.3.2 is in</a> <a href="http://codex.wordpress.org/Version_2.8">WordPress 2.8</a>, but the most exciting changes are in the automatic concatenation and compression of scripts <a title="Script loader updates « WordPress Development Updates" href="http://wpdevel.wordpress.com/2009/02/06/script-loader-updates/">via the script loader</a>.</p>
<p>Andrew Ozz says “This feature can easily be extended to include scripts added by plugins and to use server side caching, however that would require some changes to the server settings (.htaccess on Apache).”</p>
<p>I have yet to figure out how to extend that feature to scripts in my plugins, but I&#8217;m working on it.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13929/wordpress-28-script-handling/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Google&#8217;s Matt Cutts On Building Better Sites With WordPress</title>
		<link>http://maisonbisson.com/blog/post/13920/wordpress-seo-tips-from-google-matt-cutts/</link>
		<comments>http://maisonbisson.com/blog/post/13920/wordpress-seo-tips-from-google-matt-cutts/#comments</comments>
		<pubDate>Sat, 30 May 2009 18:02:51 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[Matt Cutts]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[WordCamp]]></category>
		<category><![CDATA[WordCamp 2009]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13920</guid>
		<description><![CDATA[
90% of WordPress blogs he sees are spam. But for those who aren&#8217;t spammers and want to do better in Google&#8230;.
“WordPress automatically solves a ton of SEO issues&#8230;WordPress takes care of 80-90% of SEO.”
Still, he recommends a few extra plugins:

Akismet &#8212; reduce spam comments
Cookies for Comments &#8212; reduce spam comments
FeedBurner FeedSmith
WP Super Cache &#8212; improve [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13920"><!-- &nbsp; --></abbr>
<p>90% of WordPress blogs he sees are spam. But for those who aren&#8217;t spammers and want to do better in Google&#8230;.</p>
<p>“WordPress automatically solves a ton of SEO issues&#8230;WordPress takes care of 80-90% of SEO.”</p>
<p>Still, he recommends a few extra plugins:</p>
<ul>
<li>Akismet &#8212; reduce spam comments</li>
<li>Cookies for Comments &#8212; reduce spam comments</li>
<li>FeedBurner FeedSmith</li>
<li>WP Super Cache &#8212; improve performance</li>
</ul>
<p>“We crawl roughly in order of PageRank&#8230;higher ranked sites get crawled faster and deeper.”</p>
<p>“What is PageRank? The number and importance of links pointing to you.” But “avoid BO (backlink obsession). You want to be relevant and reputable.”</p>
<p>Relevant is what you say on your page/site.</p>
<p>Reputable is what others say (link) about you.</p>
<p>Be relevant: Blog about what you love. Blog about what you&#8217;re really good at doing (or, I suppose, what you want to be really good at). Blog in your own voice. Write often, write every day.</p>
<p>Think about the keywords that users will type. Include them naturally in your posts</p>
<p>Avoid jargon mismatch. Be sure to include language that non-expert users may use to find information. Include relevant information for beginners on the front page. Try <a title="Google AdWords: Keyword Tool" href="https://adwords.google.com/select/KeywordToolExternal">Google Keyword Tool</a> to understand what people are searching for.</p>
<p>Recommends /%postname%/ permalinks. And use slightly different terms in the permalink and title. Other URL tips:</p>
<ul>
<li>Use categories that are also good keywords</li>
<li>keywords in URL paths
<ul>
<li>dashes best</li>
<li>next best is underscores</li>
<li>no spaces is worst</li>
</ul>
</li>
<li>Should I change old URLs? No.</li>
</ul>
<p>Ferris&#8217;s law: don&#8217;t do it if it&#8217;s not fun.</p>
<p>Gaining Reputation?</p>
<ul>
<li>Be interesting</li>
<li>Update often</li>
<li>Apply Katamari Philosophy &#8212; start small, build up, don&#8217;t over reach. Start in a niche, then “ambigining” that niche.</li>
</ul>
<p>Build an audience:</p>
<ul>
<li>Provide a useful service</li>
<li>Do original research or reporting</li>
<li>Give great information</li>
<li>Creative niche</li>
<li>Write some code</li>
<li>Live blogging</li>
<li>Make lists</li>
<li>Create controversy</li>
<li>Meet folks on Twitter, Facebook, etc</li>
<li>Make a video</li>
</ul>
<p>Consider using:</p>
<ul>
<li>Google website optimizer (a/b testing)</li>
<li>&lt;!&#8211; google_ad_section_start &#8211;&gt; and &lt;!&#8211; google_ad_section_end &#8211;&gt;</li>
</ul>
<p>In your content:</p>
<ul>
<li>Identify and leverage “evergreen” content</li>
<li>Show related content</li>
<li>Avoid shortcuts and scams</li>
<li>Avoid paid posts</li>
</ul>
<p>Keep your WordPress updated! Don&#8217;t let spammers hack your site.</p>
<p>LifeHacker: productivity porn, read about it more than you do it</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13920/wordpress-seo-tips-from-google-matt-cutts/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>WordPress Action Ticketing API</title>
		<link>http://maisonbisson.com/blog/post/13862/wordpress-action-ticketing-api/</link>
		<comments>http://maisonbisson.com/blog/post/13862/wordpress-action-ticketing-api/#comments</comments>
		<pubDate>Thu, 30 Apr 2009 16:23:47 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[ticket]]></category>
		<category><![CDATA[ticketing]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13862</guid>
		<description><![CDATA[
This plugin is the next step after my proposal for a common invite API. Here&#8217;s how I described it when requesting hosting at the plugin directory:
A common framework for registering tickets that will be acted upon later. Use it to manage challenge/response interactions to confirm email addresses, phone numbers, IM screen names, Twitter accounts, etc. [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13862"><!-- &nbsp; --></abbr>
<p><a title="WordPress › wp-ticket-framework « WordPress Plugins" href="http://wordpress.org/extend/plugins/wp-ticket-framework/">This plugin</a> is the next step after my <a title="» Do We Need A WordPress Common Invite or Challenge-Response API? MaisonBisson.com" href="http://maisonbisson.com/blog/post/13744/do-we-need-a-wordpress-common-invite-or-challenge-response-api/">proposal for a common invite API</a>. Here&#8217;s how I described it when requesting hosting at the plugin directory:</p>
<blockquote><p>A common framework for registering tickets that will be acted upon later. Use it to manage challenge/response interactions to confirm email addresses, phone numbers, IM screen names, Twitter accounts, etc. Build an invite system around it, or use it as the foundation of a short URL system. It&#8217;s an extensible framework that takes cues from WordPress&#8217; cron and admin Ajax functions.</p>
<p>Tickets are unique 1-32 character strings associated with actions and some stored data. Upon receiving a ticket, the matching action is executed with the stored data as an argument. After receiving the action, a plugin can destroy the ticket (as for challenge/response actions), or or leave the ticket in place for repeated use (like redirecting to longer post permalinks for a short URL resolver).</p></blockquote>
<p>Here&#8217;s how it works:</p>
<p>Registering a ticket requires three things:</p>
<ul>
<li>The unique string that identifies the ticket</li>
<li>A string representing the action that will be executed when the ticket is called</li>
<li>Some data that will be passed to that action when the ticket is called</li>
</ul>
<p>And here it is in action:</p>
<pre class="brush: php;">$ticket = $wptix-&gt;register_ticket( 'action_name_string', $wptix-&gt;generate_md5(), array( 'data' =&gt; 'val', 'more_data' =&gt; 'another_val' ));</pre>
<p>To actually do anything with that ticket you&#8217;ll have to also register a function associated with the action name you gave when you registered it:</p>
<pre class="brush: php;">add_action( 'action_name_string', 'my_function_name' );</pre>
<p>WP Ticket Framework registers a URL base in the form of <code>http://site.net/do/any_ticket_string</code>, so you can call a ticket simply by visiting that URL, or you can call tickets within your code. The following demonstrates one method of handling ticket inputs as part of a larger form submission.</p>
<pre class="brush: php;">if( ( $ticket = $wptix-&gt;is_ticket( $_POST['phone_confirmation'] )) &amp;&amp; $ticket-&gt;arg['user_id'] == $current_user-&gt;ID ){
 $wptix-&gt;do_ticket( $_POST['phone_confirmation'] );
}else{
 $errors-&gt;add( 'user_phone', __( &quot;&lt;strong&gt;ERROR&lt;/strong&gt;: The confirmation code is invalid.&quot; ), array( 'form-field' =&gt; 'phone_confirmation' ) );
 return;
}</pre>
<p>Caveats:</p>
<ul>
<li>Tickets don&#8217;t have any built in expiration mechanism. You can, however, include an expiration time in data saved in the ticket and act on that accordingly.</li>
<li>Tickets don&#8217;t have any built in security mechanism. If only a certain user should be allowed to call a ticket, your code needs to be aware of that and enforce it.</li>
<li>Tickets are deleted after being called, though you can suppress that by calling <code>$wptix-&gt;clean_up_after( FALSE );</code>.</li>
<li>Tickets can only be queried by ticket string. If your application needs to keep track of open tickets for each user (as an example) it should also make a user meta entry about it.</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13862/wordpress-action-ticketing-api/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Saving Objects In WordPress&#8217; User Meta</title>
		<link>http://maisonbisson.com/blog/post/13866/saving-objects-in-wordpress-user-meta/</link>
		<comments>http://maisonbisson.com/blog/post/13866/saving-objects-in-wordpress-user-meta/#comments</comments>
		<pubDate>Wed, 29 Apr 2009 16:34:03 +0000</pubDate>
		<dc:creator>Casey</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[php objects]]></category>
		<category><![CDATA[usermeta]]></category>
		<category><![CDATA[user_meta]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13866</guid>
		<description><![CDATA[
There&#8217;s a hole in the wall at about head level next to my desk.
I&#8217;ve spent most of the day trying to track down a bug with some code I&#8217;ve been working on to add fields to a user&#8217;s profile in WordPress. The problem is that upon trying to save the profile I&#8217;d get an error [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13866"><!-- &nbsp; --></abbr>
<p>There&#8217;s a hole in the wall at about head level next to my desk.</p>
<p>I&#8217;ve spent most of the day trying to track down a bug with some code I&#8217;ve been working on to add fields to a user&#8217;s profile in WordPress. The problem is that upon trying to save the profile I&#8217;d get an error like the following:</p>
<p><code>Catchable fatal error: Object of class stdClass could not be converted to string in /wp-includes/wp-db.php on line 472</code></p>
<p>Line 472 in my install is <a title="/wp-includes/wp-db.php – WordPress Trac" href="http://core.trac.wordpress.org/browser/tags/2.7.1/wp-includes/wp-db.php#L428">in the <code>wpdb::escape()</code> function</a>. After poking around the wrong side of the problem, I finally broke down and rewrote the function along these lines:</p>
<pre class="brush: php;">
function escape($string) {
 if( !is_object( $string ))
 return( $string );

 echo '&lt;h2&gt;'. $this-&gt;get_caller() .'&lt;/h2&gt;&lt;pre&gt;';
 print_r( $string );
 echo '&lt;/pre&gt;';
 die();
}
</pre>
<p>That&#8217;s how I finally learned that <a title="#9640 (wp_update_user() blindly calls add_magic_quotes(), even on objects) – WordPress Trac" href="http://core.trac.wordpress.org/ticket/9640"><code>wp_update_user()</code> was at fault</a>. I also opened <a title="#9638 (add_magic_quotes() fails on objects) – WordPress Trac" href="http://core.trac.wordpress.org/ticket/9638">a ticket for <code>add_magic_quotes()</code></a><code><code>, as both probably need independent fixes. </code></code></p>
<p><code><code>For now, however, I'm just converting the object to an array and avoiding the mess.</code></code></p>
<p><code><code> </code></code></p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13866/saving-objects-in-wordpress-user-meta/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Correction: I Do Still Need The Wufoo Forms WordPress Embed Shortcode</title>
		<link>http://maisonbisson.com/blog/post/13772/correction-i-do-still-need-the-wufoo-forms-wordpress-embed-shortcode/</link>
		<comments>http://maisonbisson.com/blog/post/13772/correction-i-do-still-need-the-wufoo-forms-wordpress-embed-shortcode/#comments</comments>
		<pubDate>Thu, 23 Apr 2009 15:43:50 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[embedding]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[shortcode]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wufoo]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13772</guid>
		<description><![CDATA[
A few weeks ago I said I no longer needed the Wufoo embedding code that I&#8217;d put into bSuite. I was wrong. So I&#8217;ve taken another look, fixed the code from my old post, and coded it up into a stand-alone plugin. I&#8217;ve added installation and usage instructions to the bottom of the original post.
]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13772"><!-- &nbsp; --></abbr>
<p><a href="http://maisonbisson.com/blog/post/13446/wufoo-forms-wordpress-embed-shortcode/" title="» Wufoo Forms WordPress Embed Shortcode MaisonBisson.com">A few weeks ago</a> I said I no longer needed the Wufoo embedding code that I&#8217;d put into <a href="http://maisonbisson.com/bsuite/">bSuite</a>. I was wrong. So I&#8217;ve taken another look, fixed the code from my old post, and coded it up into a <a href="http://maisonbisson.com/files/2009/03/wufoo_shortcodephp.txt">stand-alone plugin</a>. I&#8217;ve added installation and usage instructions to the bottom of <a href="http://maisonbisson.com/blog/post/13446/wufoo-forms-wordpress-embed-shortcode/">the original post</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13772/correction-i-do-still-need-the-wufoo-forms-wordpress-embed-shortcode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fixing Batcache to Send The Correct Content-Type Header</title>
		<link>http://maisonbisson.com/blog/post/13773/fixing-batcache-to-send-the-correct-content-type-header/</link>
		<comments>http://maisonbisson.com/blog/post/13773/fixing-batcache-to-send-the-correct-content-type-header/#comments</comments>
		<pubDate>Wed, 22 Apr 2009 17:19:12 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[batcache]]></category>
		<category><![CDATA[caching]]></category>
		<category><![CDATA[fix]]></category>
		<category><![CDATA[memcached]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[workaround]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13773</guid>
		<description><![CDATA[
I&#8217;m a fan of Batcache, the Memcached-based WordPress full-page cache solution, but I&#8217;ve discovered that it ignores the content-type header set when the page is initially generated and re-sends all content with content-type: text/html. I posted a note about this at the WordPress support forums, but then I realized what the problem was: apache_response_headers() doesn&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13773"><!-- &nbsp; --></abbr>
<p>I&#8217;m a fan of <a href="http://wordpress.org/extend/plugins/batcache/" title="WordPress › Batcache « WordPress Plugins">Batcache</a>, the Memcached-based WordPress full-page cache solution, but I&#8217;ve discovered that it ignores the <code>content-type</code> header set when the page is initially generated and re-sends all content with <code>content-type: text/html</code>. I <a href="http://wordpress.org/support/topic/263161" title="WordPress › Support » Batcache ignores content type header, sends everything as text/html">posted a note about this</a> at the WordPress support forums, but then I realized what the problem was: <a href="http://php.net/apache_response_headers" title="PHP: apache_response_headers - Manual"><code>apache_response_headers()</code></a> doesn&#8217;t return the content type, but <a href="http://php.net/headers_list" title="PHP: headers_list - Manual"><code>headers_list()</code></a> does.</p>
<p>The solution is to replace <code>apache_response_headers()</code> with <code>headers_list()</code> <a href="http://plugins.trac.wordpress.org/browser/batcache/trunk/advanced-cache.php#L93" title="/batcache/trunk/advanced-cache.php – WordPress Plugin Repository">in the code</a>, though <code>headers_list()</code> is PHP 5+ only, so it might be a while before we see a change like this committed. Still, I&#8217;ll shamelessly tag <a href="http://andy.wordpress.com/" title="Andy Skelton">Andy Skelton</a> (Batcache&#8217;s author) on it.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13773/fixing-batcache-to-send-the-correct-content-type-header/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Do We Need A WordPress Common Invite or Challenge-Response API?</title>
		<link>http://maisonbisson.com/blog/post/13744/do-we-need-a-wordpress-common-invite-or-challenge-response-api/</link>
		<comments>http://maisonbisson.com/blog/post/13744/do-we-need-a-wordpress-common-invite-or-challenge-response-api/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 16:39:45 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[BuddyPress]]></category>
		<category><![CDATA[challenge response]]></category>
		<category><![CDATA[framework]]></category>
		<category><![CDATA[invitation]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[WordPress MU]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13744</guid>
		<description><![CDATA[
The BuddyPress forums have a number of threads about handling invitations (two worth looking at: one, two), but no real solution has emerged. At the same time, there&#8217;s also a need for some means of confirming other actions such as password resets, email changes (both of those are already handled by WPMU, I know), cell [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13744"><!-- &nbsp; --></abbr>
<p>The <a href="http://buddypress.org/forums/">BuddyPress forums</a> have a number of threads about handling invitations (two worth looking at: <a href="http://buddypress.org/forums/topic.php?id=394">one</a>, <a href="http://buddypress.org/forums/topic.php?id=782">two</a>), but no real solution has emerged. At the same time, there&#8217;s also a need for some means of confirming other actions such as password resets, email changes (both of those are already handled by WPMU, I know), cell phone numbers to receive SMS messages, and other actions that need to be confirmed later.</p>
<p>So <a href="http://buddypress.org/forums/topic.php?id=2192">I&#8217;m proposing a generic API</a> to handle things like this. The built-in <a href="http://core.trac.wordpress.org/browser/tags/2.7.1/wp-includes/cron.php">WordPress cron</a> and <a href="http://core.trac.wordpress.org/browser/tags/2.7.1/wp-admin/admin-ajax.php">ajax functions</a> seem to offer a clear pattern for creating such an API: Simply, plugins and core code could register an action and a function to be called when that action is executed. The API could also store data to be sent to that function when it is executed.</p>
<p>Among the things I&#8217;d do with this?</p>
<ul>
<li>Confirm email addresses</li>
<li>Confirm cell phone numbers via text message</li>
<li>Confirm IM accounts</li>
<li>Confirm Twitter accounts</li>
<li>Confirm password reset requests</li>
<li>Confirm invitations in BuddyPress</li>
</ul>
<p>Anybody else interested?</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13744/do-we-need-a-wordpress-common-invite-or-challenge-response-api/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Fixing User Meta To Accept Repeating Fields &#8212; Just In Time For The WordPress Has-Patch Marathon</title>
		<link>http://maisonbisson.com/blog/post/13745/fixing-user-meta-to-accept-repeating-fields-just-in-time-for-the-wordpress-has-patch-marathon/</link>
		<comments>http://maisonbisson.com/blog/post/13745/fixing-user-meta-to-accept-repeating-fields-just-in-time-for-the-wordpress-has-patch-marathon/#comments</comments>
		<pubDate>Fri, 17 Apr 2009 00:45:24 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[bug fixes]]></category>
		<category><![CDATA[has-patch]]></category>
		<category><![CDATA[user meta]]></category>
		<category><![CDATA[usermeta]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13745</guid>
		<description><![CDATA[
There&#8217;s a WordPress has-patch marathon going on now and I&#8217;m hoping one of my recent patches gets some attention. I&#8217;m hoping to fix the user meta functions to allow them to accept multiple values per key, per user.
It&#8217;s listed there among the other has-patch tickets in Trac, and there&#8217;s been some discussion in WP-Hackers. Why [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13745"><!-- &nbsp; --></abbr>
<p>There&#8217;s a <a title="WordPress › Blog » The Super-Awesome WordPress 24-Hour Has-Patch Marathon" href="http://wordpress.org/development/2009/04/the-super-awesome-wordpress-24-hour-has-patch-marathon/">WordPress has-patch marathon</a> going on now and I&#8217;m hoping one of my recent patches gets some attention. I&#8217;m hoping to <a title="#7540 (allow multiple values for key in usermeta) – WordPress Trac" href="http://core.trac.wordpress.org/ticket/7540">fix the user meta functions to allow them to accept multiple values per key, per user</a>.</p>
<p>It&#8217;s listed there among the other <a title="Custom Query – WordPress Trac" href="https://core.trac.wordpress.org/query?status=assigned&amp;status=new&amp;status=reopened&amp;group=status&amp;order=priority&amp;col=id&amp;col=summary&amp;col=component&amp;col=owner&amp;col=type&amp;col=priority&amp;col=version&amp;milestone=2.8&amp;keywords=~has-patch">has-patch tickets in Trac</a>, and there&#8217;s been <a href="http://comox.textdrive.com/pipermail/wp-hackers/2009-April/#26015">some discussion in WP-Hackers</a>. Why not take a look?</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13745/fixing-user-meta-to-accept-repeating-fields-just-in-time-for-the-wordpress-has-patch-marathon/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Wufoo Forms WordPress Embed Shortcode</title>
		<link>http://maisonbisson.com/blog/post/13446/wufoo-forms-wordpress-embed-shortcode/</link>
		<comments>http://maisonbisson.com/blog/post/13446/wufoo-forms-wordpress-embed-shortcode/#comments</comments>
		<pubDate>Mon, 23 Mar 2009 16:35:30 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[bsuite]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[embedding]]></category>
		<category><![CDATA[shortcode]]></category>
		<category><![CDATA[shortcodes]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wufoo]]></category>
		<category><![CDATA[Wufoo forms]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13446</guid>
		<description><![CDATA[
I tossed this together a while ago, and it even made it in to bSuite for a time, but I don&#8217;t have a need for it anymore, and I&#8217;m cleaning house.

function shortcode_wufoo( $arg ){
 // [wufoo id=z7x4m0 domain=place.wufoo.com]

 $arg = shortcode_atts( array(
 'id' =&#62; FALSE,
 'domain' =&#62; FALSE,
 'height' =&#62; 500,
 ), $arg );

 if( [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13446"><!-- &nbsp; --></abbr>
<p>I tossed this together a while ago, and it even made it in to <a href="http://maisonbisson.com/bsuite/">bSuite</a> for a time, but I don&#8217;t have a need for it anymore, and I&#8217;m cleaning house.</p>
<pre class="brush: php;">
function shortcode_wufoo( $arg ){
 // [wufoo id=z7x4m0 domain=place.wufoo.com]

 $arg = shortcode_atts( array(
 'id' =&gt; FALSE,
 'domain' =&gt; FALSE,
 'height' =&gt; 500,
 ), $arg );

 if( !$arg['id'] || !$arg['domain'] )
 return( FALSE );

 return( str_replace( array( '%%id%%','%%domain%%','%%height%%' ), array( $arg['id'], $arg['domain'], $arg['height'] ), '&lt;iframe height=&quot;%%height%%&quot; allowTransparency=&quot;true&quot; frameborder=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;width:100%; border:none&quot; src=&quot;https://%%domain%%/embed/%%id%%/&quot;&gt;&lt;a href=&quot;http://%%domain%%/forms/%%id%%/&quot;&gt;Fill out my Wufoo form!&lt;/a&gt;&lt;/iframe&gt;' ));
}
add_shortcode( 'wufoo', 'shortcode_wufoo' );
</pre>
<p>Download the simple plugin here: <a href="http://maisonbisson.com/files/2009/03/wufoo_shortcodephp.txt"><code>wufoo_shortcode.php</code></a>. Save it as <code>wufoo_shortcode.php</code>, upload it to your WordPress&#8217; <code>wp-content/plugins/</code> directory, then activate it.</p>
<p>To use it you&#8217;ll have to have a <a href="http://wufoo.com/">Wufoo account</a> and forms. Then simple put in a shortcode like this <code>[wufoo id=z7x4m0 domain=place.wufoo.com]</code> in one of your posts or pages. The <a href="http://collingswoodlib.org/contact-us/contact-director/">result will look like this</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13446/wufoo-forms-wordpress-embed-shortcode/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Slideshare WordPress Embed Shortcode</title>
		<link>http://maisonbisson.com/blog/post/13448/slideshare-wordpress-embed-shortcode/</link>
		<comments>http://maisonbisson.com/blog/post/13448/slideshare-wordpress-embed-shortcode/#comments</comments>
		<pubDate>Mon, 16 Mar 2009 16:30:13 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Technology]]></category>
		<category><![CDATA[bsuite]]></category>
		<category><![CDATA[embed]]></category>
		<category><![CDATA[embedding]]></category>
		<category><![CDATA[shortcode]]></category>
		<category><![CDATA[shortcodes]]></category>
		<category><![CDATA[slideshare]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13448</guid>
		<description><![CDATA[
I&#8217;m cleaning house in bSuite, and I&#8217;ve decided that this shortcode function for embedding Slideshare items in WordPress needs to go. Rather than totally toss it away, however, I&#8217;m posting it here in case somebody else finds it useful.

	function shortcode_slideshare&#40; $arg &#41;&#123;
		// [slideshare id=211578&#38;amp;doc=misty-holland-1198496990903941-2&#38;amp;w=425]
&#160;
		$arg = shortcode_atts&#40; array&#40;
			'id' =&#38;gt; FALSE,
		&#41;, $arg &#41;;
&#160;
		if&#40; ! $arg&#91;'id'&#93; &#41;
			return&#40; FALSE [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13448"><!-- &nbsp; --></abbr>
<p>I&#8217;m cleaning house in <a href="http://maisonbisson.com/bsuite/">bSuite</a>, and I&#8217;ve decided that this shortcode function for embedding Slideshare items in WordPress needs to go. Rather than totally toss it away, however, I&#8217;m posting it here in case somebody else finds it useful.</p>

<div class="wp_syntax"><div class="code"><pre class="php php" style="font-family:monospace;">	<span style="color: #000000; font-weight: bold;">function</span> shortcode_slideshare<span style="color: #009900;">&#40;</span> <span style="color: #000088;">$arg</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#123;</span>
		<span style="color: #666666; font-style: italic;">// [slideshare id=211578&amp;amp;doc=misty-holland-1198496990903941-2&amp;amp;w=425]</span>
&nbsp;
		<span style="color: #000088;">$arg</span> <span style="color: #339933;">=</span> shortcode_atts<span style="color: #009900;">&#40;</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span>
			<span style="">'id'</span> <span style="color: #339933;">=&amp;</span>gt; <span style="color: #000000; font-weight: bold;">FALSE</span><span style="color: #339933;">,</span>
		<span style="color: #009900;">&#41;</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arg</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
		<span style="color: #b1b100;">if</span><span style="color: #009900;">&#40;</span> <span style="color: #339933;">!</span> <span style="color: #000088;">$arg</span><span style="color: #009900;">&#91;</span><span style="">'id'</span><span style="color: #009900;">&#93;</span> <span style="color: #009900;">&#41;</span>
			<span style="color: #b1b100;">return</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">FALSE</span> <span style="color: #009900;">&#41;</span>;
&nbsp;
		<span style="color: #b1b100;">return</span><span style="color: #009900;">&#40;</span> <span style="color: #990000;">str_replace</span><span style="color: #009900;">&#40;</span> <span style="">'%%id%%'</span><span style="color: #339933;">,</span> <span style="color: #000088;">$arg</span><span style="color: #009900;">&#91;</span><span style="">'id'</span><span style="color: #009900;">&#93;</span><span style="color: #339933;">,</span> <span style="">'
&lt;div id=&quot;slideshare-%%id%%&quot; class=&quot;embed slideshare&quot;&gt;&lt;object width=&quot;425&quot; height=&quot;348&quot; data=&quot;https://s3.amazonaws.com:443/slideshare/ssplayer.swf?id=%%id%%&quot; type=&quot;application/x-shockwave-flash&quot;&gt;&lt;param name=&quot;wmode&quot; value=&quot;transparent&quot; /&gt;&lt;param name=&quot;src&quot; value=&quot;https://s3.amazonaws.com:443/slideshare/ssplayer.swf?id=%%id%%&quot; /&gt;&lt;/object&gt;&lt;/div&gt;
'</span> <span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;
	<span style="color: #009900;">&#125;</span>
&nbsp;
	add_shortcode<span style="color: #009900;">&#40;</span><span style="">'slideshare'</span><span style="color: #339933;">,</span> <span style="color: #990000;">array</span><span style="color: #009900;">&#40;</span><span style="color: #339933;">&amp;</span>amp;<span style="color: #000088;">$this</span><span style="color: #339933;">,</span> <span style="">'shortcode_slideshare'</span><span style="color: #009900;">&#41;</span><span style="color: #009900;">&#41;</span>;</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13448/slideshare-wordpress-embed-shortcode/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Usability vs. Open Source</title>
		<link>http://maisonbisson.com/blog/post/13526/usability-vs-open-source/</link>
		<comments>http://maisonbisson.com/blog/post/13526/usability-vs-open-source/#comments</comments>
		<pubDate>Mon, 09 Mar 2009 15:43:17 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Dispatches]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[joomla]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[usability]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13526</guid>
		<description><![CDATA[
This article comparing the usability of Joomla vs. WordPress has already been linked by everybody&#8217;s uncle, but it&#8217;s still worth a look.
I find it amusing, however, that none of the comments so far on that blog post mention the commitment that the core WordPress team appears to have on making blogging fun. If you start [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13526"><!-- &nbsp; --></abbr>
<p>This article comparing the <a title="Playing With Wire » Open Source and usability: Joomla vs. WordPress" href="http://www.playingwithwire.com/2009/03/open-source-and-usability-joomla-vs-wordpress/">usability of Joomla vs. WordPress</a> has already been linked by everybody&#8217;s uncle, but it&#8217;s still worth a look.</p>
<p>I find it amusing, however, that none of the comments so far on that blog post mention the commitment that the core WordPress team appears to have on making blogging <em>fun</em>. If you start with the goal of making something fun, then add sophistication to make it flexible without being complex, you&#8217;ll get a very different result than you would if you started with different goals.</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13526/usability-vs-open-source/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Scriblio 2.7 Released</title>
		<link>http://maisonbisson.com/blog/post/13484/scriblio-27-released/</link>
		<comments>http://maisonbisson.com/blog/post/13484/scriblio-27-released/#comments</comments>
		<pubDate>Wed, 25 Feb 2009 16:00:15 +0000</pubDate>
		<dc:creator>Casey Bisson</dc:creator>
				<category><![CDATA[Libraries & Networked Information]]></category>
		<category><![CDATA[Technology]]></category>
		<category><![CDATA[lib20]]></category>
		<category><![CDATA[libraries]]></category>
		<category><![CDATA[library 2.0]]></category>
		<category><![CDATA[release]]></category>
		<category><![CDATA[scriblio]]></category>
		<category><![CDATA[Scriblio 2.7]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://maisonbisson.com/?p=13484</guid>
		<description><![CDATA[

My slides for my presentation yesterday at code4lib are available both as a 2.7MB QuickTime and a 7.8 MB PDF, while the gist of talk went something like this:
Scriblio is an open source WordPress plugin that adds the ability to search, browse, and create structured data to the the popular blog/content management platform. And WordPress [...]]]></description>
			<content:encoded><![CDATA[<abbr class="unapi-id" title="maisonbisson-13484"><!-- &nbsp; --></abbr>
<p><a href="http://www.flickr.com/photos/maisonbisson/3308721449/" title="Scriblio 2.7 Released by misterbisson, on Flickr"><img src="http://farm4.static.flickr.com/3565/3308721449_25cf0efe01.jpg" width="500" height="375" alt="Scriblio 2.7 Released" /></a></p>
<p>My slides for my presentation yesterday at <a href="http://code4lib.org/conference/2009/">code4lib</a> are available both as a <a href="http://oz.plymouth.edu/~cbisson/presentations/code4lib2009_2009Feb24.mov">2.7MB QuickTime</a> and a <a href="http://oz.plymouth.edu/~cbisson/presentations/code4lib2009_2009Feb24.pdf">7.8 MB PDF</a>, while the gist of talk went something like this:</p>
<p><a href="http://about.scriblio.net/">Scriblio</a> is an <a href="http://svn.wp-plugins.org/scriblio/trunk/LICENSE.txt">open source</a> <a href="http://wordpress.org/extend/plugins/scriblio/">WordPress plugin</a> that adds the ability to search, browse, and create structured data to the the popular blog/content management platform. And WordPress adds great ease of use, permalinks, comments/trackbacks/pingbacks, and other social and web-centric features to that structured data. But that&#8217;s not news. The news is that Scriblio now has an internal data model that supports much more sophisticated uses (slides 3 and 4). Whereas previous versions of Scriblio were mostly just display and social interaction interfaces to data that&#8217;s created or managed elsewhere, this new version supports soup to nuts creation and management of collections. <a href="http://archives.colby-sawyer.edu/">Colby-Sawyer College&#8217;s archive</a> (slide 5) is the first to implement this (take note of how <a href="http://archives.colby-sawyer.edu/browse/">the horizontal search layout makes the facets more visible and usable</a>).</p>
<p>And that new data model also improves the usefulness of Scriblio to regular libraries (<a href="http://collingswoodlib.org/">Collingswood (NJ) Public Library</a> is shown on slide 6). Because Scriblio has an internal awareness of the metadata, it can automatically merge records from multiple sources (or multiple copies of the same record from the same source). The source of each piece of metadata in a record is identified and preserved (see the sourceid column in slides 7,8,9), allowing records to contain data from multiple sources (each with, perhaps, its own licensing terms). A practical example is enriching book records with data from <a href="http://www.tr.librarything.com/work/683408">LibraryThing&#8217;s Common Knowledge</a> <a href="http://www.librarything.com/services/librarything.ck.getwork.php">web service</a>, making that data part of the index and facets in the local catalog, while also properly crediting the service when a record contains that data.</p>
<p>The automated merging of records enables a few new applications. Among them: the merging of an A to Z periodical list with the ILS&#8217;s inventory, or the creation of a union catalog from several systems. Slide 11 shows a prototype union catalog that shows materials (and their real-time availability) from three institutions in New Hampshire. Assembling that catalog was as easy as entering each ILS&#8217;s hostname and record number range in the harvester (slide 12).</p>
<p>I didn&#8217;t mention it during the presentation, but Scriblio is now built to work well in both regular <a href="http://wordpress.org/">WordPress</a> as well as <a href="http://mu.wordpress.org/">WordPress MU</a>, the multi-user version of WordPress that allows a single installation to host many different sites (think <a href="http://wordpress.com/">WordPress.com</a>) at a <a href="http://en.wikipedia.org/wiki/Marginal_cost">marginal cost</a> to the hosting organization that approaches zero. The work to make Scriblio compatible with WordPress MU was <a href="http://www.neh.gov/ODH/Default.aspx?tabid=111&amp;id=69">supported in part by the National Endowment for the Humanities</a> (there&#8217;s lots more to say about that project soon).</p>
]]></content:encoded>
			<wfw:commentRss>http://maisonbisson.com/blog/post/13484/scriblio-27-released/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
<enclosure url="http://oz.plymouth.edu/~cbisson/presentations/code4lib2009_2009Feb24.mov" length="2829832" type="video/quicktime" />
		</item>
	</channel>
</rss>