One of the great things about computers is that you can make them do some of the tedious, repetitive, grunt work for you. Say for example, that you want to set a particular TV value for new Resources created in a particular folder, but only if certain other conditions are true. If it weren’t for the other conditions, you could use Form Customization, but once you introduce anything beyond checking Resource field values, Form Customization won’t do it for you. You need a Plugin.
Similarly, you might want to do something special with a user when the user is saved. Maybe you want to add users to a User Group based on their zip codes or phone area codes. Maybe you want to create a user group and Resource group for each user, so they can have Resources that they alone can access. Again, you need a Plugin.
In both cases, you could perform the task by hand every time a new Resource or user is created, but let’s face it—you have better things to do with your time.
Plugins to the Rescue
People are often afraid of Plugins because they don’t understand them. They are a bit mysterious, operating in the background as MODX goes about its business, but it’s a shame to give up the power of Plugins just because they aren’t as obvious as Snippet.
A MODX Snippet is just a bit of PHP code that is executed when MODX encounters a Snippet tag. The return value of the Snippet replaces the tag.
Plugins, in contrast, don’t involve tags at all and often don’t have return values, but like a Snippet, a Plugin is just a bit of PHP code that is executed at a given time. In the case of Plugins, that time is when a System Event they are tied to “fires”.
System Events
As MODX performs its usual tasks, it periodically fires what are called System Events (in many other systems, these are called “hooks”). A System Event is just MODX’s way of periodically asking, ”Does anyone have anything they want done at this point?“
System Events are fired at strategic points where a developer might want to take some action. For example, when a Resource or user is saved or deleted, the code that does the work invokes a particular System Event. There are many System Events, some of which are fired in more than one situation. There’s a list of System Events and the variables available for each one here.
How It Works
System Events are “fired” in PHP code. This particular example lives in the processor that saves Resources:
$modx->invokeEvent('OnDocFormSave', array(
'mode' => modSystemEvent::MODE_NEW,
'id' => $this->object->get('id'),
'resource' => $this->object,
));
The code above is placed just after the code that saves the Resource to the database. When MODX encounters that code, it calls the invokeEvent()
method in the MODX class file. That method simply checks to see if any Plugins are connected to that event. If so, it executes their code (sending along the three variables in the array). If not, it does nothing. We’ll look at that in more detail in a bit, but first, let’s back up and see how the Plugins get attached to the events.
When you create or edit a Plugin, there’s a “System Events” tab with checkboxes for every possible System Event. When you check a box for a particular event and save the Plugin, MODX creates a record in the modx_site_plugin_events
table, recording the id
of the Plugin and the name of the event. That’s your way of telling MODX, “when this event fires, run this Plugin’s code”.
Looking at things from the other side, when the invokeEvent()
method is called (say, when a Resource is saved in the Manager), the invokeEvent()
method gets the name of the event as its first argument, and the array of variables (like the ones in the code above) as its second argument. MODX looks at the modx_site_plugin_events
table to see if there are any records for the named event. If not, it does nothing. If there are registered Plugins, however, it runs them, and the variables in the second argument are sent along for the ride.
On that same tab where you set the event(s) your Plugin is attached to, you can also select a property set to be used with the Plugin (it has to go here, because there is no Plugin tag in which to specify a property set). There is also a place to set the Plugin’s “Priority”. During the invokeEvent()
action, if MODX finds more than one Plugin attached to the current event, it executes them in order of their priority, starting with 0. Most of the time, the order of execution doesn’t matter, but occasionally, the order in which the Plugins execute could make a difference.
The Variables
In the example above, the $mode
, $id
, and $resource
variables will be available in the Plugin.
The $mode
variable just indicates whether the object is new or not. Its value is a constant (the actual values are 'new' and 'upd') and will always be either modSystemEvent::MODE_NEW
or modSystemEvent::MODE_UPD
The $id
variable is the ID of the Resource being saved and the $resource
variable is the Resource object itself. Note that where you would use $modx->resource
in a Snippet, in a Plugin, you would often use just $resource
. The $modx->resource
variable is seldom set for an event that’s fired in the Manager, a fact that trips up a lot of beginning Plugin writers. It is often set, though, for events that fire in the front end, like OnWebPagePrerender
. You can always look here to see which variables (if any) are available for a given event.
Doing Stuff
Once you’ve determined that an event fires at the point where you want to perform some action, you simply attach a Plugin to the event, write the Plugin code, and leave the rest to MODX.
For example, say you want to do something when a new Resource is saved (but leave existing Resources alone). The code, attached to OnDocFormSave
, would look something like this:
if ($mode !== modSystemEvent::MODE_NEW) {
return;
}
/* Your code here */
The first line checks to see whether the Resource is new, and if not, it simply returns without doing anything. The “Your code here” part is where you do whatever you want with the Resource.
In upcoming articles, we’ll look at some examples of things you might want to do at that point.
Multiple Events
Many Plugins are attached to a single event, but they can actually be attached to as many events as you like. In the ClassExtender Extra, for example, one of the Plugins is attached to both OnUserFormPrerender
and OnUserFormSave
. During the former event, it adds fields to the Create/Edit User form. During the latter, it saves the content of those fields to the database. This could have been done with two separate Plugins, but having the code together is convenient and adds less clutter to the Elements tree.
When a Plugin is attached to more than one event, it needs to detect which event has fired in order to know what bit of code to run. This is easy to do because the name of the event is always available in the Plugin as $modx->event->name
. You could use the PHP if
statement to identify the current event, but usually it’s done like this:
switch($modx->event->name) {
case 'OnDocFormPrerender':
/* some code here */
break;
case 'OnDocFormSave':
/* some different code here */
break;
}
If there is code that you want to execute in both cases, (e.g., code that returns if it’s not a new Resource), just put it outside the switch statement.
$modx->event->name
in Plugins that are attached to only one event. This is unnecessary, since the value of $modx->event->name
will always be the name of the event the Plugin is attached to. If it’s the only event attached to the Plugin, there’s no need to check its name.
Last Words
Plugins can be a great way to automate repetitive tasks in MODX. One catch that you should be aware of, however, is that when a PHP error occurs in a Plugin, things often just hang. Worse yet, you usually can’t use print
or echo
to display debugging information from a Plugin. That’s why it’s essential to have a good code editor that highlights PHP errors as you write your code. Another valuable Plugin tip is (if possible) to write your Plugin as a Snippet first, since Snippets are much easier to debug. Always remember to convert the variables when you move the code into a Plugin (for example, changing $modx->resource
to $resource
).
Bob Ray is the author of the MODX: The Official Guide and dozens of MODX Extras including QuickEmail, NewsPublisher, SiteCheck, GoRevo, Personalize, EZfaq, MyComponent and many more. His website is Bob’s Guides. It not only includes a plethora of MODX tutorials but there are some really great bread recipes there, as well.