Tuesday 20 December 2011

Fixing wordpress

Today I was still clearing up errors on my photo website discovered by the IIS Site Analyzer. Mostly I was trying to fix wordpress errors.

The problem is that the url of my blog is /blog/, but wordpress doesn't let you specify that the url ends in a trailing slash. So often when wordpress generates a link back to the blog homepage, it will use a url of /blog, which then creates an unneeded redirect to the correct address of /blog/.

The urls of tags and categories are /blog/tag/tag-name or /blog/category/category-name and again, there is no way to change this (that I know of) to force them to end in a trailing slash. The problem here is the opposite, that often when wordpress generates a link to the tag or category, it will end with a trailing slash e.g. /blog/tag/tag-name/. So this then creates an unneeded redirect to the correct address of /blog/tag/tag-name.

After trying various things and much research I ended up with the following in my theme's functions.php file:

//Wordpess won't save the site/blog URL with the needed trailing slash, so we have to add it manually here
add_filter( 'index_rel_link', 'fix_index_rel_link' );
function fix_index_rel_link(){
 return '<link rel="index" title="David Kennard Photography" href="'.get_bloginfo('url').'/" />';
}
//In the opposite way, Wordpress adds trailing slashes to URLs that don't need them, so we have to remove it manually here
add_filter('get_pagenum_link', 'fix_get_pagenum_link');
function fix_get_pagenum_link($w){
 //match an ending slash or slash followed by query string, so long as the slash isn't immediately preceded by /blog
 return preg_replace('/(?<!blog)(\/$|\/(\?))/', '$2', $w);
}

Next I found that the feed had similar problems, and also was using the same description for every category and tag. However I couldn't find a way to filter the info used in the feed. The feed uses bloginfo_rss() to get the various info. While it is possible to filter this, it didn't seem possible to get the type of info that had been requested. So if I created a filter, the same filter would be run on bloginfo_rss('url'), bloginfo_rss("description"), and bloginfo_rss('name'), and there is no way to tell in the filter function whether you are filtering a url, description, or name.

So, what I had to do instead is to add a custom feed template to my theme. I copied the default feed-rss2.php file into my theme directory. In functions.php I added:

//Default wordpress feed doesn't give correct title on tag pages etc. so use a custom feed
remove_all_actions( 'do_feed_rss2' );
add_action( 'do_feed_rss2', 'dkphoto_feed_rss2', 10, 1 );
function dkphoto_feed_rss2( $for_comments ) {
    $rss_template = get_template_directory() . '/feed-rss2.php';
    load_template( $rss_template );
}

For the custom feed I wanted to use the same titles, descriptions etc. that I used for the non feed page equivalents. So I removed the logic that pulled these from my theme's header.php file and put it into a separate file, which I named header_pageTypeDetect.php. Googling to find how to include the new file, I found the function get_template_part(). However, this didn't work as the variables created in header_pageTypeDetect.php were scoped within the get_template_part() call. Since the variables created in header_pageTypeDetect.php needed to be accessed by header.php and feed-rss2.php, this was no good.

The solution is instead to use a standard include with get_template_directory() to get the correct path. e.g. include(get_template_directory().'/header_pageTypeDetect.php');.

After getting this set up, I found that while the feed was working for most pages, it wasn't working for /blog/feed. The reason was that I was using is_home() to detect the front page of the blog, but this doesn't work for the feed of the blog home. Unfortunately, there doesn't seem to be any functions available to detect if you are at the feed of the blog homepage.

So what I did instead was to do my standard checks, setting the title and description etc. appropriately, then at the bottom I added

//If this is the main feed page /blog/feed
elseif(is_feed() && !is_archive()){
   //set the title, description etc. here
}

Since I had already done a check for single posts and pages, I knew that if the check got this far, and it was a feed and not an archive (tags, categories etc.), then it must be the feed for the home page.

While working on this I found that some of my blog pages had extremely long meta keywords tags. This is because I was including all the keywords for all posts on a page. Doing some googling, it seemed to be generally recommended to stick to only about 10 keywords: Google Webmaster Central: Max length of Meta Tags ?. So it looked like I should only include the 10 most common keywords from the posts on the page rather than all the keywords.

For figuring out the keyword popularity, I thought that the keyword cloud widget must already do something along these lines. However, I couldn't see any code easily borrowable from the keyword cloud widget, so I just wrote my own logic:

if(have_posts()){
 $metaKeywords = array();
 //var_dump($wp_query); exit();
 //get all the tags for posts on this page
 while (have_posts()){
  the_post();
  $tags = get_the_tags($post->ID);
  if($tags){
   foreach($tags as $tag){
    if(isset($metaKeywords[$tag->name])){
     $metaKeywords[$tag->name]+= 1;
    }
    else{
     $metaKeywords[$tag->name] = 1;
    }
   }
   unset($tags, $tag);
  }
 }
 //Sort the keywords by most used and select only the top 10
 if(count($metaKeywords)>10){
  arsort($metaKeywords);
  $metaKeywords = array_slice($metaKeywords,0,10,true);
 }
 $metaKeywords = array_keys($metaKeywords);
}

Another thing that the IIS Site Analyzer brought to my attention today is that I was serving some pages with text/xml, while others were being served with application/xml. I read What's the difference between text/xml vs application/xml for webservice response, and it seems that it doesn't make much difference what one you use (text/xml means easily readable by humans, application/xml means not easily readable by humans).

Along other lines today, DPS had a special offer of all 35 ebooks from Craft & Vision for $99 (40% off). After looking at some of the book pages and customer comments on the Craft and Vision site, it did look like a great deal. However, in the end I decided against it. I already have tons of stuff I've bought and not had time to read or use yet. If I bought the e-books they'd probably just be added to that 'pile'. Better to save the money for spending on a new camera or lens.

I also had a message from Red Bubble that they were offering 20% off gift vouchers. I thought this sounded quite good as you could buy the voucher then use it to buy a T-shirt for yourself. Most of the T-shirts on the site seemed quite expensive, so I wondered how much it costs to make you own shirt. Checking their prices, it costs £12.40 for a White Unisex S-XL Tee. This is excluding VAT at 20%. Since the voucher is 20% discount, £12.40 would essentially be the price you pay (I couldn't see anything about there being additional shipping charges). I checked Zazzle, and they were charging about £15.50 for the same, so seems quite a good deal to me.

No comments: