News

Navigation of Custom Post Type Archives in WordPress

WordPress changed when it introduced Custom Post Types – suddenly the possibilities were endless.  Wordpress had become the content management system we all were hoping it would.

But for one problem.  It was and still really isn’t clear how to include posts of  custom post types in your website navigation.  This article outlines how I do it.

Create a Custom Post Type

First I create a custom post type – let’s use the ubiquitous ‘movie’:

register_post_type('movie', array(
 'labels' => get_labels('Movie'),
 'supports' => array('title', 'editor', 'thumbnail', 'excerpt'),
 'has_archive' => true,
 'hierarchical' => false,
 'rewrite' => array('slug' => 'movies', 'with_front' => false),
 'public' => true
));

The function get_labels() is just a helper function I use to customise all the various labels required for each custom post type with a single function call.   I’ve included the source here:

function get_labels($singular, $plural = '') {
 if ($plural == '') $plural = $singular.'s';
 return array(
  'name' => $plural,
  'singular_name' => $singular,
  'search_items' => 'Search '.$plural,
  'popular_items' => 'Popular '.$plural,
  'all_items' => 'All '.$plural,
  'parent_item' => 'Parent '.$singular,
  'edit_item' => 'Edit '.$singular,
  'update_item' => 'Update '.$singular,
  'add_new_item' => 'Add New '.$singular,
  'new_item_name' => 'New '.$singular,
  'separate_items_with_commas' => 'Separate '.$plural.' with commas',
  'add_or_remove_items' => 'Add or remove '.$plural,
  'choose_from_most_used' => 'Choose from most used '.$plural
 );
}

Before we move on, go ahead and create a few dummy posts of our new post type ‘movie’.

Create a page for your custom post type archive, and add it to your menu

Next I create a page ‘Movies’ with slug ‘/movies/’.  Note that this slug of this page matches the slug defined in the rewrite property of our custom post type – this is important.

Make sure you then add your new page to the menu so that it appears in your site’s navigation.  By default, this will now load the page, and not show our recently created posts of custom post type ‘movie’ – let’s fix that.

Create a custom rewrite rule to get your list of posts of custom post type

Ultimately, we want WordPress to get both the page we created and our posts of post type ‘movie’.  But because we can’t create page templates bespoke to child pages, it’s best to tell WordPress to get the movies, and then to latch on the page later.  To do that, we’re going to use a custom rewrite rule.  Add the following code to your functions file.

// set up the rewrite
add_action( 'init', 'ft_setup_rewrites' );
function ft_setup_rewrites(){
 add_rewrite_rule('movies(/page/([0-9]+)?)?/??$','index.php?post_type=movie&paged=$matches[2]','top');
}

This basically adds a new rewrite rule ahead of the one that WordPress is currently using to locate a page from /movies/ and tells it instead to go get all posts of type ‘movie’.  I’ve also catered for paging.  With this rule in place, you’ll now find that when loading /movies/, wordpress now uses the archive.php template file to display a list of your movies.

But we’ve lost out page!

Customise archive.php to display the page content as well

That’s no problem, we can easily pull that back in.  Add the following code to archive.php before the loop:

<?php
 $slug =  parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
 $page = get_page_by_path($slug);
 if ($page) :
  setup_postdata($page);
?>

Using get_page_by_path($slug) ensures that child pages work as well as root pages.

Now I can use template tags (i.e. the_content(); etc.) as normal to get anything from our ‘Movies’ page, and all I need to do to return to our standard loop through the posts of type ‘movie’ is reset the post data and close our if statement:

<php
  wp_reset_postdata();
 endif;
?>

Alternatively, if you want to be able to call a template with a loop in it (i.e. while (have_posts()) : the_post(); etc), you can use the following code:

<?php
 $slug = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
 $page = get_page_by_path($slug);
 query_posts('post_type=page&p='.$page->ID);
?>
...
<?php wp_reset_query() ; ?>

This template file will now work for any custom post type we create – movies, books, products.  If we want our movie archive to display a little differently from archives of posts or other custom post types, we can further customise our movie template by saving ‘archive.php’ file as ‘archive-movie.php’ and making further customisations to this file.

How do you like that!?

Customize the JPEG Image Compression in WordPress

When you upload an JPEG image to WordPress, it compresses that image to improve performance when the site is being downloaded.  The default level of compression is 10% – that is to say the filesize is reduced to 90% of the original.

If your site and it’s message depends upon it’s imagery, or your target audience is sure to have a fast connection, you may feel that this level of image compression is too high.  Similarly, if your website’s imagery is not critical to the it’s purpose, you might like to increase the compression to maximise website performance.

To remove image compression in WordPress, add the following line of code to your theme’s functions.php file:

add_filter(‘jpeg_quality’, function($arg){return 100;});

To increase the level of image compression in WordPress, add the following line of code to your theme’s functions.php file instead:

add_filter(‘jpeg_quality’, function($arg){return 60;});

I have selected ’60’, but try a few different settings from 1-100, using Alex Mills’ Regenerate Thumbnails plugin to update your site after each change.

AJAX in WordPress: A template

To implement AJAX in wordpress themes, use the following template:

Javascript

var data = array();
data[‘action’] = ‘FUNCTION_NAME’;
new Request.HTML({
url: ‘/wp-admin/admin-ajax.php’,
update: $(‘results’)
}).post(data);

PHP

add_action(‘wp_ajax_FUNCTION_NAME’, ‘FUNCTION_NAME’);
add_action(‘wp_ajax_nopriv_FUNCTION_NAME’, ‘FUNCTION_NAME’);

function FUNCTION_NAME() {
…logic…
exit;
}

 

Improved branding for intraspin.com

intraspin.com has a new logo.  It’s been a long time coming, the previous logo was designed 6 years ago and lacked simplicity and a strong metaphor.

The new logo employs all caps and a bold typeface to present a strong presence to support a somewhat awkward name.  A complete re-brand was considered but decided against at this time.  The target symbol in place of the ‘dot’ in ‘dot com’ represents the marketing-driven approach taken by intraspin.com to web design.  Every detail in Iain’s designwork is customer-focused and can be justified in terms of ROI.

Iain also thinks the similarity to the heroic RAF logo is quite cool!  He’s just not sure what to do with it yet.

intraspin.com moves to new offices

intraspin.com has recently moved into new offices, shared with the designers of o street and BERG.  Previously a launderette and a general store before that, the new space has been completely renovated to high standard with a contemporary “designer” feel that is already having a massively positive impact on Iain’s creativity and productivity.

Continue reading

SQL required to move a WordPress Site to a new domain

To move a wordpress site from one domain to another, you need to execute the following SQL scripts on the database:
UPDATE wp_options SET option_value = replace(option_value, 'http://www.old-domain.com', 'http://www.new-domain.com') WHERE option_name = 'home' OR option_name = 'siteurl';

UPDATE wp_posts SET guid = replace(guid, 'http://www.old-domain.com','http://www.new-domain.com');

UPDATE wp_posts SET post_content = replace(post_content, 'http://www.old-domain.com', 'http://www.new-domain.com');

This works as of WordPress 2.8.

Web Marketing – A Brief Glossary

There are increasingly a range of acronyms being thrown around in web marketing that sometimes slip out when interacting with clients. Here’s a brief overview of some of the more common e-marketing acronyms to ease the conversation.

  • SEM
    Search Engine Marketing

    SEM is a broad term covering the range of activities you might engage in to improve the extent to which you generate revenue via search engines
  • SEO
    Search Engine Optimisation
    SEO focuses on the organic listings as opposed to sponsored listings, or PPC. The position of your site in the listings for a given search term is determined by a wide range of factors, each contributing to the search engine’s algorithm. They can be broadly divided, however, into two groups:

    • Content Relevancy: The greater the extent to which the content of a page matches the search term in question, the better it will rank (subject to the engine’s spam protection measures).
    • Trust relevancy The greater the extent to which a page is connected (by hyperlinks) to sites also well connected to other sites relevant to the search term, the better it will rank, based on it being a trusted resource.
  • PPC
    Pay Per Click
    Many search engines present two listings when the user makes a search – the main, organic search results, and the sponsored listings. To achieve a sponsored listing, you must agree to pay a certain amount to the search engine every time someone clicks on your listing. Your bid compared to that of your competitors determines your position in the listing – bid prices can range from a few pence for less competitive phrases to several pounds for very competitive phrases. Most often however clicks will cost less than £0.50.
  • SMO / SMM
    Social Media Optimisation / Social Media Marketing
    More recently, a new area has opened up in web marketing with the arrival of social networking and in particular social news websites, such as Digg, Reddit, and a host of others. These sites allow you to submit content to their ‘Upcoming’ listing, presented initially in reverse date/time order. As time passes, if your site receives votes, it maintains it’s high position and may reach the ‘popular’ listing. This is encouraging marketers to be creative and generate interesting content, as the potential returns of getting ‘dugg’ are substantial in the short and long term.

UK Google Market Share 2008

Following our post last year on Google UK’s market share in 2007, here are some figures providing an indication of Google’s Market share in the UK in 2008. Hitwise are providing the numbers again, and in a relatively short sampling period during March 2008, they found Google to be holding a market share 87.5%, 10 percentage points greater than the same figures for 2007. They found 73.7% to be using google.co.uk, and 13.8% google.com. Clearly Yahoo, Microsoft and Ask among others have therefore lost ground to their primary competitor.

UK Google Market Share 2008

Particularly interesting in the same report was the statistics regarding the proportion of users opting to use Google’s ‘Pages from the UK’ search option. The report confirms intuition by showing only 13.6% of searchers to make use of this facility. This will help you decide the relative value of a .co.uk TLD vs. a .com or alternative (a google.co.uk search for ‘Pages from the UK’ will only return pages with a .co.uk TLD).

For more details, click through hitwise.

MooTools’ Garbage Collection and IE’s ‘Stop this script running?’ error

I wrote a post before the weekend about some performance issues with MooTools, DHTML and AJAX, but having found the solution to a related problem this morning, I wanted to post a followup.

I’ve been working with a large, dynamically generated and AJAX populated table that features sorting, filtering and row highlighting, and was finding that my table took a long time to render, and was also very slow to close – that is, when I tried to close the window or refresh the page, there would be a delay when the browser would first hang for a few seconds. IE often (but not always) popped up the error/prompt Stop this script running?, and Firefox less often threw it’s Unresponsive Script warning.

I’d heard of MooTools’ garbage collection functions that reduced memory leakage, and figured that these were probably responsible. I then found Kevin Smith’s write up of his similar experience, and came to understand the problem. MooTools’ garbage collection takes time to clean up any element that has been extended. My table was executing the following code, effectively extending every table row in the table, resulting in some 500+ extended elements.

// MooTools Code
Element.extend({

getChildren: function(){
return $$(this.childNodes);
},

});

// My Code
this.tablerows = this.body.getChildren();

When it came to cleanup, this javascript processing took longer than IE’s configured script timeout, and thus prompted the warning.

To avoid this cleanup overhead, you’ll have to avoid extending the elements with MooTools’ extensive set of functions and instead extend the specific elements in question with the specific functions required.

MooTools, AJAX, DHTML and Performance

I first delved into javascript frameworks with Prototype, but I quickly realised that the Prototype+Script.aculo.us combination, even in Protocoluous or Protopackt form, was never going to work – it was just too slow.

I moved to MooTools, and for a while was pretty happy – load times were quicker, effects smoother.

But having recently tried to build sorting and filtering functionality into an HTML table of 200+ rows, I’ve been forced to take a closer look at how different browsers execute javascript, and at where the bottlenecks are. Here I’m going to promote a few best practices, largely via Julien LeComte at Yahoo.

Inserting new Elements

Working with the DOM in MooTools is a breeze – code like the following is a pleasure to write and to read:

var div = new Element(‘div’, {id:’example’}).addClass(‘example’).setHTML(‘Example Content’).injectAfer(‘previousElementID’);

However it’s worth noting that the Element class uses ‘document.createElement’, which is much more expensive than the alternative, albeit less readible innerHTML. Further, inject() and adopt() functions use appendChild() and are also thus very expensive. An it certainly feels like this effect is magnified when working with tables.

Changing Existing Elements

Working with with DOM can cause performance issues, but if the DOM element in question is not visible (display:none), or if the DOM element is ‘off-DOM’, you’ll acheive a performance gain.

Retrieving Values from the DOM

Retreiving values from the DOM is much more expensive than referencing a local variable:

// bad code
children.each(function(child) {
if (child.getText() == otherElement.getText()) alert(‘slow’);
});

// good code
var text = otherElement.getText();
children.each(function(child) {
if (child.getText() == text) alert(‘fast’);
});

Attaching Event Handlers

Attaching events is also very slow. To tackle this, instead of looping through multiple elements attaching events, attach the event handler to the parent, and within the handler detect which element has been clicked:

// bad code
children.each(function(child) {
child.addEvent(‘mousedown’, function () {
alert(child.getText());
}
});

// good code
parent.addEvent(‘mousedown’, function (e) {
var child = new Event(e).target;
alert(child.getText());
}

By applying these ideas, I was able to cut the processing time of loading a table by more than 70%, and hopefully you can benefit too.

"Iain clearly has a deep understanding of user needs and business goals and an ability to translate these into well documented designs."

Denise Ross
UX Designer Barclays Bank PLC

Think we may be able to help you? Why not start a conversation - chances are, you'll go away with some new ideas and knowledge.