---
title: Allow Plugins to Short-circuit wp_nav_menu
date: 2013-02-26T14:42:34+00:00
modified: 2013-02-26T14:56:13+00:00
image:: https://kaspars.net/wp-content/uploads/2013/02/wp-debug-menu-query-wp-nav-menu.png
permalink: https://kaspars.net/blog/filter-pre-wp-nav-menu
post_type: post
author:
  name: Kaspars
  avatar: https://reverse.kaspars.net/gravatar/avatar/92bfcd3a8c3a21a033a6484d32c25a40b113ec6891f674336081513d5c98ef76?s=96&d=mm&r=g
post_tag:
  - MySQL
category:
  - Web Performance
  - WordPress
---

# Allow Plugins to Short-circuit wp\_nav\_menu

![Database queries necessary for wp_nav_menu](https://kaspars.net/wp-content/uploads/2013/02/wp-debug-menu-query-wp-nav-menu.png?strip=all&quality=90&resize=500,330)

I just submitted my second [WordPress core patch that adds a short-circuit filter](http://core.trac.wordpress.org/ticket/23627) at the top of [`wp_nav_menu`](http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/nav-menu-template.php#L136) which enables plugins to retrieve rendered menu output from a transient or non-persistent cache instead of relying on relatively complex database query that returns one of the most static items of every website.

### Why is this important?

To illustrate the complexity of menu retrieval, here is a list of all database queries that are run on **every** page load:

1. [Retrieve term object](http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/nav-menu-template.php#L148) of the `nav_menu` taxonomy that corresponds to the specific menu name.
2. [Retrieve menu item IDs](http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/nav-menu.php#L480) (not complete post objects, yet) that are in the particular term.
3. [Query for menu item post objects with the specific IDs](http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/nav-menu.php#L493) and retrieve three `post_meta` values per each menu item.
4. [Retrieve post and term objects](http://core.trac.wordpress.org/browser/tags/3.5.1/wp-includes/nav-menu.php#L499) corresponding to **each** menu item (map every `nav_menu_item` post to the actual post, page or archive page).

and here are the corresponding query samples:

#### Retrieve `nav_menu` term object:

```
SELECT t.*, tt.* FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy = 'nav_menu' AND t.term_id = 2 LIMIT 1
```

#### Retrieve menu item IDs:

```
SELECT tr.object_id FROM wp_term_relationships AS tr INNER JOIN wp_term_taxonomy AS tt ON tr.term_taxonomy_id = tt.term_taxonomy_id WHERE tt.taxonomy IN ('nav_menu') AND tt.term_id IN ('2') ORDER BY tr.object_id ASC
```

#### Retrieve menu item post objects:

```
SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.ID IN (5,6,7) AND wp_posts.post_type = 'nav_menu_item' AND (wp_posts.post_status = 'publish') ORDER BY wp_posts.menu_order ASC
```

#### Retrieve post meta for all menu items:

```
SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (5,6,7)
```

#### Retrieve post, post meta and term objects corresponding to each menu item:

```
SELECT wp_posts.* FROM wp_posts WHERE 1=1 AND wp_posts.ID IN (2) AND wp_posts.post_type = 'page' AND (wp_posts.post_status = 'publish') ORDER BY wp_posts.post_date DESC
```

```
SELECT post_id, meta_key, meta_value FROM wp_postmeta WHERE post_id IN (2)
```

```
SELECT t.*, tt.* FROM wp_terms AS t INNER JOIN wp_term_taxonomy AS tt ON t.term_id = tt.term_id WHERE tt.taxonomy IN ('category') AND ( t.term_id = 1 ) ORDER BY t.name ASC
```

That is **seven queries** just to get the menu items. By adding `pre_wp_nav_menu` we would allow plugins to retrieve the whole menu HTML straight from a transient or object cache.