Don’t use strlen()

Each time I see someone use strlen() I cringe. It will break.

Despite its name, strlen() doesn’t count characters. It counts bytes. In UTF-8 a character may be up to four bytes long.

So what happens if we use strlen() and its companion substr() to shorten the title of post?

<?php # -*- coding: utf-8 -*-
declare( encoding = 'UTF-8' );
header('Content-Type: text/plain;charset=utf-8');

$string = 'Doppelgänger';
print 'strlen():    ' . strlen( $string ) . "\n";
print 'mb_strlen(): ' . mb_strlen( $string, 'utf8' ) . "\n\n";

print 'substr():    ' . substr( $string, 0, 8 ) . "\n";
print 'mb_substr(): ' . mb_substr( $string, 0, 8, 'utf8' );

Output:

I have to use an image here. If I had used the plain text output our newsfeed would break. And that’s what happens each time you use strlen() and substr() on strings encoded in UTF-8: You end up with partial characters and invalid UTF-8.

Alternatives for mb_strlen()

You can use different methods to get the real string length.

$length = preg_match_all( '(.)su', $string, $matches );

See also Hakre: PHP UTF-8 string Length.

Or just use …

$length = strlen( utf8_decode( $string ) );

There is also a nice php-utf8 library on GitHub from Frank Smit.

Implement a 404 image in your Theme

Every good Theme comes with a 404.php for requests that don’t match any post or page. But what to do with missing images? They are requested per an <img> element usually, your visitors may never see the HTML template. Let’s use a 404 image.

I put the following code on top of my 404.php before get_header():

// @version 2011.12.23
// matches 'img.png' and 'img.gif?hello=world'
if ( preg_match( '~\.(jpe?g|png|gif|svg|bmp)(\?.*)?$~i', $_SERVER['REQUEST_URI'] ) )
{
    header( 'Content-Type: image/png' );
    locate_template( 'img/404.png', TRUE, TRUE );
    exit;
}

My 404 image is bright, eye-hurting red to let me see it easily during the tests.

404

License: WTFPL. Grab it while it’s red.

Pretty permalinks without mod_rewrite

There are still some third-class web hosters who do allow the .htaccess files … and turn off the standard module mod_rewrite. But without mod_rewrite, WordPress cannot use pretty permalinks, right? Wrong!

There’s another directive we can use: ErrorDocument.

ErrorDocument 404 /index.php

This will do almost the same as the rewrite rules WordPress offers. It will not work with caching plugins like W3 Total Cache, it will not catch empty searches and other .htaccess tricks you may want to use. So consider this trick as a temporary solution until you have found a real web hoster.

Advent Calendar- How to disable comments for WordPress pages in any theme

Usually you don’t need comments on pages. Unfortunately, WordPress doesn’t offer a separate option to leave comments on posts on and turn them off for pages. If your theme calls comments_template(); in its page.php and you don’t want to break automatic updates, you cannot just remove the function call, because it will be overwritten with the next update.

No problem. There’s an hook for that. It’s a filter called … wait for it … comments_template. We can change the path to the comments template here – if haven’t figured that out already. Let’s build a small plugin.

So, what do we do? We hook into comments_template(); and change the path. Our new path should point to an existing file without any HTML output. In this case, we use just our plugin file, because we know it exists and we control the output.

As you may have noticed our plugin file is included two times: First as a plugin, later as a replacement for comments.php. The function_exists() check prevents any You cannot redeclare … errors.

Putting this all together …

<?php # -*- coding: utf-8 -*-
/**
Plugin Name: Disable Comments On Pages
Version:     1.0
Author:      Thomas Scholz
Author URI:  http://toscho.de
License:     GPL
*/
// This file is not called from WordPress. We don't like that.
! defined( 'ABSPATH' ) and exit;

// If the function exists this file is called as comments template.
// We don't do anything then.
if ( ! function_exists( 't5_disable_comments_on_pages' ) ) {
	/**
	 * Replaces the path of the original comments template with this
	 * file's path on pages.
	 *
	 * @param  string $file Original comments template file path.
	 * @return string
	 */
	function t5_disable_comments_on_pages( $file ) {
		return is_page() ? __FILE__ : $file;
	}

	add_filter( 'comments_template', 't5_disable_comments_on_pages', 11 );
}