Extending WordPress custom menus

Extending WordPress custom menus

Created:29 May 2017 13:23:02 , in  Web development

Suppose you have built a custom menu using WordPress GUI for your website. The menu contains a subset of links to posts and pages that your website has to offer. For example, it might not, and in fact it shouldn't, contain a link to a confirmation page, user gets redirected to after sending email from the website. Nonetheless, once user is on that "email sent" page you want an item in the menu that reflects the new location.

This sort of behavior is difficult to achieve in WordPress now unless perhaps another menu is loaded conditionally.

At times, similar problem emerges with custom menus for single posts. Suppose, each such post contains description of one of thousands of products. Building custom menus for all these products and then loading them conditionally is out of question here. An acceptable solution might be an extra menu item containing a common label or post title for the post currently being displayed.

Again, this sort of functionality is not feasible with the graphical custom menus interface WordPress provides now.

sWWWCustomMenuExtension class

For exactly the sort of problems describe above I wrote sWWWCustomMenuExtension class.

It makes adding an extra custom menu top level item for a page or single post simple, quick and configurable.

Technically, the class relies on two filters, wp_nav_menu_objects and wp_nav_menu_items. They enable modifying output of wp_nav_menu WordPress function.

sWWWCustomMenuExtension depends on my ArrayInsert class. The dependency faciliates inserting new items in a chosen place of custom menu. (A detailed article on ArrayInsert is available under this link.

Here is the sWWWCustomMenuExtension class listing:

Class: sWWWCustomMenuExtension
Description: add extra custom menu top level item for a single post or page  
Author: Sylwester Wojnowski
WWW: wojnowski.net.pl

  [$a_text] - String - label for the new item in the menu, if empty, post/page title will be used
  [$current] - Bool - specifies whether the newly inserted item should be highlighted or not. 
  [$page_id] - Integer|Bool - page id to modify custom menu for (for pages only). 
    menu modification will be visible only on that page. 
    Set it to false for single post.
  [$position] - String|Integer - Position to insert new item in the list of custom menu items.
    Accepted values are :
      prepend - new item will be displayed first
      append - new item will be displayed last
      int - items array index to insert new item at (e.g. 0, 5). 

class sWWWCustomMenuExtension{
  public static function forSingle($a_text = '',$current = true,$page_id = 0,$position='append'){
    add_filter( 'wp_nav_menu_objects', function($items,$args) use ($a_text,$current,$page_id,$position){

    # current single post / page is being targeted
      if(!is_page($page_id)){ return $items; } 
      if(!is_single()){ return $items; } 
    $post = get_post();

    if(is_null($post)){ return $items; }

    $post -> title = empty($a_text) ? get_the_title() : $a_text; 
    $post -> classes = array (
    # highlight the extra item
      $post -> classes[] = 'current-menu-item';
      add_filter('wp_nav_menu_items',function($items,$args) use ($a_text){
        $a_text = esc_attr($a_text);
        $items = str_replace('<a>'.$a_text.'</a>','<span>'.$a_text.'</span>',$items);
        return $items;
    # for cases when extra menu item must stay a link (receives no highlight)    
        # for cases when the new menu item has included
        $post -> url = get_the_permalink($page_id);
    # re-index $items
    $items = array_values($items);
      case 'prepend':
        $items = ArrayInsert::itemAt($items,0,$post);
      case (int)$position > 0  && (int)$position < count($items):
        $items = ArrayInsert::itemAt($items,(int)$position,$post);
        # by default new menu item is appended   
        $items[] = $post;       
      return $items;

A note on Installation

As mentioned briefly earlier in this article, sWWWCustomMenuExtension uses ArrayInsert internally. This means both classes have to be fully loaded before they can be used. PHP provides spl_autoload_register function for this sort of purposes. Here is a very basic example how the function can be used for loading any PHP class from includes directory in the active WordPress theme.

  include get_template_directory().'/includes/'.$class.'.php';

The piece of code should go in functions.php file.

Use examples

Here are some use examples of sWWWCustomMenuExtension

In order to add label "Record" as the last item to custom menu for single post:


This can be put in a conditional tag: e.g. is_category(), is_tag() etc. if more fine-grained control of which posts will be affected is required.

To add highlighted label 'Confirmation' as the last item of a custom menu visible only on page with id 12:


To add highlighted label with page title as the last item of a custom menu for page with id 12:


To insert link with text "Help" as the second top item of custom menu for page with id 23:


Final remarks

Similar functionality to described in this article can be achieved using JavaScript, AJAX and PHP. I went for PHP-only solution mostly to avoid loading extra files.

Often WordPress installations, especially those relying on plugins heavily, are overburdened with JavaScript even before secondary pieces of functionality like the one presented here are added.

At the moment sWWWCustomMenuExtension does not allow for inserting items in sub-menus. Hence, the class might not be a complete solution for you. Still it shows how to extend / modify a custom menu. If you need more insight on the subject I would advise taking a closer look at wp_nav_menu WordPress function.

This post was updated on 29 May 2017 15:35:35

Tags:  php ,  wordpress 

Author, Copyright and citation


Sylwester Wojnowski

Author of the above article, Sylwester Wojnowski, is sWWW admin and owner.He enjoys doing Maths and studying algorithms, writing code in scripting and command languages, Thrash Metal music and playing electric guitar.


©Copyright, 2017 Sylwester Wojnowski. This article may not be reproduced or published as a whole or in parts without permission from the author. If you share it, please give author credit and do not remove embedded links.

Computer code, if present in the article, is excluded from the above and licensed under GPLv3.


Cite this article as:

Wojnowski, Sylwester. "Extending WordPress custom menus." From sWWW - Code For The Web . https://wojnowski.net.pl//main/index/extending-wordpress-custom-menus