It's possible to use a shortcode as a menu url but it's not trivial.
A member of the Advanced WordPress Facebook group asked whether it was possible to use a shortcode in a menu. The answer is No, well, Yes but…
Shortcodes are primarily used in the page or post content. They are easily used in a text or custom html widget by passing the widget content through the do_shortcode() function. Maybe this will work in the menu…
When you add a Custom Link with a url of [MENU_SHORTCODE] to the menu it automatically gets a http:// prefix. This will be our downfall. You can try to remove it but it keeps coming back!
Here is what the html source looks like for this custom link:
Let’s add code to expand the shortcode and pass the menu markup through the do_shortcode() function:
The wp_nav_menu() function has a number of filters but the ‘wp_nav_menu‘ is the last one run before the markup is returned.
You can see that the shortcode has worked as expected, converting [MENU_SHORTCODE] to https://www.example.com (that url does work!) but the http:// is still there.
Parsing html markup can be difficult. A change in the order of item attributes would break a search string or regular expression but would still be valid html (e.g. ‘class’ and ‘src’ attributes could appear in a different order and continue to work). If we can filter the menu items before they are converted to markup it will be easier.
If the menu uses the standard Walker class (most do) then you can use the ‘nav_menu_link_attributes‘ filter that is in the wp-includes/class-walker-nav-menu.php file. The filter function receives 4 parameters (menu item attributes, menu item object, menu args, menu item depth). I examined the incoming data with error_log() and var_export() and found that the menu item attributes structure contained the menu item URL. Searching for the shortcode in this is easy and the persistent ‘http://‘ can finally be removed.
You can use an existing shortcode that has an add_shortcode() handler or set the url value in the function below.
I did a quick experiment with a shortcode with additional values
[MENU_SHORTCODE num=”2″ office=”DUB”]
but the quotes were removed and the spaces removed:
I had hoped that the menu item URL could be simply passed through do_shortcode() instead of writing a custom parse function.
Since standard shortcode parameters don’t work you could encode the parameters into the shortcode e.g.
and then figure a good way to parse this e.g. /-num=(\d+)/ and /-office=(\w+)/ but I’m leaving that for another day.