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).
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: