Feature request
Summary
The manager's quick search (uberbar) currently searches a fixed set of object types (Resources, Elements, Users) with no extension mechanism. Extras that manage their own data types (e.g., Commerce products, MIGX items, custom tables) cannot integrate with the search bar. Adding a system event would allow plugins to register custom search providers.
Current behavior
The Search/Search processor (core/src/Revolution/Processors/Search/Search.php) has a well-designed generic method searchElements() that accepts a class, type identifier, and field names:
protected function searchElements($class, $type, $nameField, $descriptionField, $contentField)
However, this method is:
- Not extensible — the list of searched types is hardcoded in
process()
- Limited in output — the
_action URL is hardcoded as 'element/' . $type . '/update&id='
- No event — there is no system event like
OnManagerSearch that plugins could hook into
The frontend (modx.searchbar.js) already supports custom result types — it checks for label and icon fields before falling back to built-in mappings:
getLabel: function(values) {
if (values.label) { return values.label; }
return _('search_resulttype_' + values.type);
}
getClass: function(values) {
if (values.icon) { return values.icon; }
// ... switch/case fallback
}
So the frontend is ready for extension; the backend is not.
Suggested solution
Add an OnManagerSearch system event that fires during quick search processing. Plugins respond by providing search provider configurations — structured arrays describing what to query. The processor builds and executes queries using these configs, following the same pattern as the existing searchElements().
Provider configuration structure:
// Plugin attached to OnManagerSearch
$providers = &$modx->event->params['providers'];
$providers[] = [
'class' => 'MyExtra\Model\Product', // xPDO model class (required)
'type' => 'products', // Result group identifier (required)
'label' => 'Products', // Display label for group header
'icon' => 'shopping-cart', // FontAwesome icon name
'permission' => 'myextra_view', // Permission to check (optional)
'nameField' => 'name', // Primary search field (required)
'descriptionField' => 'sku', // Secondary search/display field
'contentField' => 'description', // Content field (respects quick_search_in_content)
'action' => 'myextra/product/update&id=', // URL pattern, ID is appended (required)
'joins' => [ // Optional xPDO joins
[
'class' => 'MyExtra\Model\Category',
'alias' => 'Category',
'on' => 'Product.category_id = Category.id',
'type' => 'left',
],
],
'searchFields' => [ // Additional fields to search (from joins)
'Category.name',
],
];
How the processor would handle it:
// In process(), after built-in searches:
$providers = [];
$this->modx->invokeEvent('OnManagerSearch', [
'query' => $this->query,
'providers' => &$providers,
'maxResults' => $this->getMaxResults(),
]);
foreach ($providers as $provider) {
if (!empty($provider['permission']) && !$this->modx->hasPermission($provider['permission'])) {
continue;
}
$this->searchProvider($provider);
}
The searchProvider() method would follow the same query-building logic as searchElements() — LIKE conditions on specified fields, sorting by exact match, respecting quick_search_result_max limit — but with support for joins, custom action URLs, and custom icons/labels.
Why this approach
- Reuses existing patterns —
searchElements() already does exactly this for built-in types; the new method generalizes it
- Declarative, not imperative — plugins describe what to search, the processor handles how. This ensures consistent query building, limit enforcement, and result formatting
- Frontend already supports it — no JS changes needed beyond an optional default icon for unknown types
- Safe — the processor controls query execution, so plugins can't inject arbitrary SQL or bypass limits
- Consistent UX — results from extras look and behave identically to built-in results
Additional considerations
- The
searchElements() _action is currently hardcoded as 'element/' . $type . '/update&id='. This should be parameterized regardless of the event, as it's a limitation even for potential future core search types
- Result validation should filter out malformed provider configs (missing required fields)
- Event groupname:
System (same as OnManagerPageInit and similar manager events)
- Event service:
2 (plugin event)
Feature request
Summary
The manager's quick search (uberbar) currently searches a fixed set of object types (Resources, Elements, Users) with no extension mechanism. Extras that manage their own data types (e.g., Commerce products, MIGX items, custom tables) cannot integrate with the search bar. Adding a system event would allow plugins to register custom search providers.
Current behavior
The
Search/Searchprocessor (core/src/Revolution/Processors/Search/Search.php) has a well-designed generic methodsearchElements()that accepts a class, type identifier, and field names:However, this method is:
process()_actionURL is hardcoded as'element/' . $type . '/update&id='OnManagerSearchthat plugins could hook intoThe frontend (
modx.searchbar.js) already supports custom result types — it checks forlabelandiconfields before falling back to built-in mappings:So the frontend is ready for extension; the backend is not.
Suggested solution
Add an
OnManagerSearchsystem event that fires during quick search processing. Plugins respond by providing search provider configurations — structured arrays describing what to query. The processor builds and executes queries using these configs, following the same pattern as the existingsearchElements().Provider configuration structure:
How the processor would handle it:
The
searchProvider()method would follow the same query-building logic assearchElements()— LIKE conditions on specified fields, sorting by exact match, respectingquick_search_result_maxlimit — but with support for joins, custom action URLs, and custom icons/labels.Why this approach
searchElements()already does exactly this for built-in types; the new method generalizes itAdditional considerations
searchElements()_actionis currently hardcoded as'element/' . $type . '/update&id='. This should be parameterized regardless of the event, as it's a limitation even for potential future core search typesSystem(same asOnManagerPageInitand similar manager events)2(plugin event)