get_permalink memory usage issues

Every post that you call get_permalink for is added to the object cache (in memory). Now, if you’re doing a get_permalink call, 9 out of 10 times you’ll need to more of that post than just the permalink, so this isn’t really a problem. However, in some cases, especially when you do large quantities of get_permalink calls, this is a problem.

Most people call get_permalink like this:

$url = get_permalink( $post->ID );

or like this:

$url = get_permalink( 123 );

What most people don’t realize though, is that you can actually feed get_permalink a post object, simply like this:

$url = get_permalink( $post );

Let’s look a bit closer at the core code to see what the difference is, this is the code in get_permalink that decides whether to do get_post or not, get_post is the function that actually caches the post:

if ( is_object($id) && isset($id->filter) && 'sample' == $id->filter ) {
	$post = $id;
	$sample = true;
} else {
	$post = &get_post($id);
	$sample = false;
}

Calling it with a post object is actually already slightly faster than calling get_permalink with $post->ID (in get_post it then only sanitizes and adds to cache, it doesn’t fetch new data), but the real benefit comes when you add a variable called filter in the $post object, setting it to “sample”. Now you decide whether that post object is going to be cached or not and which variables it contains. At a minimum, a post object that you feed to get_permalink needs the following variables to create a URL1:

  • ID
  • post_author
  • post_date
  • post_name
  • post_parent
  • post_status
  • post_type

So if you’re doing a query to wp_posts yourself, you could retrieve those values and then use the generated objects to do a call to get_permalink. Doing this in my WordPress SEO plugin when generating XML sitemaps reduced memory usage drastically. A very much simplified (and therefor not very practical other than for explaining) example, could be:

$posts = $wpdb->get_results("SELECT ID, post_type, post_name, post_author, post_parent, post_modified_gmt, post_date, post_date_gmt
			FROM $wpdb->posts
			WHERE post_status = 'publish'
			AND	post_password = ''
			ORDER BY post_modified ASC
			LIMIT 100");

foreach ( $posts as $p ) {
	$p->post_status = 'publish';
	$p->filter	= 'sample';

	$url = get_permalink( $p );
}

A second step to take to further reduce memory is to clean the post objects term cache, its categories, tags, etc. To clean it for a post, within a loop, do something like this:

clean_object_term_cache( $post->ID, $post->post_type );

I hope this helps you to reduce the memory usage of your plugins! Happy coding!

1: If you’re writing custom code for one specific site and you know that for instance the date isn’t used in the permalink structure, you could of course leave that out too, never do that in a plugin or theme though!

Yoast.com runs on the Genesis Framework

Genesis theme frameworkThe Genesis Framework empowers you to quickly and easily build incredible websites with WordPress. Whether you're a novice or advanced developer, Genesis provides you with the secure and search-engine-optimized foundation that takes WordPress to places you never thought it could go.

Read our Genesis review or get Genesis now!