I recently had the need to add a series of anchor links to a WordPress menu that linked to specific sections of a page. I found this to be tedious, since the page URL needed to be hard coded into the custom link menu item and if the page URL was ever updated each anchor needed to be updated as well. To complicate things further, when looking at the custom link within the menu editor it’s not immediately obvious that the link is an anchor if the URL is longer than the input box.
What I wanted to be able to do is simply create a custom link menu item and set the link value to #my-custom-anchor. Generally if you create a custom link menu item and set the link to be something like #my-custom-anchor it will work, if you’re already on the page for the given anchor, however it will also navigate to “my-custom-anchor” even if you’re on another page where “my-custom-anchor” doesn’t exist.
What I needed was for the anchor to navigate to the desired page and then to the specific section of the page. To do this, the URL would need to have the page URL prepended to the anchor hash. This would allow anchor links to be clicked from anywhere on the website and still navigate to the correct page, and correct section, but if the page was already being viewed the page would not reload (so scrolling animations would still work as well).
Since all of the anchor links were nested under a page menu item, as illustrated in the example below, I was able to filter the menu and prepend the URL with the URL of its’ parent menu item.
Menu Structure Example
- Page Menu Item 1
- Page Section 1 Anchor Menu Item
- Page Section 2 Anchor Menu Item
- Page Section 2 Sub Section 1 Anchor Menu Item
- Page Section 2 Sub Section 2 Anchor Menu Item
- Page Section 3 Anchor Menu Item
- Page Menu Item 2
- Page Menu Item 3
In the above example each “Page Section… Menu Item” would link to “Page Menu Item 1” and scroll to the specified section of that page. This is very useful for long pages with many sections and sub-sections.
The Solution is in the Code
To accomplish this I created a menu filter function, that gets added to the themes functions.php file, that searches for menu items with URLs that begin with a # and then prepends the URL with the URL of its’ parent menu item.
function lb_menu_anchors($items, $args) { $urls = array(); $custom_anchor_links = array(); foreach ($items as $key => $item) { $urls[$item->ID] = $item->url; if ($item->object == 'custom' && substr($item->url, 0, 1) == '#') { $custom_anchor_links[] = $item; } } foreach ($custom_anchor_links as $custom_anchor_link) { if (strpos($urls[$custom_anchor_link->menu_item_parent], '#') === false) { $custom_anchor_link->url = $urls[$custom_anchor_link->menu_item_parent] . $custom_anchor_link->url; } else { // multiple nested menu items with anchors $custom_anchor_link->url = explode('#', $urls[$custom_anchor_link->menu_item_parent])[0] . $custom_anchor_link->url; } } return $items; } add_filter('wp_nav_menu_objects', 'lb_menu_anchors', 10, 2);
This allowed me to create custom link menu items with easily readable anchor links, that could be nested, and would also dynamically update if the page URL ever changed. Another benefit to this method vs “hard coding” an anchor link menu item is that the URL continues to work in a Domain Mapped environment, and across dev, staging, and production environments as well.
Leave a Reply