1

A continuation to this question:

Replacing WordPress menu functionality with a plugin

Since I really rarely work with WordPress (I've done a lot of work with phpBB, myBB, Concrete5, and custom PHP scripts - but my WordPress experience is limited to one or two simple sites) I feel that I might get an answer quicker here than spending 3 hours reading through the documentation.

I'm creating a plugin to replace the WordPress menu with my own. So far here is the code for this plugin (it's all in a single PHP file):

add_action('init', 'DEMenu::init');
class DEMenu {

    public static function init() {
        $DEMenu = new DEMenu();
        load_plugin_textdomain ('de-menu', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/');
        /* Load CSS with wp_enqueue_style() */

        // If in admin page, then load admin page stuff
        if (is_admin()) {
            add_action('admin_menu', 'DEMenu::admin');
        }   
        // If not on admin page ...
        else {
            // Load plugin core - doesn't require a hook
            $DEMenu->core();
        }

    }

    public static function admin() {
        add_options_page('DE Menu Options', 'DE Menu', 'manage_options', 'de-menu', 'DEMenu::options');
//      add_option('de_menu_maintenance', 'off');
    }

    public static function options() {
        if (!current_user_can('manage_options'))  {
            wp_die( __('You do not have sufficient permissions to access this page.') );
        }
        echo '<div class="wrap">';
        echo '<p>Here is where the form would go if I actually had options.</p>';
        echo '</div>';
    }

    public static function core() {

        /* Add support for various themes */
        add_filter('wp_nav_menu', 'DEMenu::display');

        /* If I need to add more actions/filters they will go here... I may enqueue CSS here, too */

    }

    public static function display() {
        print "Let's see if this displays. I'll add some text to ctrl+F for later";
    }

}

This is mostly the culmination of various bits of advice from the WordPress documentation, plugin development tutorials, and basic OOP practices.

Now I'm tasked with drawing the menu from the Dashboard > Appearance > Menus area. How can I access this menu object (as an array or other accessible data type) so that I can work with it?

And I do realize it seems silly to completely override the wp_nav_menu() output if I'm just going to be using the same menu, however I can think of no other way to accomplish what I want.

EDIT -

I have been reading through wp-includes/nav-menu-template.php to learn how wp_nav_menu() gets the list of menu items, as well as how it displays it. I have been trying to essentially emulate the method used by this function only with slight variations to add in the multi-column structure. Here is what I have so far:

public static function core() {

    /* Add support for varoius themes */
    add_filter('wp_nav_menu', 'DEMenu::display', 1);

    /* If I need to add more actions/filters they will go here... I may enqueue CSS here, too */

}

    public static function display( $args ) {
        /* The following is blatantly ripped from nav-menu-template.php */

            // *****************************************************************
            /* Excluded for ease of reading - this is an exact copy of nav-menu-template.php */
            // *****************************************************************

        // Here we can invoke our custom walker without editing the theme
        $args->walker = 'DEMenu_Walker';

            $items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );
            unset($sorted_menu_items);

            // *****************************************************************
            /* Excluded for ease of reading - this is an exact copy of nav-menu-template.php */
            // *****************************************************************

//          $nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args );
//  
//          if ( $args->echo )
//                  echo $nav_menu;
//          else
//                  return $nav_menu;

        // Rather than checking if we should echo the output, just return it.
        // This is a filter, so the output will be echo'd by the calling function
        return $nav_menu;
    }

Then later (outside of the DEMenu class):

class DEMenu_Walker Extends Walker_Nav_Menu {

    function __construct() {
        die("We made it to the constructor!");
    }

}

However I am getting the following error:

Warning: Attempt to assign property of non-object in /home/coupon/public_html/wp-content/plugins/DE-menu/index.php on line 146

This line number is referring to:

$args->walker = 'DEMenu_Walker';

Perhaps there is a far more reasonable solution that I have over-looked, however from what I can tell I need a custom walker class (along with private variables for keeping track of how many items have been displayed and how many items should be displayed per column) and this is the only way to use a custom walker class without editing the theme. However if I'm to use the solution that I'm currently working on then I need to understand why the $args variables is a non-object when wp_nav_menu() clearly has the following line of code near the very beginning of the function:

$args = (object) $args;

ANOTHER EDIT -

I solved the non-object problem. When wp_nav_menu() calls the filter it is calling it like so:

$nav_menu = apply_filters( 'wp_nav_menu', $nav_menu, $args );

I failed to realize that this meant it was passing two arguments. I modified the display function like so:

public static function display( $nav_menu, $args ){

And of course modified the add_filter() call like so:

add_filter( 'wp_nav_menu', 'DEMenu::display', 1, 2 );

Although now I'm getting all sorts of fun new errors.

Fatal error: Using $this when not in object context in /home/coupon/public_html/wp-includes/class-wp-walker.php on line 185

Mind you I have made absolutely no modifications to WordPress core, so I don't understand why there's an error in class-wp-walker.php... I also don't understand why this error is just now showing up. Any ideas?

FINAL EDIT -

With help from https://stackoverflow.com/questions/6862887/replacing-wordpress-core-functionality-with-a-plugin I have finally realized that I can use the wp_nav_menu_args filter to pass my own walker class without copying the entirety of the wp_nav_menu() function. I will be using this solution (solving this problem), although as mentioned above - I am having a new problem where my walker class is causing its parent class to throw a fatal error. I will make a new question for that since it's an issue with the Walker class and not with accessing menu items or passing a custom walker.


Task: I need each sub-menu (second level or lower) to be divided into 5 columns (either 5 separate <ul> elements or <div> elements wrapped around certain <li> elements).

1 Answer 1

0

First: Use, for options(), the Settings API (tutorial).

Second: Take a look at the core function and the available filters. Then take a look at the available filters:

$sorted_menu_items = apply_filters( 'wp_nav_menu_objects', $sorted_menu_items, $args );
$items = apply_filters( 'wp_nav_menu_items', $items, $args );
$items = apply_filters( "wp_nav_menu_{$menu->slug}_items", $items, $args );
4
  • For options I was going by WordPress's own documentation: codex.wordpress.org/Writing_a_Plugin Although I don't have any options yet. At the moment I'm making this a very simple plugin that will support one use case, then I'll expand it and add options as necessary. Although I have been reading through core.trac.wordpress.org/browser/tags/3.2.1/wp-includes/… to find the best method of accessing menu items. Since I want to edit the menu output and not the item list I think I may have to re-generate the item list (silly, I know)...
    – stevendesu
    Jul 28, 2011 at 22:19
  • Codex isn't up to date, that's why I linked Chips tutorial. For the $items, just inspect them step by step. Else use a custom walker.
    – kaiser
    Jul 28, 2011 at 22:22
  • Problem is (mentioned in the previous question) I wanted to make this plugin with the assumption that I had no power to edit the theme (since it will be used on multiple different themes and the client may likely change themes at some point in time). My solution so far was to copy/paste the code from nav-menu-template.php except for this line: $items .= walk_nav_menu_tree( $sorted_menu_items, $args->depth, $args );. I can change this line to implement my own walker. However this means wp_nav_menu() is essentially run twice, with the first output discarded. Kind of wasteful.
    – stevendesu
    Jul 28, 2011 at 22:35
  • 1
    I actually just realized (with the help of a response to stackoverflow.com/questions/6862887/…) that I can use wp_nav_menu_args to pass my own custom walker class. For the recommendation to look at available filters, I'm accepting this answer as it does answer the original question. Although I recently have a problem with my Walker class, I can make a new question for this...
    – stevendesu
    Jul 28, 2011 at 23:23

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.