Wordpress Style Modules: Analysis
Before we implemented "wordpress style" modules in Maintain, we analyzed how they handle modules over there.
Actual Maintain implementation
Module API
In modules/module.php, the Maintain module API is implemented. Like before, the actual modules remain subclasses of the class module.
Every module action should be implemented using this API. Exception: Authentication and Search, which are implemented through overriding the respective methods.
However, there are new, static methods:
static final methods (not to be overridden or inherited)
add_action(hook, function, priority, access)
Connects a module's function to a named module hook (for valid hooks see Maintain Module Hooks). This method is to me called by the register_hooks() method of every module. Arguments:
- hook, String, name of the hook
- function, mixed. Either String: name of this module's method to be connected to the hook, or array(String module name, String method name). In case only the function name is provided, the module name will automatically be determined.
- priority, int. Optional. Between 1 and 20, while 1 is the highest and 20 the lowest lowest. If none is given, 10 is assumed. The priority values may only be exceeded by core modules.
- access, int. Optional. Between 0 and 100. Default of 5 (GUEST). Any user with access level less than the access level trying to access the module will not be able to. (The module is skipped entirely).
add_filter(hook, function, priority, access)
Same as add_action, only that a filter hook gets some input data, should process it, and return the modified input data. For the documentation on the module hooks (input data etc.), see Maintain Module Hooks.
do_action(hook, optional arguments...)
This is called throughout the maintain code, (even inside module code), when all the functions connected to a specific action hook are to be called. They will be executed according to their priority, descending from 1 to 20. When two methods have the same priority, they are executed in the order they were added to the action list.
The optional arguments might be user or object IDs, etc., according to the module hook documentation.
Actions ususally do not return values. The respective modules are called for their effect rather than their return value. However, to allow cases in which the return value of an action is in fact important, do_action returns an array, containing the return values of all of the module methods that were called.
Example:
do_action('whatever');
returns an array like:
array( array of ('module' => module name,
'method' => method name,
'result' => return value of the method )
)
apply_filter(hook, filter_string, optional arguments)
Same as do_action, only that filter_argument is supposed to be processed and afterwards returned by the method. Therefore, even if the module happens not to change the input value at all, the method still has to return its original value. The optional arguments can yet again be object IDs etc, according to the hook documentation.
Apply_filter hits the modules sequentially according to their priorities, passing on the (modified) input variable (which is a string or an object reference or whatever). Each module gets the string, the way it was returned by its predecessor.
Example:
caller: 'String' -> (mod1) -> 'S.t.r.i.n.g' -> (mod2) -> 'g.n.i.r.t.S' -> (mod3) -> 'r.t.S' ---> return to caller.
do_single_action(module, hook, optional arguments)
This function works exactly the same as do_action, the only difference is: do_single_action executes the given module hook only on one single module.
Example:
do_single_action('mymodule', 'whatever');
executes the 'whatever' action on the module named 'mymodule' and no other module, even if they are registered for that hook, too.
In case the named module is not registered to this hook or the module does not exist, do_single_action returns false. Otherwise, it returns whatever return value it gets from the module.
Note: This function triggers one and only one action. So, do not register the same module to the same hook more than once on a hook that will be triggered by one of the "single" functions. (You can only do that with regular hooks.) If you do so anyway, you have been warned: Only the first function it finds will be executed. And that might not be what you expect.
apply_single_filter(module, hook, filter_string, optional arguments)
Same as do_single_action, but for a single filter hook. If the chosen module is registered to the given hook, the filter method is applied to the filter_string object.
Note: If the module does not exist, or it is not registered to this hook, apply_single_filter will return with an unchanged filter_string. This way, the filter is not broken if there respective module does not exist.
Second note: As mentioned for do_single_action above, this function will trigger one and only one method registered to the hook. Do not register a module several times to a hook that will be called by one of the "single" functions. You can only do that with regular hooks.
Cron Modules (As of Maintain 3.1)
add_cron($hook, $method, $start, $minutes)
As of Maintain 3.1, you can add modules to be run as part of the cron process. The module can be either run as a backend or a non-backend process by either hooking into cron_mod or backend, respectively. The module will start on the unix timestamp provided in $start, and will execute in a given interval. For example, if you set $start to 1165618800 and $minutes to 15 your module will run on 12/8/2006 at 17:00, 17:15, 17:30, ... , MM/DD/YYYY at n:(mm%15). So, if you wanted to write a module that runs foo() for the first time at 12/8/2006 at 17:00 and runs every 15 minutes thereafter as a non-backend process, you would put the following code in your register_hooks() method:
add_cron('cron_mod', 'foo', 1165618800, 15);
Or as a backend process:
add_cron('backend', 'foo', 1165618800, 15);
do_cron($hook, $force = false)
This functions almost exactly the same as do_action; however it checks the interval of the module, and if it's not at the start time yet or it is not currently in the appropriate interval, the module will not run. Adding a do_cron hook arbitrarily in the code will not run with the cron process. The hook will run when the script is run, just as any other hook. However, you can put cron.php in your crontab, which has the two default hooks (backend and cron_mod). The $force is a boolean flag which will make the hook behave just as do_action, disregarding any of the checks for start time and interval. For example, in cron.php the hook is created by the following code:
if(!$mode['backend_only']) {
Module::do_cron('cron_mod', $mode['force_run']);
}
if(!$mode['no_backend'])
Module::do_cron('backend', $mode['force_run'], $mode);
static abstract methods (to be overridden by the subclasses)
register_hooks()
Is automatically called by the module handler to register the module with the hooks it should reply to. Every module is supposed to override this method. Inside the method, there should be a bunch of add_action(...) and add_filter(...) statements, stating which hooks the module is connected to.
Example:
add_action("push_dhcp", "config_server_copy");
add_action("build_dhcp", array("my_module_name", "build_config_file"), 15);
add_filter("username", "get_full_name");
Module hooks
see Maintain Module Hooks