Allowing Hyperlinks in Your WordPress Excerpts

September 22nd, 2010  |  Published in Mind

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’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).

The first line I needed to change was the PHP function call strip_tags(). I need to set it to allow the <a> tag… very simple to do:

Original Line:

$text = strip_tags($text);

New Line:

$text = strip_tags($text, '<a>');

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 </a>, 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, <a href=”http://lewayotte.com/”>My Website</a>, would count as a single word. By default, WordPress creates a 55 word excerpt. That is pretty easy to change as well.

Original Line:

$words = preg_split('/[\n\r\t ]', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY );

New Line:

$words = preg_split('/(<a.*?a>)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE );

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:

<?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(']]>', ']]>', $text);
		$text = strip_tags($text, '<a>');
		$excerpt_length = apply_filters('excerpt_length', 55);

		$excerpt_more = apply_filters('excerpt_more', ' ' . '[...]');
		$words = preg_split('/(<a.*?a>)|\n|\r|\t|\s/', $text, $excerpt_length + 1, PREG_SPLIT_NO_EMPTY|PREG_SPLIT_DELIM_CAPTURE );
		if ( count($words) > $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');

Regular Expression Explained

I changed /[\n\r\t\s ]/ to /(<a.*?a>)|\n|\r|\t|\s/ because I needed to capture everything in the <a> HTML tags and count it as a single word. \n, \r, \t, \s are all pretty basic regex characters that preg_split() is using to break up the content. (<a.*?a>) is what captures everything in the <a> tag. The .* means all “characters” adding the ? to .* makes it “non-greedy.” This for the case where there are multiple hyperlinks in the content. It prevents the regex from thinking <a href=”link1″>link 1</a>, <a href=”link2″>link 2</a> is a single word. The parenthesis simply group the <a.*?a> together, so it doesn’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.

You should be able to use this as a pretty solid base for adding other HTML tags.

Tags: , , , , , , ,

Active Directory (LDAP) Authentication in WordPress Multi-Site

September 9th, 2010  |  Published in Mind

As many of you know, I led the team that launched the College of Education at UGA’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’s current AD implementation.

When I first researched this there weren’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 Clifton Griffin called Simple LDAP Login. I installed in on a development website, put in the necessary information and BAM it worked… but it wasn’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.

Clifton used the opensource PHP LDAP Class in his plugin, which works great. So, in my version, I stripped out everything I didn’t need/want like auto account creation, non-AD functionality, etc. Basically, I just needed to authenticate users via Active Directory.

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’ user table:

<?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->add( 'empty_username', __( 'ERROR: The username field is empty.' ) );

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

		return $error;
	}

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

			if ( !$user || ( strtolower( $user->user_login ) != strtolower( $username ) ) ) {
				do_action( 'wp_login_failed', $username );
				return new WP_Error( 'invalid_username', __( 'Login Error 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->ID );
			}
	} else {
		return new WP_Error( 'invalid_username', __( 'Login Error 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'		=>	ACCOUNT_SUFFIX,
		'base_dn'				=>	BASE_DN,
		'use_tls'				=>	USE_TLS,
		'use_ssl'				=>	USE_SSL,
		'domain_controllers'	=>	explode( ';', DOMAIN_CONTROLLERS )
	);

	$adldap = new adLDAP( $sll_options );

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

	return $result;
}

Tags: , , , , , ,

Remove Username Character Limit from WordPress Multi-Site / Multi-User

May 13th, 2010  |  Published in Mind

I’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 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’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).

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:

function remove_username_char_limit($result) {
  if ( is_wp_error( $result[ 'errors' ] ) && !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');

Tags: , , , , , ,