Easy MODX Custom Manager Pages (CMPs) I

An easier way to create Custom Manager Pages (CMPs) in MODX


In this series of articles, we'll look at an easier way to create a Custom Manager Page (CMP). In this article, we'll get a start on creating a minimal CMP, in the next one, we'll modify it so it actually does something.

MODX logo

Custom Manager Pages

A Custom Manager Page (CMP) is a page you add to the MODX Manager. Unlike a widget, which must be lodged in a dashboard, a CMP is a regular Manager page, like the Create/Edit Resource panel or the Manage Users grid. CMP's are launched the same way other Manager pages are — by clicking on a menu choice in the Manager's Top Menu.

One upon a time, CMPs were a lot of work to create. They involved creating menu items, creating actions that launched controllers, linking the menu items to the actions, and putting the whole thing together. Creating a transport package to share your CMP was even more difficult, since the IDs of the actions could only be found during the package installation. Menu items and actions had to be created separately and then linked in a resolver that ran at the end of the package installation process.

CMPs could contain HTML code, but allowed no MODX tags or placeholders to be used.

Much of that process has changed since the old days. We now have class-based controllers and processors. These new controllers and processors handle a lot of housekeeping tasks (like checking permissions and loading lexicon files). Actions are specified directly by name in Menu items, and the old modx_actions table is no longer used.

As of MODX 2.5.0, thanks to Romain Tripault (Melting Media), we now have a controller class that allows the use of MODX tags and placeholders.


Let's Build a CMP

In this series of articles, we'll build a working CMP. It's still a little more complicated than writing a snippet, but the tools available now make it seem like child's play compared to the old days.

Our use case is a simple search function to find resources that match a search word or phrase. Of course the Manager already has one of these, but it's a case that's easy to understand , and the CMP we create could easily be modified to perform any number of useful tasks. By the end of the following article, you should have a working Search CMP that provides links to edit matching resources.

To build our Search CMP (let's call it MySearch) we only need three things. A namespace, a controller file, and a menu item. Since we can now use placeholders, we'll add a Tpl chunk to hold the HTML content the controller will display (i.e., the search form). We could put that content in the controller itself, but since it's HTML, it will be easier to write and edit in a Tpl chunk.


Creating the Namespace

The function of the namespace is to hold the two base paths to the CMP's files. This will include a core path and an assets path. That way, when we specify the namespace for our menu item, MODX will know where to look for the CMP's files.

Go to System (gear icon) -> Namespaces. Click on the "Create New" button and enter the following values in the three fields exactly as written:

Name:         mysearch

Core Path:    {core_path}components/mysearch/

Assets Path:  {assets_path}components/mysearch/

MODX will replace the two parts in curly brackets with the actual core and assets paths. If you move or rename your core directory later, these paths will still work. Make sure that your paths end in a slash and that there's *no* slash after the closing curly brace.

Click on the "Save" button.


The two paths above specify the standard location, but the files can actually go anywhere. In my development environment, for example, all my extras are under the assets//mycomponents directory. So, for example, my Core Path for the mysearch namespace is {assets_path}mycomponents/mysearch/core/components/mysearch/



Creating the Menu Item

Now that we have a namespace, we can create our menu item. Go to System (gear icon) -> Menus. Click on the "Create Menu" button. Use the following values for the form fields:

Parent:      Top Navigation (or 0)
Lexicon Key: My Search
Action:      home
Namespace:   mysearch
Permission:  edit_document,edit_chunk,edit_plugin,edit_snippet,edit_template,edit_user

Leave the other fields blank. Click on the "Save" button. You should see the menu item in the menu tree. If not, reload the page. It should automatically go at the end of the Top Navigation section, but you can click and drag it to another location

If you reload the page (you might have to clear the cache), you should see your menu item in the Top Menu. If not, you probably don't have one of the permissions listed in the Permission field.

If you click on the menu item, you should get a message telling you that MODX couldn't find the controller file, and a similar message in the Error Log. Take a close look at it and make sure there are no doubled or missing slashes. If it's wrong, you can go to System -> Namespaces, right-click on the "mysearch" namespace, and update it.


Creating the Controller File

This file (home.class.php) goes in the following location:

core
    components
        mysearch
            controllers
                home.class.php

If you've moved or renamed the core, the first part of the path will be different, but since you used {core_path} in the namespace Core Path, MODX will know where to look for it, even if you move and/or rename the core in the future.

MODX is actually not all that fussy about where the file is. It has to go beneath the mysearch directory, but you can put it just under the mysearch directory, under mysearch/controllers/, or in mysearch/controllers/default. If you put it in the default directory, MODX may only find it if you are using the default theme for the manager. If you're using another theme, you'll need to put it under a directory named for that theme. If you put it where I've suggested above, it will always be found, but if you're using another Manager theme, it may not be styled according to that theme.

In case you're curious, the URL MODX uses to get to the controller is:

http://yoursite.com/manager/?a=home&namespace=mysearch

The a is the action. MODX uses the namespace core path to get to the component's directory, then looks under it for a file named after the action, home.class.php or the old-style controller, home.php. If you ever need to create a link to a controller, you can use the format of the URL above.


Here's the content for the home.class.php controller file:

<?php
/**
 * mysearch Home Controller
 */
class mysearchHomeManagerController extends modParsedManagerController {
    public function getPageTitle() {
        return 'My Search';
    }

    public function process() {
        $this->modx::sanitize($_POST);
        if (isset($_POST) && ! empty($_POST)) {
            /* For now, just show the $_POST array */
            $results = '<pre>' . print_r($_POST, true) . '</pre>';
            $this->modx->setPlaceholder('mysearch_results', $results );
        }
        /* Get the form */
        $output = '[[!$MySearchTpl]]';

        return $output;
    }
}

Unlike the location, MODX is very picky about the class name of the controller. Remember than when we created the My Search menu item, we put home in the Action field. The format for controller names is:

NamespaceActionManagerController

You have to replace the Namespace and Action parts of that path with the actual namespace and default action (in this case home).

If you create other controllers, you need to use that exact format for the class name. If you don't, MODX will give you a confusing error message saying that the controller file wasn't found. If the class name of the controller is wrong, MODX thinks it has loaded the wrong file and refuses to go any further. The class name should always be followed by extends modParsedManagerController, which is Romain Tripault's excellent controller class that handles MODX tags and placeholder. As you can see, we've set a placeholder and used a chunk tag in our controller.

We've set the placeholder mysearch_results. For now, all it puts there is what's in the the $_POST array, wrapped in pre tags to make it easier to read. I always do this when developing form handling code. It's tremendously helpful when writing the code to see exactly what the form puts in the $_POST array when the form is submitted. On launching the CMP, it will just show array(), because the $_POST array will be empty. After you fill out the form and submit it, it will show name field of each non-empty input, followed by its value.

We've set the $output variable to a chunk tag and returned it. It will be displayed as the content of the CMP. We could also have just done this:

return $modx->getChunk('MySearchTpl')

Using getChunk() would be a tiny bit faster, but I wanted to show that you can return tags to be included in the output (including snippet tags). I used the exclamation point to make the chunk tag uncached. I do this during development when the chunk is changing often. The exclamation point can be removed once everything is working to make the CMP page load faster.

If you click on the My Search menu option, you won't see much at this point, because we haven't created the Tpl chunk yet. That's next.


Creating the Tpl Chunk

Create a chunk called MySearchTpl with this content:

<div class="container">
    <h2  class="modx-page-header">[[+ph._pagetitle]]</h2>

    <div class="x-panel-body shadowbox">
        <div class="panel-desc">Search Resources</div>
        <div class="x-panel main-wrapper">


          <form action="#" id="mysearch_form" method="post">
            <fieldset id="mysearch_fieldset" style="padding: 50px;">

                <div>
                  <label for="search_term">Search For: </label>
                  <input required class="x-form-text x-form-field" size=100 type="text" id="search_term" name="search_term">
                </div>
                <br class="clear"/>

                <br class="clear">


                <div class="mysearch_submit">
                    <input style="padding:5px;" type="submit" id="mysearch_submit" name="mysearch_submit" value="Launch Search"/>
                </div>
                <div id="mysearch_results">
                    [[+mysearch_results]]
                </div>
            </fieldset>
          </form>
        </div>
        </div>
</div>

The pagetitle placeholder is set automatically by the controller class. The mysearch_results placeholder is set by our own code in the controller file. I've used some of the Manager's styling classes to make things match the Manager style. There are more places Manager style classes could be inserted, but it's not too bad as is.

At this point, you should be able to click on the My Search menu item and see the form. Filling in the Search Term input and submitting the form won't search yet, but you should see the $_POST fields set by the form.


Coming Up

In the following article, we'll get our CMP to do an actual search.




Looking for high-quality, MODX-friendly hosting? As of May 2016, Bob's Guides is hosted at A2 hosting. (More information in the box below.)



Comments (0)


Please login to comment.

  (Login)