I just submitted my second WordPress core patch that adds a short-circuit filter at the top of wp_nav_menu
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:
- Retrieve term object of the
nav_menu
taxonomy that corresponds to the specific menu name. - Retrieve menu item IDs (not complete post objects, yet) that are in the particular term.
- Query for menu item post objects with the specific IDs and retrieve three
post_meta
values per each menu item. - Retrieve post and term objects 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.
Great addition man! Looking forward to using this in production.