WordPress

Posts filed under WordPress

Custom WordPress Gravatars – The Right Way

Filed in Web DevelopmentTags: Gravatars, Themes, tutorials, WordPress

I recently (h/t: Nacin) came across this tutorial by Nenuno Creative that recommends bypassing WordPress core implementation of Gravatars in order to output custom Gravatars. Below, I present a brief tutorial for a much better way to implement custom Gravatars in a way that doesn't require bypassing WordPress' core functionality.

The Nenuno Creative tutorial presents the following "customizations" of Gravatars:

  1. Comment Author email address
  2. Custom default Gravatar image
  3. Custom Gravatar image size

The problem with their tutorial is that, assuming your Theme is using wp_list_comments() to output the comments list (and your Theme is using wp_list_comments() to output the comments list, isn't it?), you have no easy way to control where and how your custom-built Gravatar is displayed (at least, not without quite a bit of additional custom code) - as evinced by the author's recommendation:

I would recommend using this in the “comments.php” page, somewhere around “< ? php wp_list_comments(); ? >” or whatever similar you may have in your theme!

Not a terribly helpful implementation suggestion, is it? (And in truth, since wp_list_comments() outputs a Gravatar by default, it's actually a rather incorrect recommendation.) Fortunately, all of the above can be implemented in a much, much easier way.

First, wp_list_comments() by default outputs a 32x32px Gravatar based on the Comment Author email address. So, all we need to deal with are custom Gravatar size, and custom default Gravatar image.

Custom Gravatar size is as simple as passing the avatar_size argument to wp_list_comments(). The arguments passed to wp_list_comments() are an array, so to output an 80x80px Gravatar, replace the default call:

wp_list_comments();

With this:

wp_list_comments( 'avatar_size=80' );

Simple, right?

That just leaves us with defining a custom default Gravatar image. Admittedly, this part is a bit trickier, but still not terribly complicated. We will be using the built-in user-configuration setting for default Gravatar image. By default, the option list includes "Mystery Man", "blank" (no image), the Gravatar logo, an Identicon, a Wavatar, and a Monster ID:

Default Avatars

The default list of images available for use as the default avatar in WordPress, including Mystery Man, blank (no image), the Gravatar logo, Identicon, Wavatar, and Monster ID

We will be hooking into this list, using the avatar_defaults filter, in order to add a custom image to this list (h/t: WPEngineer).

Simply add the following to your Theme's functions.php file:

function mytheme_addgravatar( $avatar_defaults ) {
  $myavatar = get_bloginfo('template_directory') . '/images/avatar.gif';
  $avatar_defaults[$myavatar] = 'My Theme Custom Gravatar';

  return $avatar_defaults;
}
add_filter( 'avatar_defaults', 'mytheme_addgravatar' );

You will need to replace /images/avatar.gif with an appropriate image file, that you have uploaded to your Theme directory.

That's it! Now, just go to Settings -> Discussion, and you will see your custom image listed in the options for Default Avatar:

Default Avatar Setting List With Custom Image

The default avatar setting list with a custom image "My Theme Custom Gravatar" added to the list

Simply select your custom image, and save settings.

Voila! We've just implemented everything from the Nenuno Creative tutorial, in a way that uses, rather than bypasses, core WordPress functionality.

Using Really Simple CAPTCHA Plugin for Comments

Filed in Web DevelopmentTags: CAPTCHA, Plugins, WordPress

I use the Contact Form 7 plugin for my site's contact form. The plugin's developer, Takayuki Miyoshi, created a complimentary plugin, Really Simple CAPTCHA, that incorporates with Contact Form 7 to provide a CAPTCHA for forms. In a nice example of forward thinking, Miyoshi created Really Simple CAPTCHA as a stand-alone plugin, complete with API, to facilitate other plugins' incorporation of CAPTCHA functionality. I had been using the excellent Math Comment Spam Protection plugin for my comments form.

However, continued development of the plugin has been dormant (the last update was almost three years ago), and the developer hasn't kept it updated with newer WordPress releases (I had to hack it to ensure compatibility with WordPress 3.0). Not wanting to take on maintaining a fork of Math Comment Spam Protection, realizing that I was actually using two different CAPTCHA solutions on my site, and wanting to take on the challenge of figuring out how to use Really Simple CAPTCHA's API, I decided to try to implement it for my comment form, directly into my Theme via functions.php.

As you can see: I managed to figure it out - through a combination of parsing the plugin files for Really Simple CAPTCHA, Contact Form 7, and Math Comment Spam Protection. Since I assume others might find this technique useful, I will try to explain the process. Integrating Really Simple CAPTCHA consists of two steps:

  1. Creating the CAPTCHA image, and adding associated fields to the comment form.
  2. Validating the CAPTCHA response when the comment form is submitted.

Creating the CAPTCHA image, and adding associated fields to the comment form

I will assume that the Theme uses a call to comment_form() rather than a hard-coded comment form, and thus cannot hard-code CAPTCHA fields into the comment form. Fortunately, WordPress has several built-in, comment form-related hooks. For our purposes, the comment_form_after_fields action hook works perfectly. This hook will allow us to add our form fields immediately after the Name/Email/URL fields, and before the comment text field. So, let's add the hook 1:

if ( ( ! $user_ID ) && ( class_exists('ReallySimpleCaptcha') ) ) {
	add_action( 'comment_form_after_fields' , 'mytheme_comment_captcha' );
}

Next, we need the function called by the hook:

function mytheme_comment_captcha() { 

}

Now to build the function. The first step is to instantiate the ReallySimpleCaptcha() class:

$comment_captcha = new ReallySimpleCaptcha();

The instantiated class uses several variables, the defaults for many of which can be modified if you choose to do so. Here are the defaults for several useful ones:

// Characters to use in CAPTCHA image.
$comment_captcha->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
// Number of characters in CAPTCHA image.
$comment_captcha->char_length = '4';
// Width/Height dimensions of CAPTCHA image.
$comment_captcha->img_size = array( '72', '24' );
// Font color of CAPTCHA characters, in RGB (0 - 255).
$comment_captcha->fg = array( '0', '0', '0' );
// Background color of CAPTCHA image, in RGB (0 - 255).
$comment_captcha->bg = array( '255', '255', '255' );
// Font Size of CAPTCHA characters.
$comment_captcha->font_size = '16';
// Width between CAPTCHA characters.
$comment_captcha->font_char_width = '15';
// CAPTCHA image type. Can be 'png', 'jpeg', or 'gif'
$comment_captcha->img_type = 'png';

Once you've (optionally) set variables, the next step is to generate a random prefix, which will be used to generate the CAPTCHA image:

// Generate random word and image prefix
$comment_captcha_word = $comment_captcha->generate_random_word();
$comment_captcha_prefix = mt_rand();
// Generate CAPTCHA image
$comment_captcha_image_name = $comment_captcha->generate_image($comment_captcha_prefix, $comment_captcha_word);

Next, define some variables for use in the comment form CAPTCHA fields:

$comment_captcha_image_url =  get_bloginfo('wpurl') . '/wp-content/plugins/really-simple-captcha/tmp/';
$comment_captcha_image_src = $comment_captcha_image_url . $comment_captcha_image_name;
$comment_captcha_image_width = $comment_captcha->img_size[0];
$comment_captcha_image_height = $comment_captcha->img_size[1];
$comment_captcha_field_size = $comment_captcha->char_length;
$comment_captcha_form_label = 'Anti-Spam:';

And finally, output the fields for the comment form:

?>
<p class="comment-form-captcha">
<img src="<?php echo $comment_captcha_image_src; ?>"
 alt="captcha"
 width="<?php echo $comment_captcha_image_width; ?>"
 height="<?php echo $comment_captcha_image_height; ?>" />
<label for="captcha_code"><?php echo $comment_captcha_form_label; ?></label>
<input id="comment_captcha_code" name="comment_captcha_code"
 size="<?php echo $comment_captcha_field_size; ?>" type="text" />
<input id="comment_captcha_prefix" name="comment_captcha_prefix" type="hidden"
 value="<?php echo $comment_captcha_prefix; ?>" />
</p>
<?php

Here it is, all put together:

// Instantiate the ReallySimpleCaptcha class, which will handle all of the heavy lifting
$comment_captcha = new ReallySimpleCaptcha();

// ReallySimpleCaptcha class option defaults.
// Changing these values will hav no impact. For now, these are here merely for reference.
// If you want to configure these options, see "Set Really Simple CAPTCHA Options", below
// TODO: Add admin page to allow configuration of options.
$comment_captcha_defaults = array(
'chars' => 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789',
'char_length' => '4',
'img_size' => array( '72', '24' ),
'fg' => array( '0', '0', '0' ),
'bg' => array( '255', '255', '255' ),
'font_size' => '16',
'font_char_width' => '15',
'img_type' => 'png',
'base' => array( '6', '18'),
);

/**************************************
* All configurable options are below  *
***************************************/

// Set Really Simple CAPTCHA Options
$comment_captcha->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
$comment_captcha->char_length = '4';
$comment_captcha->img_size = array( '72', '24' );
$comment_captcha->fg = array( '0', '0', '0' );
$comment_captcha->bg = array( '255', '255', '255' );
$comment_captcha->font_size = '16';
$comment_captcha->font_char_width = '15';
$comment_captcha->img_type = 'png';
$comment_captcha->base = array( '6', '18' );

// Set Comment Form Options
$comment_captcha_form_label = 'Anti-Spam:';

/********************************************************************
* Nothing else to edit.  No configurable options below this point.  *
*********************************************************************/

// Generate random word and image prefix
$comment_captcha_word = $comment_captcha->generate_random_word();
$comment_captcha_prefix = mt_rand();
// Generate CAPTCHA image
$comment_captcha_image_name = $comment_captcha->generate_image($comment_captcha_prefix, $comment_captcha_word);
// Define values for comment form CAPTCHA fields
$comment_captcha_image_url =  get_bloginfo('wpurl') . '/wp-content/plugins/really-simple-captcha/tmp/';
$comment_captcha_image_src = $comment_captcha_image_url . $comment_captcha_image_name;
$comment_captcha_image_width = $comment_captcha->img_size[0];
$comment_captcha_image_height = $comment_captcha->img_size[1];
$comment_captcha_field_size = $comment_captcha->char_length;
// Output the comment form CAPTCHA fields
?>
<p class="comment-form-captcha">
<img src="<?php echo $comment_captcha_image_src; ?>"
 alt="captcha"
 width="<?php echo $comment_captcha_image_width; ?>"
 height="<?php echo $comment_captcha_image_height; ?>" />
<label for="captcha_code"><?php echo $comment_captcha_form_label; ?></label>
<input id="comment_captcha_code" name="comment_captcha_code"
 size="<?php echo $comment_captcha_field_size; ?>" type="text" />
<input id="comment_captcha_prefix" name="comment_captcha_prefix" type="hidden"
 value="<?php echo $comment_captcha_prefix; ?>" />
</p>
<?php
}
if ( ( ! $user_ID ) && ( class_exists('ReallySimpleCaptcha') ) ) {
	add_action( 'comment_form_after_fields' , 'mytheme_comment_captcha' );
}

At this point, your comment form should have a (non-functional) CAPTCHA field and image. Now we need to validate the CAPTCHA when the form is submitted.

Validating the CAPTCHA response when the comment form is submitted

For this part, we will use the preprocess_comment filter hook 2:

if ( ( ! $user_ID ) && ( $comment_data['comment_type'] == '' ) && ( class_exists('ReallySimpleCaptcha') ) ) {
	add_filter('preprocess_comment', 'mytheme_check_comment_captcha', 0);
}

And as before, we define the function added by the filter:

function mytheme_check_comment_captcha( $comment_data  ) {

}

Once again, our first step is to instantiate the ReallySimpleCaptcha() class.

$comment_captcha = new ReallySimpleCaptcha();

Then, declare a variable to hold the validation result, which we will default to false:

$comment_captcha_correct = false;

Next, we will use the "check" function built into the ReallySimpleCaptcha class to validate the CAPTCHA response from the comment form:

$comment_captcha_prefix = $_POST['comment_captcha_prefix'];
$comment_captcha_code = $_POST['comment_captcha_code'];
$comment_captcha_check = $comment_captcha->check( $comment_captcha_prefix, $comment_captcha_code );
$comment_captcha_correct = $comment_captcha_check;

Now that CAPTCHA validation is complete, we don't need the files hanging around the temp directory. So, we'll clean them up. The first function removes the files we just used. The second will remove any files older than 60 minutes (in case any are hanging around for some reason):

$comment_captcha->remove($_POST['comment_captcha_prefix']);
$comment_captcha->cleanup();

And finally, if the CAPTCHA response is incorrect, return an error; otherwise, process the comment as per normal:

if ( ! $comment_captcha_correct ) {
	wp_die('You have entered an incorrect CAPTCHA value. Click the BACK button on your browser, and try again.');
	break;
}
return $comment_data;

Here's the comment-processing function, all put together:

function mytheme_check_comment_captcha( $comment_data  ) {
$comment_captcha = new ReallySimpleCaptcha();
// This variable holds the CAPTCHA image prefix, which corresponds to the correct answer
$comment_captcha_prefix = $_POST['comment_captcha_prefix'];
// This variable holds the CAPTCHA response, entered by the user
$comment_captcha_code = $_POST['comment_captcha_code'];
// This variable will hold the result of the CAPTCHA validation. Set to 'false' until CAPTCHA validation passes
$comment_captcha_correct = false;
// Validate the CAPTCHA response
$comment_captcha_check = $comment_captcha->check( $comment_captcha_prefix, $comment_captcha_code );
// Set to 'true' if validation passes, and 'false' if validation fails
$comment_captcha_correct = $comment_captcha_check;
// clean up the tmp directory
$comment_captcha->remove($comment_captcha_prefix);
$comment_captcha->cleanup();
// If CAPTCHA validation fails (incorrect value entered in CAPTCHA field) don't process the comment.
if ( ! $comment_captcha_correct ) {
	wp_die('You have entered an incorrect CAPTCHA value. Click the BACK button on your browser, and try again.');
	break;
}
// if CAPTCHA validation passes (correct value entered in CAPTCHA field), process the comment as per normal
return $comment_data;
}
if ( ( ! $user_ID ) && ( $comment_data['comment_type'] == '' ) && ( class_exists('ReallySimpleCaptcha') ) ) {
	add_filter('preprocess_comment', 'mytheme_check_comment_captcha', 0);
}

That's it! Now you should have a fully functional CAPTCHA for your comment form. To use the same technique, just drop the above two functions and corresponding hooks into your Theme's functions.php file, then install and activate the Really Simple CAPTCHA plugin.

In case you would rather not mess with your Theme's functions.php file, I have also created a plugin to accomplish the same thing: cbnet Really Simple CAPTCHA Comments. I've added inline documentation, and cleaned up the code a bit. In a subsequent version, I will include an admin options page for setting the configurable options. For now, options can be set in the PHP file.

Notes:

  1. I've wrapped the hook in two conditionals:

    1. ( ! $user_ID ) - if $user_ID is set, then the user is logged in, so we don't need to add a CAPTCHA.
    2. ( class_exists('ReallySimpleCaptcha') )- the ReallySimpleCaptcha() class corresponds to the Really Simple CAPTCHA plugin, upon which our code depends. If it's not installed/activated, we don't want to try to use it.

  2. For this hook, in addition to the same two conditionals, we add a third:

    • ( $comment_data['comment_type'] == '' ) - only validate the CAPTCHA for comments, and not for Trackbacks or Pingbacks

WordPress Themes, GPL, and Copyright Case Law

Filed in Web DevelopmentTags: Copyright, GPL, Judiciary, Plugins, Themes, WordPress

Within the WordPress community, the question of GPL inheritance of WordPress themes erupts into contentious debate with the reliability - if not the frequency - of Old Faithful. While I understand that, according to the GPL interpretation of Matt Mullenweg, the Free Software Foundation (FSF), and the Software Freedom Law Center (SFLC), WordPress themes are derivative of WordPress and therefore must necessarily inherit WordPress' GPL, I would like to investigate the issue not in light of their interpretation but rather in light of copyright law and precedent case law.

Before I begin, let me add an important caveat: I have no qualms with the GPL. I have always released - and will continue to release - under GPL anything I develop related to WordPress. I do so because I choose to do so, as a means of making even a minor contribution to a project from which I believe I have personally benefited. I do have issues with how the GPL-inheritance question has been handled - but those issues are out-of-scope for this post.

Having (hopefully) made that point clear, let's begin!

What US Copyright Law Says

US Copyright law defines a "derivative work" as such:

A “derivative work” is a work based upon one or more preexisting works, such as a translation, musical arrangement, dramatization, fictionalization, motion picture version, sound recording, art reproduction, abridgment, condensation, or any other form in which a work may be recast, transformed, or adapted. A work consisting of editorial revisions, annotations, elaborations, or other modifications, which, as a whole, represent an original work of authorship, is a “derivative work”.

Note the key adjectives: recast, transformed, and adapted.

Consider also Section 102(b), which states:

In no case does copyright protection for an original work of authorship extend to any idea, procedure, process, system, method of operation, concept, principle, or discovery, regardless of the form in which it is described, explained, illustrated, or embodied in such work.

This clause establishes the boundary around copyright between copyrightable expression, and non-copyrightable ideas.

Summarizing GPL Inheritance Requirements

To summarize GPL requirements regarding license inheritance for derivative works 1:

  1. The GPL only applies to distribution of a (modified or unmodified) GPL-licensed work, or a derivative work. Any activity involving use, modification, or creation of derivative works that does not involve distribution is outside of the scope of the GPL.
  2. Distribution of a (modified or unmodified) GPL-licensed work, or a derivative work, requires that such distribution be licensed under GPL.

The GPL is what is now referred to as a "copyleft" license: a modified public-domain license that takes advantage of the exclusive rights granted by copyright law to prevent derivative works from being restrictively licensed. Since the copyright owner has exclusive right to produce and to distribute derivative works based on the copyrighted work, the GPL intends to grant unlimited usage rights (to use, study, modify, etc.) to the end-user, while forcing follow-on developers of derivative works to release those works under the same license.

It is important to understand that, because the GPL explicitly defines any activity not involving distribution to be out of the scope of the license, and since right of distribution is solely derived from copyright law, that GPL derives its legal basis from copyright law alone. This distinction separates the GPL from most other traditional software licenses, which derive their basis for usage and modification restrictions not from copyright law, but from contract law.

Notes:

  1. WordPress is released under GPL version 2.0. I'll try to summarize below the parts of the license germane to derivative works.

    First, from the Preamble:

    The reason we have a separate public license for some libraries is that they blur the distinction we usually make between modifying or adding to a program and simply using it. Linking a program with a library, without changing the library, is in some sense simply using the library, and is analogous to running a utility program or application program. However, in a textual and legal sense, the linked executable is a combined work, a derivative of the original library, and the ordinary General Public License treats it as such.

    ...

    The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, while the latter only works together with the library.

    Terms and Conditions, Clause 0:

    The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".)

    Terms and Conditions, Clause 2:

    These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

    Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library.

    Terms and Conditions, Clause 5:

    A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License.

    However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables.

JR Protection: Anatomy of a Spammy/SEO Plugin

Filed in Web DevelopmentTags: Plugins, Spam, WordPress

The JR Protection plugin (h/t: WP Jedi) purports to add content-scraping protection to one's blog posts - namely, by using javascript to block right-click and highlight functionality, and by disabling the RSS feed.

Personally, I think the plugin's functionality is ineffective toward its purported objective; but that's not the biggest complaint I have with this plugin. Despite being ineffective, the plugin is an SEO/spam Trojan horse.

Plugin Options Admin Page Spam

First up: spam injected in the plugin's options admin page.

Take a look at Line 280 of the plugin file:

<iframe src="http://www.jakeruston.co.uk/plugins/index.php" width="100%" height="20%">iframe support is required to see this.</iframe>

The contents of the linked page currently displays the following in the plugin's options admin page:

Spammy advertising injected into the JR Protection plugin's options admin page via iframe

And it's a huge banner, too: it takes up 100% of screen width, and 20% of screen height. In other words, on my screen, it takes up about three times the space taken up by the actual options presented on the page.

And that this advertising spam is injected using an iframe, rather than an image bundled with the plugin, presents a huge, potential vector for security threats. For one, the plugin author has complete control over the contents of the URL linked by the iframe. I subscribe to the TNO - Trust No One - security model. Besides, even if the plugin developer has only benevolent intent with this iframe, his site could get hacked, giving the hacker potential access to every site on which the plugin is installed.

wp_footer SEO/Spam Link Injection

Moving on to the even-more-spammy links injected into wp_footer.

The guidelines for hosting a plugin in the wordpress.org plugin repository are quite clear. Here is Restriction #4:

The plugin must not embed external links on the public site (like a "powered by" link) without explicitly asking the user's permission.

In the not-too-distant past, much discussion and argument have taken place around these restrictions, which led Mark Jaquith to clarify and expound upon them. Although his post was written in a somewhat tongue-in-cheek manner, everything he lists will, in fact, result in getting your plugin removed from the wordpress.org plugin repository. Here are two such offenses (#4-6):

  • #4. Insert SEO spam links into people’s blogs (like <a href=”http://example.com/”>video poker</a>).
  • #5. Insert external links (like a credit link, <a href=”http://example.com/”>My Awesome Plugin by Awesome Sauce</a>) into their blog without explicitly asking their permission, or make the default option be to insert the link.
  • #6. Load portions of the code from an external site for no valid reason, or use any other trick to work around #3, #4 and #5.

Loading portions of code from an external site for no valid reason, Inserting SEO spam links

Taking a look at the JR Protection plugin, Line 449:

add_action('wp_footer', 'protection_footer_plugin_support');

So let's take a look at the protection_footer_plugin_support function, on Line 453:

function protection_footer_plugin_support() {
$linkper=utf8_decode(get_option('jr_protection_link_personal'));
...

The plugin goes through a lot of motions to populate jr_protection_link_personal, including pulling a link from the developers website every so often, based on a defined refresh rate. Here's the link, from Line 468:

$content = curl_get_contents("http://www.jakeruston.co.uk/plugins/links.php?url=".$url."&pname=".$pname);

Currently, that URL pulls the following content:

SEO Spam links injected into wp_footer by JR Protection plugin

SEO Spam links injected into wp_footer by JR Protection plugin

But in case the plugin is unable to pull from the above-specified URL, it conveniently hard-codes some similar, fall-back spam links. See Line 109:

$content = "Powered by <a href='http://arcade.xeromi.com'>Free Online Games</a> and <a href='http://directory.xeromi.com'>General Web Directory</a>.";

And here's some more (including the only legitimate credit link the plugin provides), from Lines 118-130:

if (get_option("jr_protection_link_personal")=="") {
$rand=rand(2,2);

switch ($rand) {
case 1:
$anch="Jake Ruston's <a href="http://www.jakeruston.co.uk">Wordpress Plugins</a>";
break;
case 2:
$anch="<a href="http://www.xeromi.net">Cheap Web Hosting</a>";
break;
}

update_option("jr_protection_link_personal", $anch);

Inserting external links without explicitly asking permission, or setting option to display links to default to enabled

And going even further, these wp_footer links are injected by default. Here are the default settings. The key option is "Show Plugin Support?":

wp_footer spam link injection enabled by default in JR Protection plugin

wp_footer spam link injection enabled by default in JR Protection plugin

And especially annoying, when the user clicks the "No" option for "Show Plugin Support?", the plugin displays a nag dialogue:

nag dialogue displayed when user attempts to disable wp_footer links in JR Protection plugin

nag dialogue displayed when user attempts to disable wp_footer links in JR Protection plugin

Now that's just tacky.

An Ineffective Plugin

And here's the kicker: after putting up with all of that, what do you get? A totally ineffective plugin!

Broken Functionality

First, when testing out the plugin, I noted that, while the right-click disable appeared to be working, the text-highlight disable wasn't. I was able to select text both using the mouse to select specific text, and using CTRL-A to select all text.

Faulty Assumptions

But even more problematic are the plugin's faulty assumptions. The plugin assumes that anyone right-clicking or highlighting text on your site is attempting to steal your content, and that anyone using your RSS feed is attempting to scrape your content. In fact, the majority of people right-clicking and highlighting text on your site are doing so in order to link to/comment on your content, and the majority of users of your RSS are doing so for its intended purpose (to read your content).

Use of this plugin will result in the loss of all of your RSS subscribers, and a sharp reduction in people extending the conversation by writing about/commenting on your blog posts.

Gaping Holes

And it still won't do a think to prevent content theft! Due to two especially glaring holes, anyone intent on stealing your content will still be able to do so, despite use of this plugin:

Reliance on Javascript

The plugin relies on javascript to disable right-clicks and text-highlighting. Any user who browses your site with javascript disabled will be completely unaffected by this plugin, with respect to right-clicking and text-highlighting.

Browser Source

The plugin has absolutely no way to disable website visitors from using the view-source functionality built into every web browser. Even with the plugin enabled, one needs merely to invoke the browser's view-source functionality (in Firefox or Chrome, type "CTRL-U"; in Internet Explorer, select "View" from the menu, then "View Source"), which presents the entire contents in text format.

Conclusion

For all the reasons above, I would recommend against using the JR Protection plugin. Further, unless the plugin is modified to address the plugin repository restriction violations listed above, the plugin should be removed from the wordpress.org plugin repository.

Fixing Math Comment Spam Protection Plugin in WordPress 3.0

Filed in Web DevelopmentTags: Math Comment Spam Protection, Plugins, WordPress

Otto has an even better suggestion: use is_user_logged_in(). I have updated the recommended fix accordingly. Thanks, Otto!

As many people have noticed, the Math Comment Spam Protection plugin no longer works in WordPress 3.0. Unfortunately, the plugin appears to be no longer supported by its author, so some people are searching for an alternative plugin.

However, I have some good news: after a bit of trial-and-error, I found the problem with Math Comment Spam Protection. Even better news: the fix is incredibly simple.

Find Line 211 of math-comment-spam-protection.php:

if (  ( !isset($user_ID) ) && ( $comment_data['comment_type'] == '' ) ) { // Do not check if the user is registered & do not check trackbacks/pingbacks

The offending code is this:

( !isset($user_ID ))

Simply change the above to this (note: see update, above):

( ! $user_ID )

( ! is_user_logged_in() )

So that Line 211 looks like the following:

if (  ( ! $user_ID ) && ( $comment_data['comment_type'] == '' ) ) { // Do not check if the user is registered & do not check trackbacks/pingbacks

Voila! The Math Comment Spam Protection plugin will now work again!

This fix is so simple, I don't see any need to fork the code. I'll try to contact the developer, and see if he will patch the original.

New Plugin: cbnet Manage Plugins Donate Link

Filed in Web DevelopmentTags: Geekery, Plugins, WordPress

Do you use WordPress? Do you use several plugins? Have you ever considered donating to the authors of the plugins you use, but find it rather inconvenient to find each plugin's listing at WordPress.org Extend, just to find the author's Donate link?

If so, then you will find the cbnet Manage Plugins Donate Link plugin to be incredibly useful.

Donate Link

Donate link displayed in list of links beneath the plugin description

Plugin authors define their Donate link in the plugin's readme.txt file. This plugin reads each plugin's readme.txt to find the Donate link, and then, if it finds one, adds that link to the list of links in plugin_row_meta beneath the plugin description on the Manage Plugins page.

With this plugin enabled, you will have quick, convenient, one-stop access to the Donate links for the authors of all your installed plugins.

My hope is that this plugin will encourage more voluntary donations to plugin authors, most of whom put in countless hours of unpaid code contribution to the WordPress community. More and more plugin authors, out of economic necessity, are moving to "freemium", subscription, or other paid models, because they simply do not receive donations from those who use their plugins.

This plugin is but a humble attempt to encourage more users to donate to plugin authors.

Links

Support

Please do not post support questions here. Please post all support questions in the plugin support forum.

Displaying Custom WordPress Category/Tag Lists

Filed in Web DevelopmentTags: Geekery, Web Site, WordPress
Custom Category/Tag List Screenshot

Custom category list with RSS feed links and post counts

In my sidebar, I have displayed lists of categories and tags, but wanted to have greater control over these lists than what is offered by the currently available template tags. Namely, I wanted to be able to display each category/tag with a link to the RSS feed on the left, and a post count on the right. So, based on a helpful blog post, my own meanderings in this WPTavern forum thread, and help from DD32 and mfields in this WPTavern forum thread, I have custom category and tag lists, complete with links to the RSS feeds and total post counts for each category and tag.

Here's how:

Custom Category List

Add the following code to your sidebar, or into a widget:

<ul class="leftcolcatlist">
<?php
$catrssimg = "/images/rss.png";
$catrssurl = get_bloginfo('template_directory') . $catrssimg;
$customcatlist ='';
$customcats=  get_categories();
foreach($customcats as $customcat) {
$customcatlist = '<li><a title="Subscribe to the '.$customcat->name.' news feed" href="'.get_bloginfo('url').'/category/'.$customcat->category_nicename.'/feed/"><img src="'.$catrssurl.'" alt="feed" /></a><a href="'.get_bloginfo('url').'/category/'.$customcat->category_nicename.'/">'.$customcat->name.'</a> ('.$customcat->count.')</li>';
echo $customcatlist;
}
?>
</ul>

Custom Tag List

Add the following code to your sidebar, or into a widget:

<ul class="leftcolcatlist">
<?php
$tagrssimg = "/images/rss.png";
$tagrssurl = get_bloginfo('template_directory') . $tagrssimg;
$customtaglist =''; $customtags =  get_tags();
foreach($customtags as $customtag) {
$customtaglist = '<li><a title="Subscribe to the '.$customtag->name.' feed" href="'.get_bloginfo('url').'/tag/'.$customtag->slug.'/feed/"><img src="'.$tagrssurl.'" alt="feed" /></a><a href="'.get_bloginfo('url').'/tag/'.$customtag->slug.'/">'.$customtag->name.'</a> ('.$customtag->count.')</li>';
echo $customtaglist;
}
?>
</ul>

Modifications

You will need to modify $tagrssimg and $catrssimg depending on which RSS image you choose to use, and where you upload that image. If you use an image outside of your theme directory, you will also need to modify $tagrssurl and $catrssurl accordingly.

Yet To Come

Eventually, I will release a series (and/or collection) of widgets, including the above two custom lists.

Free Your Mind, Not Just Your Software

Filed in Web DevelopmentTags: Free Software Movement, GPL, WordPress

The Free Software Philosophy

The philosophy behind the free software movement is noble and well-intentioned. Projects that have chosen to operate under this philosophy have been wildly successful and have produced outstanding products. In many ways, I enjoy the fruits of free-software projects. My laptop runs Kubuntu Linux. OpenOffice.org is my office suite of choice. Firefox is my default browser. WordPress is my blogging platform of choice. Rockbox is my MP3 player firmware.

Having benefitted so greatly from using free software products, I have even done what I am able to contribute to free software projects, from introducing others to the software, to writing tutorials, to attempting to help other users in support forums, and even trying my hand at contributing code in the form of plugins and themes.

One of the fundamental principles of free software philosophy is the right of users to form a community, to use, share, change, improve, and help others to use software. This philosophy states that users should be free to use, to study, to modify, and to redistribute both the original and modified copies of software.

Thus, the free software philosophy inherently encourages those who might not otherwise choose to do so, to get involved with the project. This involvement  from the users' sense of altruism (for the good of others/the project), sense of belonging (to be part of the group/project), or sense gratitude (to give back to a project from which one has benefitted).

Unfortunately, I have seen those who espouse this free-software philosophy also exemplify stifling closed-mindedness and attitudes that actively drive would-be contributors away from, rather than bring them into, the project community. A few recent cases in the WordPress community belie close-mindedness, arrogance, condescension, and nepotistic hypocrisy - attitudes that are counter-productive to building free-software communities.

The Unforgivable Prodigal Son

In the first case, a WordPress plugin author was using some practices that are clearly unacceptable within the WordPress community. This plugin author was allowing users to download and install his plugins, but upon attempting to use the installed plugin, the plugin forced the user to register his email address with the plugin author, and was also forced to double-opt-in subscribe to the plugin author's internet-marketing-focused email list - an email list that many users complained of being "spam"-like, due to its frequency and lack of focus on the users' installed plugins from the author.

Clearly, these practices are outside the acceptable bounds for the WordPress community - and, especially, the wordpress.org plugin repository. Thus, the author's plugins were removed from the repository.

However, after weeks of back-and-forth discussion with this plugin author, he decided that being a part of the WordPress community and having his plugins listed in the wordpress.org plugin repository was more important than forcing users to subscribe to his email list. He decided to modify his plugins to make the email-list subscription optional.

What was the response of the wordpress.org repository? Rather than welcome him with open arms, and celebrate that a "prodigal son" would embrace even a bit of the free-software philosophy, the response was instead, "Thanks, but no thanks." This plugin author was told that, no matter what changes he made, his plugins would never again be accepted into the repository.

As one might expect, this response discouraged the plugin author to the point that he decided that pursuing making his plugins repository-acceptable not worth his time and effort. Further, he decided that he would no longer continue to develop free-cost plugins.

While I question the widespread usefulness of most of this author's plugins, he did develop several very useful plugins. So, not only did the response from the WordPress project actively push a developer away from the WordPress community and away from free-software philosophy, but it also reduced the availability of plugins to end users of WordPress.

And what was the reaction of many in the WordPress community? In essence: good riddance; once a spammer, always a spammer.

This response assumes that the plugin author's only intent was to be a "spammer" - that he was up to no good whatsoever. In reality, the plugin author's intent - misguided and completely unacceptable as it was - was to support his free plugin development and free plugin support by driving traffic to his profitable email list.

Such a response is both unacceptable and unwarranted.

First, the author's plugins were not "spammy" or otherwise harmful. They provided value and usefulness to those who use them. While the author's tactics for forcing subscription to his email list were wrong, the author fully and appropriately complied with un-subscribe requests. While the email newsletter is not useful to many users, it does not meet any of the accepted definitions of "spam".

Second, it is important to understand that, prior to his plugins being removed from the repository, the plugin author was given no official warning whatsoever that his plugins violated the repository guidelines. Several users complained about the plugins in the wordpress.org support forums (to which the plugin author responded), but he was never formally notified that he would need to modify his plugins or face their removal from the repository.

Third, regardless of his reasoning, the plugin author relented, and decided to accept the terms specified in the repository guidelines. Whether or not he agreed with them, he willingly chose to modify his plugins so that they would conform.

So, this plugin author was given no warning in the first place, and then was given no opportunity to resolve the problems with his plugins: no warning, no forgiveness, and no attempt to bring this plugin author into the WordPress community or the free-software philosophy.

As a result, a potential community member was actively driven away from the community, and the community has less code contributions to show for it.

No Learning Curve Allowed

In the second case, a new developer decided to develop and release a WordPress plugin. This developer, being new to the GPL and to developing for WordPress - and thus mostly ignorant of GPL requirements and the free-software philosophy of WordPress - made a mistake.

This plugin author noticed that users were removing or replacing a public-facing attribution link he had put into his plugin. So, in response, he base64-encoded this attribution link - not realizing that he was, in effect, thwarting the user's intent in using his plugin. This author also had not explicitly declared in his plugin that it was released under the GPL.

This plugin author - also without warning or notice - found that his plugin had been removed/disabled from the repository. He inquired at the WPTavern Forum, and was told that the reasons for his plugin being removed were primarily the base64-encoding of the attribution link, and secondarily the lack of license disclosure.

The plugin author confirmed this information with the wordpress.org plugin repository moderator, and based on this information, demonstrated his understanding for why the encoding was unacceptable and immediately made the necessary changes to his plugin.

(Side note: kudos to the repository moderator, for working with this plugin author and for restoring the plugin once the changes were made.)

Again, it is important to understand the context. This plugin author did nothing that explicitly (or implicitly) violated the stated repository guidelines. His plugin was removed, he inquired as to why, received - and accepted - an explanation, and immediately made the necessary changes.

This situation - primarily the assertion that not disclosing license information in the plugin would result in the plugin being removed from the repository - caused me to take a look at how well the plugins from some of the more high-profile plugin authors conformed to that (unpublished) requirement.

What I found astounded me. Only 26% of the repository-hosted plugins written by Matt Mullenweg, Mark Jaquith, Peter Westwood, Ozh, and Viper007Bond explicitly disclosed license information - yet none of these plugin authors was under threat of having his plugins removed from the repository.

I published my results (in a blog post that was generally well-received by the authors whose plugins I audited), which led to Peter Westwood (Westi) adding to the upcoming dev chat a discussion point regarding proper means of license disclosure for plugins.

What I soon discovered was that some of the core developers - including Matt Mullenweg and Viper007Bond - dismissed the concerns out of hand, claiming that the plugin author in question clearly must be a "dirty" (or "lame") "spammer", and thus up to no good, due to his use of base64 encoding.

Once again, apparently the WordPress project would rather actively drive away a potential community member, rather than accept that he made an honest mistake and that he resolved the problem once he understood it. Likewise apparently, the project would prefer arrogantly and condescendingly to declare that, "with regard to the GPL and WordPress, ignorance isn't an excuse," and that "no good intention could ever come from code obfuscation," rather than show any patience with a developer new to the GPL and free software or to offer any forgiveness for mistakes that he made.

Membership Has Its Privileges

In the third case, a plugin author decided to fork an existing, very popular plugin. The plugin author intended to write a case study on "creating a clean plugin, with emphasis in source code’s good practices." This author also discovered that his plugin had been removed from the repository without warning.

Upon inquiring, this author learned that his plugin had been removed because an unnamed source alleged that his plugin contained certain security vulnerabilities. (Note: I discuss the handling of this issue elsewhere.)

As it turns out, the alleged security vulnerabilities in question originated not with this author's plugin, but rather with the original plugin he forked. Not only that, but the same alleged security vulnerabilities were propogated into other forks of the same original plugin.

On the positive side, the author was able to fix the alleged security vulnerabilities in his own plugin as well as alert the authors of both the original and the other forks regarding those vulnerabilities. Further, in the end, the author's plugin was restored to the repository.

However, the case demonstrates a double standard applied to this plugin author. His plugin was removed merely on the word of an unnamed informant. As far as I could tell, neither the other forks nor - more importantly - the original plugin were ever treated similarly by being removed from the repository until the same vulnerabilities were fixed.

In fact, to date, the original plugin is still available in the repository, without the now-known security vulnerabilities still not fixed. What is the difference? Usage and Popularity.

The author in question had only several hundred downloads of his plugin. The original plugin is currently the #2 Most Popular plugin in the repository, with over four million downloads. The author in question was relatively unknown, while the author of the original plugin is one of the most well-known.

If the security vulnerabilities were severe enough and the risk sufficiently high to remove from the repository a plugin downloaded a few hundred times, then the risk posed to users by the original plugin must be immesurable - and yet, the plugin remains in the repository, with severe security vulnerabilities intact. The unknown author's plugin was removed immediately and without warning, while the well-known author's plugin remains, after weeks of notice of the vulnerabilities. The well-known author was informed directly regarding the security vulnerabilities before any action was taken, while the unknown author was never contacted directly before or after action was taken.

This practice is a nepotistic double standard, applied based on the relative popularity of both plugins and authors. It is also hypocritical: the plugin that - by far - posed the greatest risk was left, unpatched, in the repository, likely due to the very reason that it posed the greatest risk (sheer number of downloads), while the plugin that posed little-to-no risk (both because of its miniscule number of downloads, and because it didn't actually call the functions that contained the vulnerable code) was removed from the repository without warning, hesitation, or question.

Leading By Example

While all of the scenarios I have mentioned deal with the wordpress.org plugin repository, my statements are in no way intended to reflect upon the repository moderator, whose responsibilities are as arduous as they are thankless. MarkR works incredibly hard moderating the repository, and has been one of the lone bright spots in each of these scenarios. He was the one who worked with the plugin authors in the latter two cases, to help them restore their plugins to the repository.

I would also like to point out that Mark Jaquith has also been nothing but helpful, both in helping the plugin authors correct the problems with their plugins and also in helping to explain to the community the actions that were taken and the reasoning behind them. He has shown patience, understanding, and respect in dealing with the WordPress community regarding these issues.

Perhaps more of the WordPress community needs to follow the example set by MarkR and Mark Jaquith.

Conclusion

This is no way to build a community.

All of these actions, behaviors, and attitudes are damaging to the WordPress community. Because of them, would-be community members are driven away, less code that might benefit the community is contributed, and WordPress users are left exposed to security vulnerabilities. Because of them, new and non-expert developers are discouraged from attempting to contribute. Because of them, opportunities to reach out and to bring others into both the WordPress community and the free-software philosophy are squandered.

Free software projects (and the communities built upon and around them) are best-served by attracting to the community all who would participate - whether that participation is contributing code, just using the software, or somewhere in-between - by encouraging contributions from all who would contribute, and by displaying patience, understanding, and a willingness to help such contributors when they make mistakes as they are learning how to contribute.

Rather than close-mindedness, display acceptance, understanding, and tolerance. Rather than arrogance and condescension, display respect, humility, and a willingness to forgive.  Rather than hypocrisy, display openness and truth. It is in an environment that displays such attitudes that a free-software community can best thrive, and in which the most noble and well-intentioned principles of free-software philosophy are exemplified and promoted.

Haloscan Discontinued: Why NOT to Use Third-Party Services

Filed in Web DevelopmentTags: Geekery, Haloscan, Plugins, Web Site, WordPress

When I first started blogging many years ago, I used the Blogger platform, which I imported to my own domain using FTP (so that anyone reading my blog would see it as www.chipbennett.net). At the time, Blogger's commenting system was rather rudimentary, so I opted to use a third-party comment management system called Haloscan.

Interestingly, due to developments over the past couple of months, had I stuck with this arrangement, I would be in serious trouble. Recently, Haloscan was bought by Echo, which has announced that Haloscan is being discontinued in a matter of days. Likewise, Blogger has recently announced that it is discontinuing support for FTP importing of Blogger-hosted blogs to third-party domains.

Fortunately, I long ago left Blogger for the infinitely better self-hosted WordPress. Thus, even though Blogger has implemented a replacement service - their Custom Domains feature - and therefore the change would be minor, I don't have to worry about it at all.

More problematic, however, is the announced discontinuation of the Haloscan commenting system. When I first moved to WordPress, I continued to use Haloscan, which I had been using on Blogger. At some point, I decided to make the jump to native WordPress comments - but I still had several hundred comments hosted by Haloscan.

At the time, I was unable to export those comments from Haloscan, as such exports required the purchase of a Haloscan Pro account. So, I modified my blog theme to account for the old Haloscan comments, and kept a hybrid system.

Now, however, with the announced discontinuation of Haloscan, my hand was forced. Fortunately, Echo offered the option of converting to a (paid) Echo account, or exporting Haloscan comments. I quickly exported my comments, as I had no desire to pay for something that I was doing natively from within WordPress.

Thus, the problem became one of how to import several hundred comments into my WordPress database? Fortunately, this script came to the rescue, with a slight modification provided by the script developer. Using the provided script and the export.xml file provided by the Haloscan export, I seamlessly pulled all of my several hundred Haloscan comments into my WordPress database.

If you find yourself facing the same situation, the above script should help you as well.

Importing Blogger-Integrated Haloscan Comments

If you need to import Blogger-integrated Haloscan comments into your WordPress installation, follow the instructions provided by the script author, at the above link.

Importing WordPress-Integrated Haloscan Comments

If you, like I did, integrated your Haloscan comments directly into your WordPress installation, do the following:

  1. Download the script.
  2. Replace lines 77-81 of the script with the following code:

    $meta_records = $wpdb->get_results("select * from $wpdb->posts");

    foreach ($meta_records as $meta_record) {
    $blogger_to_wordpress[$meta_record->ID] = $meta_record->ID;
    }

  3. Upload the modified script file to www.domain.com/wordpress/wp-admin/ (where domain.com is your domain name)
  4. Export your existing Haloscan comments by logging into your Haloscan account and following the instructions provided.
  5. Upload the resulting export.xml file to www.domain.com/wordpress/
  6. Using your browser, go to www.domain.com/wordpress/wp-admin/import-haloscan.php
  7. Click the "OK" button to perform the import.

If your experience is like mine, you may get an error regarding a malformed XML file, due to its encoding. There are various options for rectifying the problem, but in my case, I just went to the line in export.xml indicated by the error message, and replaced the non-UTF-8 characters (in my case, fancy quote marks) with valid characters, and re-ran the script. Everything worked flawlessly at that point.

Auditing WordPress Plugins for License Information

Filed in Web DevelopmentTags: Geekery, GPL, Plugins, WordPress

The wordpress.org Plugin Repository requires adherence to a few simple guidelines in order for plugin authors to have their plugins hosted there:

  1. Your plugin must be GPL Compatible.
  2. The plugin most not do anything illegal, or be morally offensive (that’s subjective, we know).
  3. You have to actually use the subversion repository we give you in order for your plugin to show up on this site. The WordPress Plugins Directory is a hosting site, not a listing site.
  4. The plugin must not embed external links on the public site (like a "powered by" link) without explicitly asking the user's permission.

Lately, however, those guidelines have apparently been interpreted somewhat more strictly (emphasis added):

(13:27:03) KnxDT: By the way: Is the GPL header necesary?
(13:27:18) markr: very.
(13:27:28) KnxDT: because WP didn't mention in the standar readme.txt
(13:27:37) markr: Ideally you would include the gpl in a gpl.txt file
(13:27:57) markr: not including the declaration will get it removed
(13:28:10) markr: users have to know what they can do if they wish

I find the assertion that not including explicit license information with a plugin would result in the plugin being removed from the repository to be at odds with the current state of plugins in the repository. To confirm my suspicion that a significant number of plugins hosted at the wordpress.org Plugin Repository did not conform to this requirement, I did a quick audit of both my own installed plugins, and the current Top Ten Most Popular plugins in the repository. I posted my findings in the WPTavern forum. In short:

  • Almost 2/3 of the plugins I personally have installed don't have GPL information in the plugin
  • 2 of the Top Ten most popular plugins at Extend don't have GPL information in the plugin
  • 1 of the Top Ten most popular plugins at Extend violates the requirement that the entire plugin be distributed under a GPL-compatible license

Based on these findings, I decided to audit a few well-known and influential plugin authors - not to pick on the more high-profile developers per se, but rather to determine the state of license inclusion in plugins developed by those who, ideally, should be leading by example.

Here's what I found:

Matt Mullenweg

Plugins:
Notes:
  • bbPress was originally a stand-alone script, that included a license.txt file.
  • SyntaxHilighter Plus was written by Viper007Bond, but credited to Matt.
  • Top Comments was written by Andrew Ozz.
  • Sympathy For The Devil was written by Jeff Schult
Summary:

(0/19) of Matt Mullenweg's plugins written as a plugin and maintained by him have license notice of some kind. Shockingly, the majority of Matt's plugins lack even a readme.txt file.

Mark Jaquith

Plugins:
Summary:

(13/21) of Mark Jaquith's plugins have license notice of some kind (including one with both a license.txt file and plugin header license notice).

Ozh

Plugins:
Summary:

(0/16) of Ozh' plugins have license notice of some kind.

Peter Westwood (westi)

Plugins:
Summary:

(4/9) of Westi's plugins have license notice of some kind (including one with both a license.txt file and plugin header license notice).

Viper007Bond

Plugins:
Notes:
  • SyntaxHighlighter Evolved includes license.txt file from original SyntaxHighlighter written by Andrew Ozz
  • SyntaxHighlighter Plus includes license.txt file from original SyntaxHighlighter by Alex Gorgatchev
Summary:

(11/33) of Viper007Bond's plugins have license notice of some kind.

Overall Summary

Overall, for the plugin authors listed, only 28 out of 107 plugins (26%) have license notice of some kind (including two plugins that have both a license.txt file and a plugin header license notice). And the number is only that high thanks to Mark Jaquith, without whom the percentage of plugins with license notice of some kind would drop to less than 18%. Only 2 out of 107 plugins (<2%) include both a license.txt file and license information in the plugin header.

I find these numbers to be downright shocking, considering the unwritten rule now being enforced regarding removal from the repository of plugins that lack license disclosure, as well as the assertion that plugins should "ideally" include a license.txt file.

Let me be clear: I fully support the effort to ensure that plugin authors explicitly disclose license information in their plugins, either in the plugin header or in a separate license.txt file. The assertion that users need to be given explicit explanation of their rights to use, modify, and distribute plugins.

That said, perhaps those in the WordPress project leadership, and the plugin developers whom others look up to, should ensure that they are leading by example before a more-strict interpretation of the Plugin Repository guidelines is enforced against plugin developers at large.

Further, since new plugin developers will likely refer to the official wordpress.org Plugin Repository Readme File standard (which currently is silent on the matter of license disclosure) when determining what information needs to be included with their plugins, I would recommend that the standard be modified to include a License section - perhaps something like such:

== License ==

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more details.

This way, new plugin authors would have a standard means of disclosing license information in their plugin - and also, users searching Extend for new plugins would have a known means of determining the license of any given plugin.

What are your thoughts?