<?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>The Life of Lew Ayotte &#187; wordpress</title>
	<atom:link href="http://lewayotte.com/tag/wordpress/feed/" rel="self" type="application/rss+xml" />
	<link>http://lewayotte.com</link>
	<description>Pursue righteousness, godliness, faith, love, perseverance and gentleness. Fight the good fight of faith; take hold of the eternal life to which you were called... - 1 Timothy 6:11-12</description>
	<lastBuildDate>Wed, 09 May 2012 16:30:56 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
<xhtml:meta xmlns:xhtml="http://www.w3.org/1999/xhtml" name="robots" content="noindex" />
		<item>
		<title>Custom WordPress Plugin Update Repository</title>
		<link>http://lewayotte.com/2012/04/18/custom-wordpress-plugin-update-repository/</link>
		<comments>http://lewayotte.com/2012/04/18/custom-wordpress-plugin-update-repository/#comments</comments>
		<pubDate>Wed, 18 Apr 2012 16:30:31 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[add_filter]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=3035</guid>
		<description><![CDATA[I have recently been spending a lot of time developing the IssueM plugin for a company I do a lot of contract work for. IssueM is an issue manager plugin for WordPress, to manage issues for online magazines, periodicals, and such. The idea for IssueM started a couple years ago, and even started as a plugin, [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2012/04/18/custom-wordpress-plugin-update-repository/' addthis:title='Custom WordPress Plugin Update Repository ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I have recently been spending a lot of time developing the <a  href="http://issuem.com/">IssueM</a> plugin for a company I do a lot of contract work for. IssueM is an issue manager plugin for WordPress, to manage issues for online magazines, periodicals, and such. The idea for IssueM started a couple years ago, and even started as a plugin, then morphed into a theme, and now it is back to a plugin. There was a lot of reasoning for these changes, but the biggest was that we wanted to make a plugin that could be used in any theme. Since the IssueM theme didn&#8217;t suit everyone&#8217;s needs, it was much easier to turn the functionality into shortcodes and widgets. Plus, since WordPress 3.1, we have all the capabilities we need to make a plugin extremely useful and successful in this arena.</p>
<p>Anyway, since this is a premium plugin we need a way to notify people of plugin updates. Frankly, I have never needed to do this, so I needed to figure it out. Luckily, I have a copy of <a  href="http://www.amazon.com/gp/product/0470916222?ie=UTF8&#038;tag=phrugal-20&#038;linkCode=shr&#038;camp=213733&#038;creative=393185&#038;creativeASIN=0470916222&#038;ref_=sr_1_1&#038;qid=1334712096&#038;sr=8-1">Professional WordPress Plugin Development</a> and in Chapter 9 there is very simple example of exactly what I wanted to do. Unluckily, the example doesn&#8217;t work&#8230; well, not entirely. It was always reporting an update, even if it was on the latest version. But I had enough information to trace down what was happening and figure out what I needed to change. By the way, the example code for the book is available from the <a  href="http://www.wrox.com/WileyCDA/WroxTitle/Professional-WordPress-Plugin-Development.productCd-0470916222,descCd-DOWNLOAD.html">publisher&#8217;s website</a>.</p>
<p>So, without further adieu, this is a modified version of what I did:</p>
<p>This is the code I added to my plugin:</p>
<pre name="code" class="php">
function my_plugin_plugins_api( $false, $action, $args ) {

	$plugin_slug = plugin_basename( __FILE__ );

	// Check if this plugins API is about this plugin
	if( $args->slug != $plugin_slug )
		return false;

	// POST data to send to your API
	$args = array(
		'action' 	=> 'get-plugin-information'
	);

	// Send request for detailed information
	$response = $this->my_plugin_api_request( $args );

	return $response;

}
add_filter( 'plugins_api', 'my_plugin_plugins_api', 10, 3 );

function my_plugin_update_plugins( $transient ) {

	// Check if the transient contains the 'checked' information
	// If no, just return its value without hacking it
	if ( empty( $transient->checked ) )
		return $transient;

	// The transient contains the 'checked' information
	// Now append to it information form your own API
	$plugin_path = plugin_basename( __FILE__ );

	// POST data to send to your API
	$args = array(
		'action' 	=> 'check-latest-version'
	);

	// Send request checking for an update
	$response = $this->my_plugin_api_request( $args );

	// If there is a new version, modify the transient
	if( version_compare( $response->new_version, $transient->checked[$plugin_path], '>' ) )
		 $transient->response[$plugin_path] = $response;

	return $transient;

}
add_filter( 'pre_set_site_transient_update_plugins', 'my_plugin_update_plugins' );

function my_plugin_api_request( $args ) {

	// Send request
	$request = wp_remote_post( http://api.url/location, array( 'body' => $args ) );

	if ( is_wp_error( $request ) || 200 != wp_remote_retrieve_response_code( $request ) )
		return false;

	$response = unserialize( wp_remote_retrieve_body( $request ) );

	if ( is_object( $response ) )
		return $response;
	else
		return false;

}
</pre>
<p>Then I setup a WordPress install for my API and created a custom template for the API page</p>
<pre name="code" class="php">
/**
 * Template Name: API
**/

$action = $_REQUEST['action'];

// Create new object
$response = new stdClass;

switch( $action ) {

    // API is asked for the existence of a new version of the plugin
    case 'check-latest-version':
        $response->slug = 'my_plugin_slug';
        $response->new_version = '1.0.2';
        $response->url = 'http://plugin.url/';
        $response->package = 'http://plugin.url/download/location';
		break;

    // Request for detailed information
    case 'get-plugin-information':
        $response->name = 'my_plugin_name';
        $response->slug = 'my_plugin_slug';
        $response->requires = '3.3';
        $response->tested = '3.3.1';
	$response->rating = 100.0; //just for fun, gives us a 5-star rating :)
        $response->num_ratings = 1000000000; //just for fun, a lot of people rated it :)
        $response->downloaded = 1000000000; //just for fun, a lot of people downloaded it :)
        $response->last_updated = "2012-04-15";
        $response->added = "2012-02-01";
		$response->homepage = "http://plugin.url/";
        $response->sections = array(
            'description' =>  'Add a description of your plugin',
            'changelog' =>  'Add a list of changes to your plugin'
        );
        $response->download_link = 'http://plugin.url/download/location';
        break;

}

echo serialize( $response );
</pre>
<p>This isn&#8217;t exactly what I did, but it&#8217;s much more basic. Here are some things you can think about. First, the IssueM plugin uses an API key, so I send the API Key to api to verify the user has the right to update the plugin (say they don&#8217;t pay next year or something). The download_link setting is dynamic, for IssueM, it&#8217;s something like http://api.url/download/location?api=API_KEY. Then I have a separate script at the download location that will also verify the API Key and will send the latest IssueM plugin (which is located in a hidden directory). I also didn&#8217;t hard-code the downloaded argument, I actually track the downloads by using the dynamic download script. So my $response->downloaded actually equals get_option( &#8216;my_plugin_downloads&#8217; ).</p>
<p>The download script I setup looks something like this:</p>
<pre name="code" class="php">
/**
 * Template Name: Download Latest Version
 *
**/

$downloads = get_option( 'my_plugin_downloads', 100 );
update_option( 'my_plugin_downloads', ++$downloads );

$file = '/physical/location/of/your/file.zip';
$file_content = file_get_contents( $file );

header( 'Content-type: application/force-download' );
header( 'Content-Disposition: attachment; filename="my_plugin.zip"' );

echo $file_content;

exit;
</pre>
<p>You can completely customize and expand this code to do whatever you want. By adding extra arguments being sent to your API, you could have several plugins in this same repository. You can send API key information, host information, and anything else you&#8217;d need/want.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2012/04/18/custom-wordpress-plugin-update-repository/' addthis:title='Custom WordPress Plugin Update Repository ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2012/04/18/custom-wordpress-plugin-update-repository/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Fun with SEO Spammers</title>
		<link>http://lewayotte.com/2012/01/26/fun-with-seo-spammers/</link>
		<comments>http://lewayotte.com/2012/01/26/fun-with-seo-spammers/#comments</comments>
		<pubDate>Thu, 26 Jan 2012 12:30:40 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[funny]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[seo]]></category>
		<category><![CDATA[spam]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=3001</guid>
		<description><![CDATA[I am involved in a joint venture with one of my close friends, Glenn Ansley. It&#8217;s the World&#8217;s Best Event Calendar Plugin for WordPress (in my humble opinion). Well, if you have a website, you know you&#8217;re going to get typical SPAM through your contact form, from so-called &#8220;SEO Experts&#8221;. We received one the other [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2012/01/26/fun-with-seo-spammers/' addthis:title='Fun with SEO Spammers ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I am involved in a joint venture with one of my close friends, <a  href="http://glennansley.com/">Glenn Ansley</a>. It&#8217;s the <a  href="http://calendar-plugin.com/">World&#8217;s Best Event Calendar Plugin for WordPress</a> (in my humble opinion). Well, if you have a website, you know you&#8217;re going to get typical SPAM through your contact form, from so-called &#8220;SEO Experts&#8221;. We received one the other day that I thought was especially compelling, so much so that I decided to reply to him. Here is the brief email exchange&#8230;</p>
<blockquote><p>Name: Carson White</p>
<p>Email: <a  href="mailto:carsonwhite@sti-creative.com">carsonwhite@sti-creative.com</a></p>
<p>Comments: Hi,</p>
<p>We carried out a preliminary analysis on your website and discovered the following areas of concern.<br />
1.    Your website attracts limited traffic, which affects potential sales.<br />
2.    Your keywords don’t feature in Google first page, which affects visibility.<br />
3.    Your back links are not good enough, which affects link popularity.<br />
4.    Your website is not properly promoted, which affects the overall score.<br />
We are a Search Engine Optimization service provider and can assist you in overcoming the above mentioned problems. We can perform a more detailed analysis on your website and provide you the plan of action of how we can promote the same.</p>
<p>Please let us know if you require the SEO REPORT on your website at no cost.</p>
<p>Best Regards,<br />
Carson<br />
Systems Technology International Inc.<br />
Michigan: 39555 Orchard Hill Place, Suite 461, Novi, Michigan-48375<br />
New York: 9921 4th Ave, Brooklyn, NY 11209<br />
<a  href="http://www.sti-cs.com">www (dot) sti-cs (dot) com</a></p>
<p>Notice: Under The Bill 1618 Title iii passed by the 105th US Congress this mail may not be considered SPAM as long as the contact information is included and a method to be removed from our mailing list stated. If you are not interested in receiving our e-mails then please reply with REMOVE in the subject line and your ID will be removed from our mailing list. We apologize for the inconvenience caused to you.</p></blockquote>
<p>And my reply&#8230;</p>
<blockquote><p>Hi Carson,</p>
<p>I&#8217;ve carried out a preliminary analysis of your email and discovered the following areas of concern.<br />
1.    You think we are suckers.<br />
2.    You most likely implement black-hat &#8220;SEO&#8221; services that end up hurting companies, rather than helping them.<br />
3     You probably over charge your clients for a service that none of them need. Google actually does a pretty good job of figuring out what is important and what isn&#8217;t&#8230; without people trying to game the system.<br />
4.    You emailed us about our site not ranking well, but how do you explain finding our site?<br />
5.    The bill S.1618 Title III was passed by the Senate, but was not passed by the House. It takes both the House and the Senate to pass a law. Furthermore, a similar bill, H.R. 3888 was passed by the House, but was not passed by the Senate, thus and again, not making it law. Therefore, your email is SPAM.</p>
<p>We are intelligent human beings and can assist you in overcoming the above mentioned problems. We can help develop a training in ethics, philosophy, and logic and provide you with a plan of action of how to stop SPAMMING and SCAMMING innocent businesses.</p>
<p>Please let us know if you require these lessons at much cost.</p>
<p>Best Regards,</p>
<p><span style="color: #888888;">Lew Ayotte<br />
Full Throttle Development, LLC<br style="color: #888888;" /> <a  href="http://fullthrottledevelopment.com/" target="_blank">http://<wbr>fullthrottledevelopment.com</wbr></a><br />
<a  href="http://twitter.com/full_throttle" target="_blank">http://twitter.com/full_<wbr>throttle</wbr></a><br />
<a  href="http://twitter.com/lewayotte" target="_blank">http://twitter.com/lewayotte</a></span></p></blockquote>
<p>For some reason he never replied.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2012/01/26/fun-with-seo-spammers/' addthis:title='Fun with SEO Spammers ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2012/01/26/fun-with-seo-spammers/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Globally Disable Comments and Pings in WordPress Multi-Site</title>
		<link>http://lewayotte.com/2011/10/07/globally-disable-comments-and-pings-in-wordpress-multi-site/</link>
		<comments>http://lewayotte.com/2011/10/07/globally-disable-comments-and-pings-in-wordpress-multi-site/#comments</comments>
		<pubDate>Fri, 07 Oct 2011 20:30:31 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[action]]></category>
		<category><![CDATA[add_filter]]></category>
		<category><![CDATA[filter]]></category>
		<category><![CDATA[hook]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=2860</guid>
		<description><![CDATA[Over the past couple years I&#8217;ve worked on a number of WordPress Multi-Sites that wanted to have their comments and pings disabled. In other words, they weren&#8217;t accepting comments and didn&#8217;t want them to be displayed. Normally this is easy to accomplish, simply turn off comments in the back end. However, SPAMMERS knowing exactly how [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2011/10/07/globally-disable-comments-and-pings-in-wordpress-multi-site/' addthis:title='Globally Disable Comments and Pings in WordPress Multi-Site ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>Over the past couple years I&#8217;ve worked on a number of WordPress Multi-Sites that wanted to have their comments and pings disabled. In other words, they weren&#8217;t accepting comments and didn&#8217;t want them to be displayed. Normally this is easy to accomplish, simply turn off comments in the back end.</p>
<p>However, SPAMMERS knowing exactly how WordPress works and how to inject comment SPAM into WordPress. Though, if you do not have comments automatically approved, they definitely should not appear&#8230; if a comment does get injected, the WordPress administrator (and author) should receive a notification of a pending comment. So, there is a simple way in WordPress Multi-Site to just set all comment and ping submissions to false. Just stick this little bit of code into a php file in the mu-plugins directory:</p>
<pre name="code" class="php">
add_filter( 'pings_open', '__return_false', 10, 2 );
add_filter( 'comments_open', '__return_false', 10, 2 );
</pre>
<p>One of the Multi-Site installations that I have this enabled in wanted to allow comments on two of their sites. If this is something you need, just setup a mu-plugin php file that looks like this:</p>
<pre name="code" class="php">
function comments_and_pings_closed( $open, $post_id ) {

	global $blog_id;

	$comment_sites = array( 10, 15 ); // Site IDs of site that you don't want automatically disabled

	if ( in_array( $blog_id, $comment_sites ) ) {

		return $open;

	}

	return false;

}
add_filter( 'pings_open', 'comments_and_pings_closed', 10, 2 );
add_filter( 'comments_open', 'comments_and_pings_closed', 10, 2 );
</pre>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2011/10/07/globally-disable-comments-and-pings-in-wordpress-multi-site/' addthis:title='Globally Disable Comments and Pings in WordPress Multi-Site ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2011/10/07/globally-disable-comments-and-pings-in-wordpress-multi-site/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>How to search for user last name in the WordPress Users dashboard</title>
		<link>http://lewayotte.com/2011/05/03/how-to-search-for-user-last-name-in-the-wordpress-users-dashboard/</link>
		<comments>http://lewayotte.com/2011/05/03/how-to-search-for-user-last-name-in-the-wordpress-users-dashboard/#comments</comments>
		<pubDate>Tue, 03 May 2011 21:30:50 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[actions]]></category>
		<category><![CDATA[functions.php]]></category>
		<category><![CDATA[hooks]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=2500</guid>
		<description><![CDATA[Have a client with almost 2500 users in their WordPress site and they wanted to be able to search their users by last name. By default this is not enabled in WordPress core, so here is a quick function/hook you can add to your functions.php file to enable this: function custom_user_list_search( $query ) { if [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2011/05/03/how-to-search-for-user-last-name-in-the-wordpress-users-dashboard/' addthis:title='How to search for user last name in the WordPress Users dashboard ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>Have a client with almost 2500 users in their WordPress site and they wanted to be able to search their users by last name. By default this is not enabled in WordPress core, so here is a quick function/hook you can add to your functions.php file to enable this:</p>
<pre name="code" class="php">function custom_user_list_search( $query ) {

	if ( is_admin() ) {

		global $wpdb;

		if ( is_array( $qv = $query-&gt;query_vars ) &amp;&amp; ( $s = trim( $qv['search'], '* \t\n\0\x0B' ) )
				&amp;&amp; ( $s = "%" . esc_sql( like_escape( $s ) ) . "%" ) ) {

			if ( !preg_match( '/' . $wpdb-&gt;usermeta . '/', $query-&gt;query_from ) )
				$query-&gt;query_from .= " INNER JOIN `" . $wpdb-&gt;usermeta . "` ON `" . $wpdb-&gt;users . "`.`ID` = `" . $wpdb-&gt;usermeta . "`.`user_id`";

			$query-&gt;query_where .= " OR ( `" . $wpdb-&gt;usermeta . "`.`meta_key` = 'last_name' AND `" . $wpdb-&gt;usermeta . "`.`meta_value` LIKE '" . $s . "' ) ";

		}

	}

	return $query;
}
add_filter( 'pre_user_query', 'custom_user_list_search', 15 );</pre>
<p>I will probably expand this a little and create a WordPress plugin for it (if I can find the time).</p>
<p>NOTE: The trim regex should be this &#8211; &#8216;* \t\n\r\0\x0B&#8217; &#8211; but the plugin I&#8217;m using is stripping the \r</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2011/05/03/how-to-search-for-user-last-name-in-the-wordpress-users-dashboard/' addthis:title='How to search for user last name in the WordPress Users dashboard ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2011/05/03/how-to-search-for-user-last-name-in-the-wordpress-users-dashboard/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Rate Limiting with WordPress&#8217; Transient API</title>
		<link>http://lewayotte.com/2010/11/04/rate-limiting-with-wordpress-transient-api/</link>
		<comments>http://lewayotte.com/2010/11/04/rate-limiting-with-wordpress-transient-api/#comments</comments>
		<pubDate>Thu, 04 Nov 2010 16:30:38 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[api]]></category>
		<category><![CDATA[transient]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=2000</guid>
		<description><![CDATA[I run a web app called leenk.me, it&#8217;s a Social Media Optimization application for WordPress. Basically it publishes your WordPress content to Twitter / Facebook / Google Buzz whenever you publish new content to your website. There are a lot of &#8220;advertisers&#8221; who have been signing up for the service and one in particular has [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/11/04/rate-limiting-with-wordpress-transient-api/' addthis:title='Rate Limiting with WordPress&#8217; Transient API ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I run a web app called <a  href="http://leenk.me">leenk.me</a>, it&#8217;s a Social Media Optimization application for WordPress. Basically it publishes your WordPress content to Twitter / Facebook / Google Buzz whenever you publish new content to your website. There are a lot of &#8220;advertisers&#8221; who have been signing up for the service and one in particular has been hitting the service hard &#8212; really hard &#8212; about 4000 API requests in an hour.</p>
<p>This is a pretty big problem, all these social networks rate limit their connections (close to 300 requests per hour). So making 4000 requests in an hour could cause them to ban the user, or worse, ban leenk.me. So I&#8217;ve had to implement a rate limit of my own. I thought about doing this with iptables to block anyone who exceeds a certain number of requests per hour, but the violating users wouldn&#8217;t know what happened. I really <del datetime="2010-11-04T13:18:22+00:00">wanted</del> needed a way to prevent them from over-connecting to the social networks.</p>
<p>This is where the <a  href="http://codex.wordpress.org/Transients_API">WordPress Transients API</a> comes in. The transients API is very similar to the Options API but with the added feature of an expiration time. This is basically how the transients API works in WordPress:</p>
<pre class="php" name='code'>// Save a transient to the DB
set_transient( $transient_name, $transient_value, $expiration );</pre>
<ul>
<li>$transient_name &#8211; A unique identifier for your cached data.</li>
<li>$transient_value &#8211; Data to save, either a regular variable or an array/object. The API will handle serialization of complex data for you.</li>
<li>$expiration &#8211; Number of seconds to keep the data before refreshing.</li>
</ul>
<pre class="php" name='code'>// Get value of a transient from the DB
$transient_value = get_transient( $transient_name );</pre>
<pre class="php" name='code'>// Delete a transient from the DB
delete_transient( $transient_name );</pre>
<p>The only problem with WP Transients is that there isn&#8217;t a good way to create &#8220;rolling transients&#8221; (as I call them). A rolling transient is a transient that rolls in time. In other words, I want to rate-limit a users connection by 1 hour from their current API call, but if the users does not make any API calls within the hour the transient should expire.</p>
<p>This is how I implemented &#8220;rolling transients&#8221;:</p>
<pre class="php" name='code'>$call_limit = 350; // API calls (in an hour)
$time_limit = 60 * 60; // 1 hour (in seconds)
$transient_name = $host  . "_rate_limit"; // Using their host name as the unique identifier

// Check to see if there are any transients that match the name, if not create a new one
if ( false === ( $calls = get_transient( $transient_name ) ) ) {
	$calls[] = time();
	set_transient( $transient, $calls, $time_limit ); // Use an array of time() stamps for rolling effect
} else {
	// There is already a transient with this name
	$calls[] = time(); // Add a new time() stamp to the $calls array
	set_transient( $transient, $calls, $time_limit ); // Reset the transient (w/ expiration time)

	$call_count = count( $calls ); // How many calls have been made

	if ( $call_limit < $call_count ) { // If we're over the call limit, remove expired timestamps
		// Shift time from first element of array
		while ( $call = array_shift( $calls ) ) {
			// If time is >= current time - time limit, then it belongs in the array
			// Add it back and reset the transient
			if ( $call >= ( time() - $time_limit ) ) {
				array_unshift( $calls, $call );
				set_transient( $transient, $calls, $time_limit );
				break; // Stop processing, we're within the time_limit time now.
			}
		}

		// If we're still over the call limit, they've made too many requests in the time limit
		if ( $call_limit <= count( $calls ) ) {
			// The session needs to be killed
			die('Error: You have exceeded your rate limit for API calls, only ' . $call_limit . ' API calls are allowed every ' . $time_limit . ' seconds.');
		}
	}
}</pre>
<p>With this code, you now have rolling transients... if your users exceed the number of calls within the past hour they will be rejected. If not, the transient will expire as it should. Let me know if you found this useful or if you have any tips for making it better (it seems a little "hacky" to me).</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/11/04/rate-limiting-with-wordpress-transient-api/' addthis:title='Rate Limiting with WordPress&#8217; Transient API ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/11/04/rate-limiting-with-wordpress-transient-api/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>WordPress Weekly Patch &#8211; Escaped Apostrophe &#8211; Trac #14996</title>
		<link>http://lewayotte.com/2010/10/01/wordpress-weekly-patch-escaped-apostrophe-trac-14996/</link>
		<comments>http://lewayotte.com/2010/10/01/wordpress-weekly-patch-escaped-apostrophe-trac-14996/#comments</comments>
		<pubDate>Fri, 01 Oct 2010 21:30:34 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1946</guid>
		<description><![CDATA[Glenn Ansley started this &#8220;WordPress Weekly Patch&#8221; idea. Where you submit one patch a week to WordPress core. I&#8217;ve been doing it, but have definitely missed the &#8220;weekly&#8221; part of &#8220;weekly&#8221; :). I&#8217;ve just been way too busy. Regardless, this is my patch for the week &#8211; http://core.trac.wordpress.org/ticket/14996 If you insert a Video/Audio/Media link and [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/10/01/wordpress-weekly-patch-escaped-apostrophe-trac-14996/' addthis:title='WordPress Weekly Patch &#8211; Escaped Apostrophe &#8211; Trac #14996 ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>Glenn Ansley started this &#8220;WordPress Weekly Patch&#8221; idea. Where you submit one patch a week to WordPress core. I&#8217;ve been doing it, but have definitely missed the &#8220;weekly&#8221; part of &#8220;weekly&#8221; :). I&#8217;ve just been way too busy.</p>
<p>Regardless, this is my patch for the week &#8211; <a  href="http://core.trac.wordpress.org/ticket/14996">http://core.trac.wordpress.org/ticket/14996</a></p>
<p>If you insert a Video/Audio/Media link and have an apostrophe in the title, the link will have tried to escape the apostrophe with a backslash. My patch removes the unnecessary backslash. Pretty simple to fix.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/10/01/wordpress-weekly-patch-escaped-apostrophe-trac-14996/' addthis:title='WordPress Weekly Patch &#8211; Escaped Apostrophe &#8211; Trac #14996 ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/10/01/wordpress-weekly-patch-escaped-apostrophe-trac-14996/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Using WordPress&#8217; Built-in Media Upload</title>
		<link>http://lewayotte.com/2010/09/27/using-wordpress-built-in-media-upload/</link>
		<comments>http://lewayotte.com/2010/09/27/using-wordpress-built-in-media-upload/#comments</comments>
		<pubDate>Mon, 27 Sep 2010 19:00:15 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[media_handle_upload]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1916</guid>
		<description><![CDATA[If you found this post, useful, please consider donating 1$ to help fund my and my wife&#8217;s adoption&#8230; click here for details. I was working with a client a few weeks ago. They wanted to create a customer portal that allowed their customers to upload files to their website. Once their clients have uploaded the [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/27/using-wordpress-built-in-media-upload/' addthis:title='Using WordPress&#8217; Built-in Media Upload ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p><a  href="http://nostretchmarksrequired.com/donate"><strong>If you found this post, useful, please consider donating 1$ to help fund my and my wife&#8217;s adoption&#8230; click here for details.</strong></a></p>
<p>I was working with a client a few weeks ago. They wanted to create a customer portal that allowed their customers to upload files to their website. Once their clients have uploaded the files, they needed to be able to download and delete the files from the server. There were a few plugins in the WordPress repository that had some form of media uploading, but none of them seemed to use WordPress&#8217; built-in functions. So, I dug in a bit and figured out how WordPress does it so I could easily replicate that functionality.</p>
<p>The main function that to know about is <em>media_handle_upload()</em>. It is the bread and butter of WordPress&#8217; media upload. It takes up to 4 arguments and returns one variable.</p>
<p>From the media.php file:</p>
<blockquote><p>@param string $file_id Index into the {@link $_FILES} array of the upload<br />
@param int $post_id The post ID the media is associated with<br />
@param array $post_data allows you to overwrite some of the attachment<br />
@param array $overrides allows you to override the {@link wp_handle_upload()} behavior<br />
@return int the ID of the attachment</p></blockquote>
<p>For my basic needs, I only needed to worry about the first two arguments, <em>$file_id</em> and <em>$post_id</em> &#8230; and really the the $post_id is optional unless you want to associate the file as an attachment to a specific post (which I did).</p>
<p>The <em>media_handle_upload()</em> function is is part of wp-admin, so for good measure I included wp-admin/includes/admin.php. This probably isn&#8217;t necessary if you&#8217;re in the backend &#8212; but if you have a front-end page that your logged in clients will use, then you will need to do the same.</p>
<h3>What The Client Needed</h3>
<p>A membership portal that allowed clients to log in, go to the &#8220;upload&#8221; section, and upload a file. Then to be able to go to a &#8220;files&#8221; section to retrieve and delete the files. To do this I created two theme templates, &#8220;Client Files&#8221; and &#8220;Client File Upload&#8221;.</p>
<h3>File Upload</h3>
<p>First a simple form with a file input&#8230;</p>
<pre class="html">	&lt;form id="file-form" enctype="multipart/form-data" action="&lt;?php echo $_SERVER['REQUEST_URI']; ?&gt;" method="POST"&gt;
	&lt;p id="async-upload-wrap"&gt;
	&lt;label for="async-upload"&gt;Upload&lt;/label&gt;
	&lt;input type="file" id="async-upload" name="async-upload"&gt; &lt;input type="submit" value="Upload" name="html-upload"&gt;
	&lt;/p&gt;

	&lt;p&gt;
	&lt;input type="hidden" name="post_id" id="post_id" value="1199" /&gt;
	&lt;?php wp_nonce_field('client-file-upload'); ?&gt;
	&lt;input type="hidden" name="redirect_to" value="&lt;?php echo $_SERVER['REQUEST_URI']; ?&gt;" /&gt;
	&lt;/p&gt;

	&lt;p&gt;
	&lt;input type="submit" value="Save all changes" name="save" style="display: none;"&gt;
	&lt;/p&gt;
	&lt;/form&gt;</pre>
<p>The form calls itself, so I needed a function to check if the form has been submitted and calls the media_handle_upload() function&#8230;</p>
<pre class="php">if ( isset( $_POST['html-upload'] ) &amp;&amp; !empty( $_FILES ) ) {
	require_once(ABSPATH . 'wp-admin/includes/admin.php');
	$id = media_handle_upload('async-upload', 1199); //post id of Client Files page
	unset($_FILES);
	if ( is_wp_error($id) ) {
		$errors['upload_error'] = $id;
		$id = false;
	}

	if ($errors) {
		echo "&lt;p&gt;There was an error uploading your file.&lt;/p&gt;";
	} else {
		echo "&lt;p&gt;Your file has been uploaded.&lt;/p&gt;";
	}
}</pre>
<p>I chose to hard code the post ID 1199 in this code. Not the best solution, but it serves its purpose. 1199 is the page ID of the page I created to have all the attachments associated with. This solves the next problem, how to display all the uploaded files. This way my client can download and delete them the files from an easy to access page.</p>
<h3>Client Files</h3>
<p>The client files page is another template, I actually set it as a private page and added some permissions so only the administrator can see the page. Since all the attachments uploaded should be associated with this page, I needed to create a special query that got all those attachments and display them in a neatly organized table&#8230;</p>
<pre class="php">$args = array(
	'post_type' =&gt; 'attachment',
	'numberposts' =&gt; null,
	'post_status' =&gt; null,
	'post_parent' =&gt; 1199 //Post ID of Client Files page
);
$attachments = get_posts($args);

if ($attachments) { ?&gt;
&lt;form id="file-form" action="&lt;?php echo $_SERVER['REQUEST_URI']; ?&gt;" method="POST"&gt;
	&lt;table style="width: 100%;"&gt;
	&lt;tr&gt;
		&lt;td style="width: 50px; text-align:center;"&gt;Delete?&lt;/td&gt;
		&lt;td style="width: 150px;"&gt;Attachment&lt;/td&gt;
		&lt;td style="width: 50px;"&gt;Username&lt;/td&gt;
		&lt;td style="width: 150px;"&gt;Name&lt;/td&gt;
	&lt;/tr&gt;

	&lt;?php
	foreach ($attachments as $attachment) {
	?&gt;
	&lt;tr&gt;
		&lt;td style="text-align:center;"&gt;&lt;input type="checkbox" id="attachment_id" name="attachment_ids[]" value="&lt;?php echo $attachment-&gt;ID ?&gt;" /&gt;&lt;/td&gt;
		&lt;td&gt;&lt;a href="&lt;?php get_the_attachment_link($attachment-&gt;ID); ?&gt;"&gt;&lt;?php echo apply_filters('the_title', $attachment-&gt;post_title); ?&gt;&lt;/a&gt;&lt;/td&gt;
		&lt;td&gt;&lt;?php the_author_meta( 'user_login', $attachment-&gt;post_author ); ?&gt;&lt;/td&gt;
		&lt;td&gt;&lt;?php the_author_meta( 'first_name', $attachment-&gt;post_author ); ?&gt; &lt;?php the_author_meta( 'last_name', $attachment-&gt;post_author ); ?&gt;&lt;/td&gt;
	&lt;/tr&gt;
&lt;?php
}
?&gt;

	&lt;tr&gt;
		&lt;td colspan="4"&gt;
		&lt;input type="submit" value="Delete" name="html-delete"&gt;
		&lt;/td&gt;
	&lt;/tr&gt;
&lt;/table&gt;</pre>
<p>Just like the previous template, this form calls itself whenever the client tries to delete a file. So I needed to add a test to see if the delete function was called with the attachment ID(s) to delete. The form is using an array, so the client can delete multiple files at once.</p>
<pre class="php">if ( isset( $_POST['html-delete'] ) ) {
	if ( isset( $_POST['attachment_ids'] ) ) {
		foreach ($_POST['attachment_ids'] as $id) {
			wp_delete_attachment($id, true);
		}
	}
}</pre>
<p>And that&#8217;s it&#8230; it is actually quite simple. Using the media_handle_upload() function reduces a lot of extra work. There is no sense in re-inventing the wheel and usually with WordPress you don&#8217;t have to.</p>
<p>I&#8217;ve stripped down this code a bit for this tutorial. You should be able to use it as a framework for creating your own pages. Obviously you should keep security in mind, making sure people have the right permissions to see these pages, etc.</p>
<p>Let me know if you have any questions, I&#8217;d love to hear your feedback!</p>
<p><a  href="http://nostretchmarksrequired.com/donate"><strong>If you found this post, useful, please consider donating 1$ to help fund my and my wife&#8217;s adoption&#8230; click here for details.</strong></a></p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/27/using-wordpress-built-in-media-upload/' addthis:title='Using WordPress&#8217; Built-in Media Upload ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/09/27/using-wordpress-built-in-media-upload/feed/</wfw:commentRss>
		<slash:comments>44</slash:comments>
		</item>
		<item>
		<title>Allowing Hyperlinks in Your WordPress Excerpts</title>
		<link>http://lewayotte.com/2010/09/22/allowing-hyperlinks-in-your-wordpress-excerpts/</link>
		<comments>http://lewayotte.com/2010/09/22/allowing-hyperlinks-in-your-wordpress-excerpts/#comments</comments>
		<pubDate>Wed, 22 Sep 2010 16:30:11 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[functions.php]]></category>
		<category><![CDATA[get_the_excerpt]]></category>
		<category><![CDATA[mu-plugins]]></category>
		<category><![CDATA[php]]></category>
		<category><![CDATA[preg_split]]></category>
		<category><![CDATA[strip_tags]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp_trim_excerpt]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1896</guid>
		<description><![CDATA[By default, WordPress strips out all the HTML tags from your post excerpts. I needed to allow hyperlinks, but there is a problem when WordPress tries to truncate the post&#8217;s content. The wp_trim_excerpt function is what WordPress uses to do all the trimming work, I simply copied the code, modified it, and stuck my new [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/22/allowing-hyperlinks-in-your-wordpress-excerpts/' addthis:title='Allowing Hyperlinks in Your WordPress Excerpts ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>By default, WordPress strips out all the HTML tags from your post excerpts. I needed to allow hyperlinks, but there is a problem when WordPress tries to truncate the post&#8217;s content. The wp_trim_excerpt function is what WordPress uses to do all the trimming work, I simply copied the code, modified it, and stuck my new version in the mu-plugins directory (or you could add it to your functions.php).</p>
<p>The first line I needed to change was the PHP function call <a  href="http://php.net/strip_tags">strip_tags()</a>. I need to set it to allow the &lt;a&gt; tag&#8230; very simple to do:</p>
<p>Original Line:</p>
<pre class="php" name='code'>$text = strip_tags($text);</pre>
<p>New Line:</p>
<pre class="php" name='code'>$text = strip_tags($text, '&lt;a&gt;');</pre>
<p>The second line I needed to change was where WordPress splits the excerpt up into separate words. This was a bit tricky because you run into an issue where you could be cutting of the &lt;/a&gt;, which could screw up your entire page. I decided the best thing to do would be to treat the entire hyperlink as a single word. So, <em><strong>&lt;a href=&#8221;http://lewayotte.com/&#8221;&gt;My Website&lt;/a&gt;</strong></em>, would count as a single word. By default, WordPress creates a 55 word excerpt. <a  href="http://codex.wordpress.org/Function_Reference/the_excerpt#Control_Excerpt_Length_using_Filters">That is pretty easy to change as well.</a></p>
<p>Original Line:</p>
<pre class="php" name='code'>$words = preg_split('/[\n\r\t ]', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY );</pre>
<p>New Line:</p>
<pre class="php" name='code'>$words = preg_split('/(&lt;a.*?a&gt;)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE );</pre>
<p>Next, you simple need to remove the current wp_trim_excerpt filter and add a new one that points to your new function. Here is what the entire block of code looks like for me:</p>
<pre class="php" name='code'>&lt;?php
function new_wp_trim_excerpt($text) {
	$raw_excerpt = $text;
	if ( '' == $text ) {
		$text = get_the_content('');

		$text = strip_shortcodes( $text );

		$text = apply_filters('the_content', $text);
		$text = str_replace(']]&gt;', ']]&gt;', $text);
		$text = strip_tags($text, '&lt;a&gt;');
		$excerpt_length = apply_filters('excerpt_length', 55);

		$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
		$words = preg_split('/(&lt;a.*?a&gt;)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE );
		if ( count($words) &gt; $excerpt_length ) {
			array_pop($words);
			$text = implode(' ', $words);
			$text = $text . $excerpt_more;
		} else {
			$text = implode(' ', $words);
		}
	}
	return apply_filters('new_wp_trim_excerpt', $text, $raw_excerpt);

}
remove_filter('get_the_excerpt', 'wp_trim_excerpt');
add_filter('get_the_excerpt', 'new_wp_trim_excerpt');</pre>
<p><strong>Regular Expression Explained</strong></p>
<p>I changed /[\n\r\t\s ]/ to /(&lt;a.*?a&gt;)|\n|\r|\t|\s/ because I needed to capture everything in the &lt;a&gt; HTML tags and count it as a single word. \n, \r, \t, \s are all pretty basic regex characters that <a  href="http://php.net/preg_split">preg_split()</a> is using to break up the content. (&lt;a.*?a&gt;) is what captures everything in the &lt;a&gt; tag. The .* means all &#8220;characters&#8221; adding the ? to .* makes it &#8220;non-greedy.&#8221; This for the case where there are multiple hyperlinks in the content. It prevents the regex from thinking <em><strong>&lt;a href=&#8221;link1&#8243;&gt;link 1&lt;/a&gt;, &lt;a href=&#8221;link2&#8243;&gt;link 2&lt;/a&gt;</strong></em> is a single word. The parenthesis simply group the &lt;a.*?a&gt; together, so it doesn&#8217;t try to split those items separately and then I needed to add PREG_SPLIT_DELIM_CAPTURE to preg_split, or preg_split would have just removed the link as garbage.</p>
<p>You should be able to use this as a pretty solid base for adding other HTML tags.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/22/allowing-hyperlinks-in-your-wordpress-excerpts/' addthis:title='Allowing Hyperlinks in Your WordPress Excerpts ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/09/22/allowing-hyperlinks-in-your-wordpress-excerpts/feed/</wfw:commentRss>
		<slash:comments>15</slash:comments>
		</item>
		<item>
		<title>Active Directory (LDAP) Authentication in WordPress Multi-Site</title>
		<link>http://lewayotte.com/2010/09/09/active-directory-ldap-authentication-in-wordpress-multi-site/</link>
		<comments>http://lewayotte.com/2010/09/09/active-directory-ldap-authentication-in-wordpress-multi-site/#comments</comments>
		<pubDate>Thu, 09 Sep 2010 16:30:00 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[active directory]]></category>
		<category><![CDATA[ldap]]></category>
		<category><![CDATA[mu-plugins]]></category>
		<category><![CDATA[open source]]></category>
		<category><![CDATA[plugins]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpms]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1881</guid>
		<description><![CDATA[As many of you know, I led the team that launched the College of Education at UGA&#8217;s new website (http://www.coe.uga.edu/) which is driven by WordPress Multi-Site. The first phase is complete, and the second phase has started up. Part of their second phase is to allow a custodian from each department to edit content on [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/09/active-directory-ldap-authentication-in-wordpress-multi-site/' addthis:title='Active Directory (LDAP) Authentication in WordPress Multi-Site ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>As many of you know, I led the team that launched the College of Education at UGA&#8217;s new website (http://www.coe.uga.edu/) which is driven by WordPress Multi-Site. The first phase is complete, and the second phase has started up. Part of their second phase is to allow a custodian from each department to edit content on their own departmental site. UGA uses Active Directory campus wide, so I thought it would be best to incorporate the WordPress authentication mechanism into UGA&#8217;s current AD implementation.</p>
<p>When I first researched this there weren&#8217;t many plugins for WordPress Multi-Site that handled AD/LDAP authentication. I was planning on writing one myself, but I found one yesterday by <a  href="http://clifgriffin.com/2009/05/13/simple-ldap-login-13-for-wordpress/">Clifton Griffin</a> called <a  href="http://wordpress.org/extend/plugins/simple-ldap-login/">Simple LDAP Login</a>. I installed in on a development website, put in the necessary information and BAM it worked&#8230; but it wasn&#8217;t really designed for WordPress Multi-Site. What I needed was every site to use the Active Directory authentication, without having to set each site up individually. So I paired down the code a bit (to just what I needed) and stuck the files in the mu-plugins dir.</p>
<p>Clifton used the opensource <a  href="http://adldap.sourceforge.net/">PHP LDAP Class</a> in his plugin, which works great. So, in my version, I stripped out everything I didn&#8217;t need/want like auto account creation, non-AD functionality, etc. Basically, I just needed to authenticate users via Active Directory.</p>
<p>So I stuck this code into a file in my mu-plugins folder. Now whenever anyone tries to authenticate it, uses Active Directory instead of WordPress&#8217; user table:</p>
<pre class="php">&lt;?php
require_once( WPMU_PLUGIN_DIR . '/simple-ldap-login/adLDAP.php' );

define( 'DOMAIN_CONTROLLERS', 	'active.directory.controller.domain' );
define( 'SECURITY_MODE', 		'high' );
define( 'ACCOUNT_SUFFIX', 		'@account.edu');
define( 'BASE_DN', 				'OU=OUOU,DC=DCDC,DC=EDU' );
define( 'USE_TLS',				false );
define( 'USE_SSL', 				true );

//Authenticate function
function sll_authenticate( $user, $username, $password ) {
	if ( is_a( $user, 'WP_User' ) ) { return $user; }

	//Failed, should we let it continue to lower priority authenticate methods?
	if( "high" === SECURITY_MODE ) {
		remove_filter('authenticate', 'wp_authenticate_username_password', 20, 3);
	}

	if ( empty( $username ) || empty( $password ) ) {
		$error = new WP_Error();

		if ( empty( $username ) )
			$error-&gt;add( 'empty_username', __( '<strong>ERROR</strong>: The username field is empty.' ) );

		if ( empty($password) )
			$error-&gt;add( 'empty_password', __( '<strong>ERROR</strong>: The password field is empty.' ) );

		return $error;
	}

	if( sll_can_authenticate( $username, $password ) ) {
			$user = get_userdatabylogin( $username );

			if ( !$user || ( strtolower( $user-&gt;user_login ) != strtolower( $username ) ) ) {
				do_action( 'wp_login_failed', $username );
				return new WP_Error( 'invalid_username', __( '<strong>Login Error</strong> An error occurred while attempting to log in. If this continues please contact coeweb@uga.edu for support.' ) );
			} else {
				//we're ready to return the user
				return new WP_User( $user-&gt;ID );
			}
	} else {
		return new WP_Error( 'invalid_username', __( '<strong>Login Error</strong> An error occurred while attempting to log in. If this continues please contact coeweb@uga.edu for support.' ) );
	}
}
add_filter( 'authenticate', 'sll_authenticate', 1, 3 );

function sll_can_authenticate( $username, $password ) {
	$sll_options = array(
		'account_suffix'		=&gt;	ACCOUNT_SUFFIX,
		'base_dn'				=&gt;	BASE_DN,
		'use_tls'				=&gt;	USE_TLS,
		'use_ssl'				=&gt;	USE_SSL,
		'domain_controllers'	=&gt;	explode( ';', DOMAIN_CONTROLLERS )
	);

	$adldap = new adLDAP( $sll_options );

	$result = false;
	$result = $adldap-&gt;authenticate( $username, $password );

	return $result;
}
</pre>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/09/09/active-directory-ldap-authentication-in-wordpress-multi-site/' addthis:title='Active Directory (LDAP) Authentication in WordPress Multi-Site ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/09/09/active-directory-ldap-authentication-in-wordpress-multi-site/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Certified as one of the Three Most Important People in WordPress</title>
		<link>http://lewayotte.com/2010/08/24/certified-as-one-of-the-three-most-important-people-in-wordpress/</link>
		<comments>http://lewayotte.com/2010/08/24/certified-as-one-of-the-three-most-important-people-in-wordpress/#comments</comments>
		<pubDate>Tue, 24 Aug 2010 21:30:01 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Life]]></category>
		<category><![CDATA[Mind]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1858</guid>
		<description><![CDATA[I have been certified as one of the three most important people in WordPress! From Matt Mullenweg&#8217;s hands, to your eyes; read&#8217;em and weep!<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/08/24/certified-as-one-of-the-three-most-important-people-in-wordpress/' addthis:title='Certified as one of the Three Most Important People in WordPress ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I have been certified as one of the three most important people in WordPress!</p>
<p>From <a  href="http://ma.tt/">Matt Mullenweg&#8217;s</a> hands, to your eyes; read&#8217;em and weep!</p>
<p><a  href="http://lewayotte.com/wp-content/uploads/2010/08/WPcertificate.png" class="thickbox no_icon" rel="gallery-1858" title="WPcertificate"><img class="aligncenter size-full wp-image-1859" title="WPcertificate" src="http://lewayotte.com/wp-content/uploads/2010/08/WPcertificate.png" alt="" width="600" height="776" /></a></p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/08/24/certified-as-one-of-the-three-most-important-people-in-wordpress/' addthis:title='Certified as one of the Three Most Important People in WordPress ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/08/24/certified-as-one-of-the-three-most-important-people-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How to fix WordPress MultiSite switch_to_blog() permalinks</title>
		<link>http://lewayotte.com/2010/08/11/how-to-fix-wordpress-multisite-switch_to_blog-permalinks/</link>
		<comments>http://lewayotte.com/2010/08/11/how-to-fix-wordpress-multisite-switch_to_blog-permalinks/#comments</comments>
		<pubDate>Wed, 11 Aug 2010 23:47:04 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[get_category_links]]></category>
		<category><![CDATA[permalinks]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[switch_to_blog]]></category>
		<category><![CDATA[twitter]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpms]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1836</guid>
		<description><![CDATA[If you are using switch_to_blog() in your WordPress MultiSite installation and notice that your permalinks contain &#8220;/blog/&#8221; in them (or some other oddity). The give John James Jacoby&#8217;s plugin Switch Site Rewrite a go. Today I ran into this problem with a WPMS site that I am developing. I needed to pull posts from the [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/08/11/how-to-fix-wordpress-multisite-switch_to_blog-permalinks/' addthis:title='How to fix WordPress MultiSite switch_to_blog() permalinks ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>If you are using switch_to_blog() in your WordPress MultiSite installation and notice that your permalinks contain &#8220;/blog/&#8221; in them (or some other oddity). The give <a  href="http://johnjamesjacoby.com/">John James Jacoby&#8217;s</a> plugin <a  href="http://wordpress.org/extend/plugins/switch-site-rewrite/">Switch Site Rewrite</a> a go.</p>
<p>Today I ran into this problem with a WPMS site that I am developing. I needed to pull posts from the &#8220;news&#8221; site onto the main site. I used switch_to_blog() to do this, but when I tried to get specific category permalinks with get_category_links() it would automatically include &#8220;/blog/&#8221; in the URL.</p>
<p>This is because of the way that the $wp_rewrite variable is initialized and an attempt to reduce overhead when using switch_to_blog(). So, John&#8217;s plugin does come with a risk of added overhead, but I&#8217;m currently dealing with a 30 site installation and don&#8217;t see much of  a cost. If you were really picky, you could modify his code a bit to only work in real specific situations.</p>
<p>If you get  a chance, jump on over to <a  href="http://twitter.com/JohnJamesJacoby">twitter</a> and thank him for this little plugin. It saved me a little more development work, although it also meant I wasted 2 hours tracking down the problem :).</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/08/11/how-to-fix-wordpress-multisite-switch_to_blog-permalinks/' addthis:title='How to fix WordPress MultiSite switch_to_blog() permalinks ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/08/11/how-to-fix-wordpress-multisite-switch_to_blog-permalinks/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Call Event Calendar 3 in WPMS from a different site ID</title>
		<link>http://lewayotte.com/2010/07/29/call-event-calendar-3-in-wpms-from-a-different-site-id/</link>
		<comments>http://lewayotte.com/2010/07/29/call-event-calendar-3-in-wpms-from-a-different-site-id/#comments</comments>
		<pubDate>Thu, 29 Jul 2010 19:00:45 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[switch_to_blog]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpms]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1818</guid>
		<description><![CDATA[I&#8217;ve been working on a pretty complicated WordPress Multi-Site project for the College of Education at UGA. One of their sites will be controlling the master calendar for the main website. We wanted to display the calendar from the sub-site. One the main site of the page (an possibly on other sub-sites). Generally speaking, in [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/29/call-event-calendar-3-in-wpms-from-a-different-site-id/' addthis:title='Call Event Calendar 3 in WPMS from a different site ID ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a pretty complicated WordPress Multi-Site project for the College of Education at UGA. One of their sites will be controlling the master calendar for the main website. We wanted to display the calendar from the sub-site. One the main site of the page (an possibly on other sub-sites).</p>
<p>Generally speaking, in WPMS / WPMU you can get the content of one site by switching to that site ID using the switch_to_blog($id) function. However, this does not work with Event Calendar 3, because of the way it builds it&#8217;s global $ec3 variable.</p>
<p>The problem is, when you are on site id 1, the $ec3 creates a variable that points to the schedule table for site id 1. Even if you run switch_to_blog(2), $ec3 still tries to get the schedule from site id 1. So it was returning an empty calendar. The easiest way to fix this (until EC3 updates their code) was to re-instantiate the global $ec3 variable. Basically this is what I did:</p>
<pre name="code" class="php">
switch_to_blog(10);
global $ec3;
$ec3 = new ec3_Options();
ec3_get_calendar();
restore_current_blog();
</pre>
<p>This re-instantiates the $ec3 variable for the schedule I needed to get from that specific site ID. It should be a fairly simple fix for EC3. Until then, this is the easiest fix if you need to do what I&#8217;m doing.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/29/call-event-calendar-3-in-wpms-from-a-different-site-id/' addthis:title='Call Event Calendar 3 in WPMS from a different site ID ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/07/29/call-event-calendar-3-in-wpms-from-a-different-site-id/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Update Arguments for the WordPress Built-in Tag Cloud Widget</title>
		<link>http://lewayotte.com/2010/07/11/update-arguments-for-the-wordpress-built-in-tag-cloud-widget/</link>
		<comments>http://lewayotte.com/2010/07/11/update-arguments-for-the-wordpress-built-in-tag-cloud-widget/#comments</comments>
		<pubDate>Sun, 11 Jul 2010 19:44:04 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[add_filter]]></category>
		<category><![CDATA[apply_filters]]></category>
		<category><![CDATA[tag cloud]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wp_tag_cloud]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1742</guid>
		<description><![CDATA[Usually I&#8217;d just call the wp_tag_cloud() function manually from a WordPress theme file, but I have a client who wants to use the Tag Cloud Widget on their site. The tag cloud widget has been in WordPress since WP 2.3. Unfortunately, it isn&#8217;t the easiest widget to use because you can&#8217;t customize it from the [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/11/update-arguments-for-the-wordpress-built-in-tag-cloud-widget/' addthis:title='Update Arguments for the WordPress Built-in Tag Cloud Widget ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>Usually I&#8217;d just call the wp_tag_cloud() function manually from a WordPress theme file, but I have a client who wants to use the Tag Cloud Widget on their site. The tag cloud widget has been in WordPress since WP 2.3. Unfortunately, it isn&#8217;t the easiest widget to use because you can&#8217;t customize it from the backend.</p>
<p>Luckily there are two filters that can be used to set the arguments your client needs and maintain the ability for them to modify the widget location from the WordPress backend.</p>
<ol>
<li>widget_tag_cloud_args &#8211; lets you set the wp_tag_cloud arguments</li>
<li>wp_tag_cloud &#8211; lets you edit the wp_tag_cloud output</li>
</ol>
<p>So, for my clients need&#8217;s, I just needed to set the small and large font size arguments and change the widget output a little to fit their sidebar properly. I added these lines to the theme&#8217;s function.php:</p>
<pre name="code" class="php">
function tag_cloud_args() {
	$args = array( 'smallest' =&gt; 8, 'largest' =&gt; 14 );
	return $args;
}
add_filter('widget_tag_cloud_args', 'tag_cloud_args');

function tag_cloud($return) {
	$return = "&lt;div class="box menu tags"&gt;" . $return . "&lt;/div&gt;";
	return $return;
}
add_filter('wp_tag_cloud', 'tag_cloud');
</pre>
<p>As with any function in WordPress, be sure to check out the codex for all the <a  href="http://codex.wordpress.org/Function_Reference/wp_tag_cloud">Tag Cloud Arguments</a> that you can use.</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/11/update-arguments-for-the-wordpress-built-in-tag-cloud-widget/' addthis:title='Update Arguments for the WordPress Built-in Tag Cloud Widget ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/07/11/update-arguments-for-the-wordpress-built-in-tag-cloud-widget/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Easily Add &#8220;Excerpt&#8221; Support for Pages in WordPress</title>
		<link>http://lewayotte.com/2010/07/01/easily-add-excerpt-support-for-pages-in-wordpress/</link>
		<comments>http://lewayotte.com/2010/07/01/easily-add-excerpt-support-for-pages-in-wordpress/#comments</comments>
		<pubDate>Thu, 01 Jul 2010 15:00:07 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[add_post_type_support]]></category>
		<category><![CDATA[excerpts]]></category>
		<category><![CDATA[wordpress]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1718</guid>
		<description><![CDATA[If you found this post, useful, please consider donating 1$ to help fund my and my wife&#8217;s adoption&#8230; click here for details. I&#8217;m working on a project, that requires people to add excerpt text in a page. By default excerpts are not enabled in WordPress for pages but there is a simple function you can [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/01/easily-add-excerpt-support-for-pages-in-wordpress/' addthis:title='Easily Add &#8220;Excerpt&#8221; Support for Pages in WordPress ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p><a  href="http://nostretchmarksrequired.com/donate"><strong>If you found this post, useful, please consider donating 1$ to help fund my and my wife&#8217;s adoption&#8230; click here for details.</strong></a></p>
<p>I&#8217;m working on a project, that requires people to add excerpt text in a page. By default excerpts are not enabled in WordPress for pages but there is a simple function you can add to your functions.php file to enable Page Excerpts.</p>
<p>Locate you functions.php file in your theme&#8217;s directory and add this line of code to it:</p>
<pre>add_post_type_support('page', 'excerpt');</pre>
<p>Now you will see the Excerpt box below the Content box on your pages. For more information about the add_post_type_support function, check out the <a  href="http://codex.wordpress.org/Function_Reference/add_post_type_support">WordPress Codex</a>. Have fun!</p>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/07/01/easily-add-excerpt-support-for-pages-in-wordpress/' addthis:title='Easily Add &#8220;Excerpt&#8221; Support for Pages in WordPress ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/07/01/easily-add-excerpt-support-for-pages-in-wordpress/feed/</wfw:commentRss>
		<slash:comments>11</slash:comments>
		</item>
		<item>
		<title>Remove Username Character Limit from WordPress Multi-Site / Multi-User</title>
		<link>http://lewayotte.com/2010/05/13/remove-username-character-limit-from-wordpress-multi-site-multi-user/</link>
		<comments>http://lewayotte.com/2010/05/13/remove-username-character-limit-from-wordpress-multi-site-multi-user/#comments</comments>
		<pubDate>Thu, 13 May 2010 16:30:37 +0000</pubDate>
		<dc:creator>Lew</dc:creator>
				<category><![CDATA[Mind]]></category>
		<category><![CDATA[development]]></category>
		<category><![CDATA[functions.php]]></category>
		<category><![CDATA[hacks]]></category>
		<category><![CDATA[mu-plugins]]></category>
		<category><![CDATA[wordpress]]></category>
		<category><![CDATA[wpms]]></category>
		<category><![CDATA[wpmu]]></category>

		<guid isPermaLink="false">http://lewayotte.com/?p=1672</guid>
		<description><![CDATA[I&#8217;ve been working on a pretty complex project with WordPress MultiUser (soon to be MultiSite). This client needs several sites with hundreds of users divided into each site. I will be integrating the backend authentication with LDAP and discovered that a small percentage of their users have usernames with fewer than four characters. WordPress MU [...]<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/05/13/remove-username-character-limit-from-wordpress-multi-site-multi-user/' addthis:title='Remove Username Character Limit from WordPress Multi-Site / Multi-User ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been working on a pretty complex project with WordPress MultiUser (soon to be MultiSite). This client needs several sites with hundreds of users divided into each site. I will be integrating the backend authentication with LDAP and discovered that a small percentage of their users have usernames with fewer than four characters.</p>
<p>WordPress MU currently has a minimum limit of four characters set in its core. Unfortunately, this limit is still imposed in WordPress MS 3.0. The limit is probably there because usernames were used for the domain too and WP-Devs didn&#8217;t want to conflict with country codes. But that is not an issue for my client, so I wanted to kill the limit (without touching core).</p>
<p>Basically, I wrote a quick mu-plugin that unset the error message when someone tries to add a user with fewer than four characters. Doing this removes any halts that would stop processing the new user. Here is my code:</p>
<pre name="code" class="php">function remove_username_char_limit($result) {
  if ( is_wp_error( $result[ 'errors' ] ) &#038;&#038; !empty( $result[ 'errors' ]->errors ) ) {

    // Get all the error messages from $result
    $messages = $result['errors']->get_error_messages();
    $i = 0;
    foreach ( $messages as $message ) {

      // Check if any message is the char limit message
      if ( 0 == strcasecmp("Username must be at least 4 characters", $message)) {
        // Unset whole 'user_name' error array if only 1 message exists
        // and that message is the char limit error
        if ( 1 == count($messages) ) {
          unset( $result['errors']->errors['user_name'] );
        } else {
          // Otherwise just unset the char limit message
          unset( $result['errors']->errors['user_name'][$i] );
        }
      }	

      $i++;
    }
  }

  return $result;
}
add_action('wpmu_validate_user_signup', 'remove_username_char_limit');</pre>
<div class="addthis_toolbox addthis_default_style addthis_" addthis:url='http://lewayotte.com/2010/05/13/remove-username-character-limit-from-wordpress-multi-site-multi-user/' addthis:title='Remove Username Character Limit from WordPress Multi-Site / Multi-User ' ><a class="addthis_button_preferred_1"></a><a class="addthis_button_preferred_2"></a><a class="addthis_button_preferred_3"></a><a class="addthis_button_preferred_4"></a><a class="addthis_button_compact"></a></div>]]></content:encoded>
			<wfw:commentRss>http://lewayotte.com/2010/05/13/remove-username-character-limit-from-wordpress-multi-site-multi-user/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

