I am looking to create a custom 'directory' page which will link to several thousands of posts. Because of the large number I am trying to limit the number of DB queries. I notice that to link to each post, I am calling get_permalink() and this is creating an extra DB query for each post.

Is there anyway to retrieve the post permalink without an additional query? I have tried passing the $post object which doesn't seem to help. I've also had a look at the core function, and noticed passing the whole object along with a $post->filter = 'sample' value will avoid an additional get_post() call as per:

Why does `get_permalink()` produces an add. DB request without $post->filter?

But it still seems to be causing an extra query. Any ideas?

  • How does your test loop look like and is this on a vanilla install? Maybe you could post a testable code snippet? @NJ
    – birgire
    Jul 24, 2015 at 10:38

1 Answer 1


I notice that to link to each post, I am calling get_permalink() and this is creating an extra DB query for each post.

Not true. If you check the link to the very old trac ticket #18822 in the post that you have linked to, this issue was raised by @kaiser in 2011. The question was answered by @scribu

For example:

$posts = get_posts();
foreach ( $posts as $post )
    var_dump( get_permalink( $post->ID ) );

will not cause extra queries as all those posts are cached. You can also pass the whole $post object to get_permalink for no extra queries as get_post() accepts an object. In fact get_post() will only perform a query if you pass an object when the object has the filter property set and that post ID isn't already cached.

As always, I do not go on theory, but on facts, and the way I get my facts is in testing

Set yourself up with the following query and run it, and note the time and db calls

$posts = get_posts();
foreach ( $posts as $post ) {


echo '<p>' . get_num_queries() . ' queries in ' . timer_stop(1, 5) . ' seconds. </p>';

On my local install I get the following results:

20 queries in 0.02539 seconds

(NOTE: The amount of queries is not just for the query, but the total amount of queries that run on the page, this included menus, widgets, custom queries, main query etc. Times may vary on every page load)

Now, change the query as indicated below

$posts = get_posts();
foreach ( $posts as $post ) {

    get_permalink( $post->ID );

echo '<p>' . get_num_queries() . ' queries in ' . timer_stop(1, 5) . ' seconds. </p>';

And this is my result

20 queries in 0.02539 seconds.

As you can see, and as I have proved, the cache is first check before making a query as described in the trac ticket.


You can use get_permalink() and you don't have to worry about extra db calls due the cache system in Wordpress. You should take your time as well and work through the trac ticket

  • I actually used a similar technique using a plugin to track number of queries and page load times and I was seeing hundreds of extra queries being run hence my investigation.
    – NJ.
    Jul 24, 2015 at 4:45
  • Then the post results is not being cached. I wonder if we can maybe use the post guid and work from there :-). The guid holds the ugly permalink of the post Jul 24, 2015 at 5:01
  • Did you try out this test by Pieter? @NJ
    – birgire
    Jul 24, 2015 at 10:39
  • @birgire seems like the OP has some issue with the cache. Jul 24, 2015 at 16:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.