Creating MODX Manager Menu Items in Code

This article is about adding items to the MODX Manager’s Top Menu in PHP. A MODX menu item is kind of an odd thing. The modMenu object doesn’t have an id field (its primary key is the text field), and it doesn’t have a namespace even though it’s almost always associated with one.

It’s relatively easy to create a menu item in the Manager, where many of the details are handled for you, and you can then export it as part of a transport-package build system with the MyComponent extra. At some point, though, you might need to create a menu item in PHP code.

You might, for example, have an extra that asks the user during installation if they want a menu item and installs one if they say yes, or you might want to do it in a utility snippet as a quick way of adding menu items to new sites without the trouble of creating a transport package.

In that case, you’ll have to handle the details yourself. This article explains how to do it and provides a little information about how menu items are structured and handled by MODX. Note that the process will change in MODX 2.3 and probably change again in MODX 3.0. I’ll try to remember to update this article when that happens.

Menu structure

Most menu items that do anything have an attached action (there’s an exception to this that we’ll discuss later). The action is actually a modAction object and is completely independent from the menu item. A menu item can only have one action, but an action can be triggered by more than one menu item. Some menu items don’t do anything. The main items on the MODX Top Menu, for example, are “dead” items — nothing happens when you click on them. Their action field contains a 0, which tells MODX not to respond to clicks. It’s a little-known fact that they *can* have actions and respond to clicks. There’s an example in this article showing how to do that.

modMenu Object

Here are the fields of the modMenu object:

  • text (string) — text or lexicon key for the menu item
  • parent (string) — the ‘text’ field of the menu’s parent or ”
  • action (integer) — the ID of the action object for the item
  • description (string) — description shown under the menu item
  • icon (string) — option icon image file for the menu
  • menuindex (integer) — number to position the menu
  • params (string) — parameters to be sent to the action (usually empty)
  • handler (string) — a javascript function to execute on click (usually empty)
  • permissions (string) — permissions necessary to see the menu item

If you don’t need to internationalize your menu item, you can just fill the text field with the text you want to appear in the menu item. An exception to this would be if you are duplicating an existing MODX menu item, since the text field must be unique. In that case the text field can contain a lexicon key and you can put the actual text in a lexicon file. No two menu items can have the same text, but it’s perfectly fine for two different lexicon keys to have the same value. The description field can also contain a lexicon key.

The permissions field can be blank if you want everyone to be able to see the menu item. If you need to hide it from some users, see this article.

The handler field is usually empty for custom menu items. If it contains a JS function, you need to load the JS code in a plugin so it will be available (unless it’s built-in in MODX). If the handler field is not empty, the action field will be ignored. The JS function should always return false. For example, here is the code for the Site | Clear Cache menu item :

MODx.clearCache(); return false;

When MODX sees that, it ignores the menu item’s action field and just executes the JS function call.

When there is no handler, clicking on the menu item launches the action associated with the menu item. With custom menu items, this is almost always an index.php controller file located in the core path of the action’s namespace. Let’s take a closer look at the action object.

modAction Object

Here are the fields for the modAction object:

  • id (integer) — ID used above in the action field
  • namespace (string) — the namespace for the menu
  • controller (string) — name of the controller file, usually index for custom items
  • haslayout (integer) — true if the menu item does something
  • lang_topics (string) — any language topics to load
  • assets (string) — necessary assets, usually blank
  • help_url (string) — key of the help page for the item

Unless the action uses a built-in namespace like core, you’ll need to create a namespace object either in your code or in the Manager (System | Namespaces). The purpose of the namespace, in this case, is to provide a path to any files needed by the menu item. Every namespace has a specified core_path and assets_path, though the assets_path is often empty. The core_path tells MODX where to look for the controller file and any lexicon files used by the menu item (i.e., the file with the lexicon keys and values for the text and description fields).

How it Works

When the menu is rendered, MODX gets the lexicon values (if any) for the text and description fields.

When you click on a menu item that has an action other than 0 and has no JavaScript handler specified, MODX gets the action ID of the menu object from its action field. Then, it looks for an action with that ID. If it finds one, it gets the action’s namespace and grabs its core_path and controller fields. It then looks for and launches the controller file (typically core/components/namespace/index.php , which does a little initialization (usually loading a custom class file) and then performs its default action, sometimes through a connector. In many cases, the controller actually loads a local controller file that does the real work. In that case the controller file launched by the menu item is just a one-line file that “includes” the real controller.

Let’s look at a really simple example. Say that you have a CMP that just prints “Hello World” in the Manager’s right-hand panel. First, you’d create a namespace called helloworld with this core_path:

{core_path}components/helloworld/

The {core_path} part of that is just shorthand for the path to the MODX core directory. Next, you’d put an index.php file at core/components/helloworld/index.php. The file could be this simple:

return "Hello World!";

Once your action and menu are set up (either in the Manager, or using the code below), you’re done. You should be able to click on the menu item and see “Hello World!” in the right-hand panel.

When building a CMP, it’s not a bad idea to start out with the code above before extending it to do real work. I’ll discuss the details of more complex CMPs in another article. Since this one is about creating a menu item in code, let’s get to that.

Creating the Menu Item in Code

Here is the PHP code to create a menu for our “Hello World” CMP:


/* Get the namespace object or create it if necessary */
$namespace = $modx->getObject('modAction', array('namespace' => 'helloworld));
if (! namespace) {
    $namespace = $modx->newObject('modNamespace');
    $namespace->set('core_path','{core_path}components/helloworld/');
    $namespace->save();
}

/* Create the action */

$action = $modx->newObject('modAction');

$action->fromArray( array (
  'namespace' => 'helloworld',
  'controller' => 'index',
  'haslayout' => 1,
  'lang_topics' => 'helloworld:default',
  'assets' => '',
  'help_url' => '',
), '', true, true);

/* Create the menu item */

$menu = $modx->newObject('modMenu');
$menu->fromArray( array (
  'text' => 'Hello World',
  'parent' => 'components', /* put this on the components menu */
  'description' => '',
  'icon' => '',
  'menuindex' => 0, /* move it to the top */
  'params' => '',
  'handler' => '',
  'permissions' => '',
), '', true, true);

/* Connect the action to the menu item */
$menu->addOne($action);

/* Save both the menu and the action */
$menu->save();

/* refresh the action map so the action is
   available immediately */
$cm = $modx->getCacheManager();
$cm->refresh(array(
     'action_map' => array(),
));

If you run the code above, the menu item won’t show up on the Components menu until you reload the Manager page. If your index.php file is in the right place, your menu item should work immediately.

You might be wondering why we used lowercase for the parent field above when the parent menu item is “Components.” You can see why if you go to Manager | Actions and examine the “Components” menu item. Right-click on it in the right-hand panel and select “Update Menu”. You’ll see that the “Lexicon Key” field (which is actually the text field of the menu object) is set to “components”. But if that’s set to “components,” how come it shows in the menu as “Components”? The prompt in the form is the clue. What’s entered in this Manager form is actually a lexicon key. In the appropriate lexicon file for that menu item, you’ll find this code:

$_lang['components'] = 'Components';

If you are creating menu items that are nested under other items, remember that it’s the value of the parent menu’s text (Lexicon Key) field that you need to enter for the parent field’s value. Remember also that if you later add or change a lexicon key for a menu item, you’ll need to adjust the parent fields of any children.


For more information on how to use MODX to create a web site, see my web site Bob’s Guides, or better yet, buy my book: MODX: The Official Guide.

Looking for quality MODX Web Hosting? Look no further than Arvixe Web Hosting!

Tags: , , , , , , , , , , , , | Posted under MODX, MODX | RSS 2.0

Author Spotlight

Bob Ray

Bob Ray

I am the author of MODX: The Official Guide and over 30 MODX add-on components. I host Bob's Guides, a source of valuable information for MODX users, and I've been very active in the MODX Forums with over 14,000 posts.

Leave a Reply

Your email address will not be published. Required fields are marked *


+ 8 = 9

You may use these HTML tags and attributes: <a href="" title="" rel=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>