/** * Adds a new menu item * * Note that adding a menu item does not display it yet, allowing * for possible customization. * * @see display() * @see addSubMenu() * @param string $title The title to give the menu entry * @param string|array $callback The function to call when the menu's page nees to be rendered * @param array|bool $callback_args Optional additional arguments to pass to the callback (Optional, none by default) * @param bool $is_submenu Set to `true` if this is a submenu entry (`False` by default) * @return MenuEntry Reference to the menu entry * @throws \Exception if the specified menu is a submenu, without having added a main menu. * @api */ public function addMenu($title, $callback, $callback_args = false, $is_submenu = false) { $menu = new MenuEntry($this->id); $menu->title = $title; $menu->capability = $this->capability; $menu->_properties['callback'] = $callback; $menu->_properties['callback_args'] = $callback_args; // Convert callback to a "slug" - since 1.0.5 $menu->_properties['long_slug'] = $this->id . '-' . (is_array($callback) ? $callback[1] : (string) $callback); $menu->_properties['slug'] = Helpers::makeSlug($menu->_properties['long_slug']); // Ensure the slug is unique in our menu (up to 99). if (array_key_exists($menu->_properties['slug'], $this->menus)) { $count = 1; while (array_key_exists($menu->_properties['slug'] . $count, $this->menus) && $count < 100) { $count++; } $menu->_properties['slug'] .= $count; } if (!$is_submenu) { $this->parent = $menu->_properties['slug']; $menu->_properties['type'] = $this->type; } else { if (!empty($this->parent)) { $menu->_properties['parent_slug'] = $this->parent; $menu->_properties['type'] = MenuEntry::MT_SUBMENU; // Submenus are always of this type } else { throw new \Exception('Cannot add a submenu before adding a main menu entry.'); } } $this->menus[$menu->_properties['slug']] = $menu; return $menu; }
/** * Displays the menu entry on the WordPress Dashboard * * @return bool Returns `true` if successful, `false` otherwise. * @throws \Exception if the no title or callback function was specified */ public function display() { if (empty($this->title) || empty($this->_properties['callback'])) { throw new \Exception('No title or callback function specified for menu entry'); } $title = $this->title; $page_title = $this->page_title; $icon = $this->icon; $capability = $this->capability; $parent = $this->_properties['parent_slug']; $slug = $this->_properties['slug']; if (empty($slug)) { $_cb = $this->_properties['callback']; $slug = Helpers::makeSlug(is_array($_cb) ? $_cb[1] : (string) $_cb); // Since 1.0.5, slug is based on callback function name unset($_cb); } if (empty($page_title)) { $page_title = $title; } // Sanitize and add count to the title here (prior operations use a "clean" title) if ($this->count !== false) { $title = htmlspecialchars($title) . ' <span class="awaiting-mod"><span class="pending-count">' . $this->count . '</span></span>'; } else { $title = htmlspecialchars($title); } // We call our own callback first $callback = array($this, 'onMenuCallback'); switch ($this->_properties['type']) { case self::MT_CUSTOM: if (empty($capability)) { $capability = 'read'; } $this->hook = add_menu_page($page_title, $title, $capability, $slug, $callback, $icon); break; case self::MT_SUBMENU: if (empty($capability)) { $capability = 'read'; } if (!$this->_properties['use_subheaders']) { $this->hook = add_submenu_page($parent, $page_title, $title, $capability, $slug, $callback); } else { $this->hook = ''; } break; case self::MT_COMMENTS: if (empty($capability)) { $capability = 'moderate_comments'; } $this->hook = add_comments_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_DASHBOARD: if (empty($capability)) { $capability = 'read'; } $this->hook = add_dashboard_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_LINKS: if (empty($capability)) { $capability = 'manage_links'; } $this->hook = add_links_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_TOOLS: if (empty($capability)) { $capability = 'import'; } $this->hook = add_management_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_MEDIA: if (empty($capability)) { $capability = 'upload_files'; } $this->hook = add_media_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_SETTINGS: if (empty($capability)) { $capability = 'manage_options'; } $this->hook = add_options_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_PAGES: if (empty($capability)) { $capability = 'edit_pages'; } $this->hook = add_pages_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_PLUGINS: if (empty($capability)) { $capability = 'update_plugins'; } $this->hook = add_plugins_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_POSTS: if (empty($capability)) { $capability = 'edit_posts'; } $this->hook = add_posts_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_THEMES: if (empty($capability)) { $capability = 'edit_theme_options'; } $this->hook = add_theme_page($page_title, $title, $capability, $slug, $callback); break; case self::MT_USERS: if (empty($capability)) { $capability = 'edit_users'; } $this->hook = add_users_page($page_title, $title, $capability, $slug, $callback); break; default: $this->hook = false; break; } $this->displayed = $this->hook !== false; if ($this->displayed) { // Write back any changes for future reference $this->_properties['slug'] = $slug; $this->capability = $capability; $this->page_title = $page_title; } return $this->displayed; }