We launched new forums in March 2019—join us there. In a hurry for help with your website? Get Help Now!
    • 37286
    • 160 Posts
    I have a huge project that has multiple parts. I am trying to figure out the best way to build my menus. I know, put it in the components menu. That would be great, but the customer wants their own drop down menu and with the number of items on the menu I'm building, it is probably a good idea. So when I build the package and try to install it, my menu doesn't load the way that I had hoped. As far as I can tell the primary top menu was never even created. My ultimate goal is to have the menu I create fall between the site menu and components menu.

    I've modified my transport file:
    $modx->log(modX::LOG_LEVEL_INFO,'Packaging in menu...');
    $menus = include $sources['data'].'transport.menu.php';
    if (empty($menus)) $modx->log(modX::LOG_LEVEL_ERROR,'Could not package in menu.');
    foreach ($menus as $menu) {
        $vehicle= $builder->createVehicle($menu,array (
            xPDOTransport::PRESERVE_KEYS => true,
            xPDOTransport::UPDATE_OBJECT => true,
            xPDOTransport::UNIQUE_KEY => 'text',
            xPDOTransport::RELATED_OBJECTS => true,
            xPDOTransport::RELATED_OBJECT_ATTRIBUTES => array (
                'Action' => array (
                    xPDOTransport::PRESERVE_KEYS => false,
                    xPDOTransport::UPDATE_OBJECT => true,
                    xPDOTransport::UNIQUE_KEY => array ('namespace','controller'),
                ),
            ),
        ));
    }


    My menu file looks like:
    // top level menu
    $action=$modx->newObject('modAction');
    $action->fromArray(array(
        'id' => 1,
        'namespace' => 'addon',
        'parent' => 0,
        'controller' => 'index',
        'haslayout' => true,
        'lang_topics' => 'addon:default',
        'assets' => '',
    ),'',true,true);
     
    $menu=$modx->newObject('modMenu');
    $menu->fromArray(array(
        'text' => 'addon',
        'parent' => 0,
        'description' => 'addon.desc',
        'icon' => 'images/icons/plugin.gif',
        'menuindex' => 0,
        'params' => '',
        'handler' => '',
    ),'',true,true);
    $menu->addOne($action);
    $menus[] = $menu;
    unset($action);
    unset($menu);
    
    // first menu item
    $action=$modx->newObject('modAction');
    $action->fromArray(array(
        'id' => 1,
        'namespace' => 'addon',
        'parent' => 0,
        'controller' => 'menu1',
        'haslayout' => true,
        'lang_topics' => 'addon:default',
        'assets' => '',
    ),'',true,true);
    
    $menu=$modx->newObject('modMenu');
    $menu->fromArray(array(
        'text' => 'addon.menu1.manager',
        'parent' => 'addon',
        'description' => 'addon.menu1.manager.desc',
        'icon' => 'images/icons/plugin.gif',
        'menuindex' => 0,
        'params' => '',
        'handler' => '',
    ),'',true,true);
    $menu->addOne($action);
    $menus[] = $menu;
    unset($action);
    unset($menu);
    
    // second menu item
    $action=$modx->newObject('modAction');
    $action->fromArray(array(
        'id' => 1,
        'namespace' => 'addon',
        'parent' => 0,
        'controller' => 'menu2',
        'haslayout' => true,
        'lang_topics' => 'addon:default',
        'assets' => '',
    ),'',true,true);
    
    $menu=$modx->newObject('modMenu');
    $menu->fromArray(array(
        'text' => 'addon.menu2.manager',
        'parent' => 'addon',
        'description' => 'addon.menu2.manager.desc',
        'icon' => 'images/icons/plugin.gif',
        'menuindex' => 0,
        'params' => '',
        'handler' => '',
    ),'',true,true);
    $menu->addOne($action);
    $menus[] = $menu;
    unset($action);
    unset($menu);
    
    // etc...
    
    return $menus;


    So, before I spend any more hours on this that I don't have, can this even be done using the package builder, or does this have to be done by hand?
      • 28042 ☆ A M B ☆
      • 24,524 Posts
      I know it can be done, because I just installed something a few days ago that put itself in the main menu. If I can remember what it was, I'll let you know and you can check its files to see how it does it.
        Studying MODX in the desert - http://sottwell.com
        Tips and Tricks from the MODX Forums and Slack Channels - http://modxcookbook.com
        Join the Slack Community - http://modx.org
        • 37286
        • 160 Posts
        For anyone interested in the answer. It took some experimentation, but I was able to work it out. In my transport file, I have the below loop to add the menu items to the package.
        // load action/menu
        $modx->log(modX::LOG_LEVEL_INFO,'Packaging in menu...');
        $menus = include $sources['data'].'transport.menu.php';
        if (empty($menus)) $modx->log(modX::LOG_LEVEL_ERROR,'Could not package in menu.');
        foreach ($menus as $menu) {
            $vehicle = $builder->createVehicle($menu,array (
                xPDOTransport::PRESERVE_KEYS => true,
                xPDOTransport::UPDATE_OBJECT => true,
                xPDOTransport::UNIQUE_KEY => 'text',
                xPDOTransport::RELATED_OBJECTS => true,
                xPDOTransport::RELATED_OBJECT_ATTRIBUTES => array (
                    'Action' => array (
                        xPDOTransport::PRESERVE_KEYS => false,
                        xPDOTransport::UPDATE_OBJECT => true,
                        xPDOTransport::UNIQUE_KEY => array ('namespace','controller'),
                    ),
                ),
            ));
            $builder->putVehicle($vehicle);
        }
        unset($vehicle,$menus);


        In my menu file I define my menu items. The first item will go into the topmost menu bar between the Site and Components menu items. All the additional items added will display on the drop down below the first item.
        // primary addon menu
        $action=$modx->newObject('modAction');
        $action->fromArray(array(
            'id' => 1,
            'namespace' => 'addon',
            'parent' => 0,
            'controller' => 'index',
            'haslayout' => true,
            'lang_topics' => 'addon:default',
            'assets' => '',
        ),'',true,true);
        
        $menu=$modx->newObject('modMenu');
        $menu->fromArray(array(
            'text' => 'addon',
            'parent' => '', // set this to '' to place in top menu bar
            'description' => 'addon.desc',
            'icon' => 'images/icons/plugin.gif',
            'menuindex' => 1, // set to 1 to place between the site and components menu items
            'params' => '',
            'handler' => '',
        ),'',true,true);
        $menu->addOne($action);
        $menus[] = $menu; // add to array
        unset($action);
        unset($menu);
        
        
        // second menu item
        $action=$modx->newObject('modAction');
        $action->fromArray(array(
            'id' => 1,
            'namespace' => 'addon',
            'parent' => 0,
            'controller' => 'second_item',
            'haslayout' => true,
            'lang_topics' => 'addon:default',
            'assets' => '',
        ),'',true,true);
        
        $menu=$modx->newObject('modMenu');
        $menu->fromArray(array(
            'text' => 'addon.second_item.manager',
            'parent' => 'addon', // set to addon, the name of the first menu item I added
            'description' => 'addon.second_item.manager.desc',
            'icon' => 'images/icons/plugin.gif',
            'menuindex' => 0,
            'params' => '',
            'handler' => '',
        ),'',true,true);
        $menu->addOne($action);
        $menus[] = $menu; // add to array
        unset($action);
        unset($menu);
        // pass array to transport
        return $menus;

        What I found was that the "menuindex" field appears to start at 0 on the Dashboard menu and increases by 1 across the top. So putting 3 in this field places the new menu between Security and Tools. This is because the "menuindex" doesn't update the existing items with a new number, but appears to sort the new menu item after the existing menu item that has that same "menuindex" value.

        For example:
        Dashboard - 0
        Site - 1
        New Menu - 1
        Components - 2
        Tools - 3
        Another New Menu - 3
        Security - 4

        I don't know if this expected behavior, but in my experiments, that is what I am seeing.