The Priority Icons Plugin replaces priority text labels (Emergency, High, Normal, Low) in osTicket's Staff Panel with visual color-coded icons. The plugin works entirely client-side via DOM manipulation and requires no core file modifications.
Without this plugin: Priorities are displayed as plain text - in long ticket lists, agents must read each entry to identify urgent tickets.
With this plugin: Color-coded icons replace the text - emergency tickets pulse red, high-priority tickets glow orange. Priorities are recognizable at a glance.
prefers-reduced-motion supportHigh-volume support teams:
Teams with hundreds of open tickets can instantly identify emergency and high-priority tickets visually, without reading the text labels.
Multilingual helpdesks:
The plugin recognizes both English (Emergency, High, Normal, Low) and German (Notfall, Hoch, Normal, Niedrig) priority names - ideal for teams with mixed language configurations.
Accessible work environments:
Screen-reader text is preserved, aria-label attributes inform assistive technologies. Animations are automatically disabled when prefers-reduced-motion is set.
Teams with color-coding standards:
Admin-configurable colors allow adaptation to corporate color schemes - for example when red for critical tickets is defined in a specific shade.
Multi-monitor / Dashboard setups:
On large screens or dashboard monitors, colored icons are significantly faster to recognize than text labels.
| Component | Version | Note |
|---|---|---|
| osTicket | 1.18.x | Tested with 1.18.x |
| PHP | 8.1+ | Strict types, union types |
| jQuery | Any | Included in osTicket (for PJAX support) |
| Browser | Modern | ES6+, CSS Custom Properties required |
priority-icons folder to /include/plugins/ on your osTicket serverFinal path: /path/to/osticket/include/plugins/priority-icons/
cd /path/to/osticket/include/plugins
git clone https://github.com/markus-michalski/osticket-priority-icons.git priority-icons
The plugin automatically creates a singleton instance and starts working immediately.
Tip: No further configuration is needed after activation - the plugin works immediately with default color values.
| Setting | Description | Default |
|---|---|---|
| Enable Priority Icons | Globally enable/disable the plugin | On |
| Show Tooltips | Display priority name on hover | On |
| Icon Style | Visual style: Filled Circle, Badge, Dot | Filled Circle |
| Emergency Color | Hex color for emergency priority | #dc3545 (Red) |
| High Color | Hex color for high priority | #fd7e14 (Orange) |
| Normal Color | Hex color for normal priority | #ffc107 (Yellow) |
| Low Color | Hex color for low priority | #28a745 (Green) |
The color scheme is Bootstrap-inspired and follows a traffic light principle:
| Priority | Color | Hex | Behavior |
|---|---|---|---|
| Emergency | Red | #dc3545 |
Pulsing glow animation |
| High | Orange | #fd7e14 |
Static circle |
| Normal | Yellow | #ffc107 |
Static circle |
| Low | Green | #28a745 |
Static circle |
Icon rendering can also be overridden via CSS, without changing plugin configuration:
:root {
--priority-icon-size: 16px; /* Default: 12px */
--priority-icon-spacing: 0.375rem;
--priority-tooltip-bg: #212529;
--priority-tooltip-color: #fff;
--priority-transition-duration: 150ms;
}
After page load, the plugin scans these specific areas for priority text labels:
table.list.queue.tickets).ticket_info, .ticket-info)#ticket-status).pjax-container)Matched text labels are replaced with color-coded icon elements. The original text is preserved as screen-reader accessible text.
| English | German |
|---|---|
| Emergency | Notfall |
| High | Hoch |
| Normal | Normal |
| Low | Niedrig |
Filled Circle (Default):
Badge:
Dot:
The plugin does not use osTicket Signals for asset injection (see Technical Details for the reasoning). Instead, it uses the output buffer callback approach.
| Mechanism | Method | Purpose |
|---|---|---|
ob_start() callback |
injectAssetsIntoOutput() |
Inject CSS + JS before </head> |
enable() override |
addInstance() |
Auto-create singleton instance |
bootstrap() override |
Start ob_start() |
Initialize asset injection |
Why no Signals? The osTicket signals
apps.scpandapps.adminonly fire on the Apps page, not on regular pages like the ticket list.$ost->addExtraHeader()also doesn't work becauseglobal $ostis stillNULLduringbootstrap().
Symptoms:
Check:
Plugin enabled?
Check page source:
data-plugin="priority-icons"<style> and <script> tags with this attributeCheck browser console:
// Verify config is loaded:
console.log(window.PriorityIconsConfig);
Check error log:
tail -f /path/to/osticket/include/ost-errors.log
Fix:
If data-plugin="priority-icons" doesn't appear in the source, the plugin instance isn't active. Disable and re-enable the plugin - the singleton instance is created automatically.
Symptoms:
data-plugin="priority-icons" in page sourceCheck:
Fix:
Disable and re-enable the plugin (automatically creates singleton instance).
Symptoms:
Check:
Verify plugin version (must be >= 1.0.2).
Fix:
Update to plugin version 1.0.2+ which includes the CSS fix for vertical centering in table cells.
Symptoms:
Check:
Fix:
Custom priority names require modifying the $priorityMap in class.PriorityIconsPlugin.php.
priority-icons/
+-- plugin.php # Plugin metadata (v1.0.3)
+-- class.PriorityIconsPlugin.php # Main plugin class
+-- config.php # Admin configuration
+-- composer.json # Dependencies and scripts
+-- phpunit.xml # PHPUnit configuration
+-- assets/
| +-- .htaccess # Security + caching
| +-- priority-icons.css # Icon styles + animations
| +-- priority-icons.js # DOM manipulation + PJAX
+-- tests/
| +-- bootstrap.php # Mock osTicket classes
| +-- Unit/
| +-- PriorityIconsPluginTest.php # 44 tests
| +-- PriorityIconsConfigTest.php # 53 tests
+-- docs/
+-- ARCHITECTURE.md # Technical architecture docs
+-- CODE_REVIEW.md # Professional code review (9.2/10)
The plugin uses output buffer injection (ob_start() callback) to inject inline CSS and JavaScript before </head>:
public function bootstrap(): void
{
if ($this->isAjaxRequest()) {
return;
}
ob_start([$this, 'injectAssetsIntoOutput']);
}
Why ob_start() instead of other methods?
| Method | Problem |
|---|---|
Signal..connect('apps.scp') |
Signal only fires in scp/apps/dispatcher.php (Apps tab), not on regular pages |
$ost->addExtraHeader() |
global $ost is NULL during bootstrap() because PluginManager..bootstrap() runs inside osTicket..start() |
| External CSS/JS files | include/.htaccess contains Deny from all, blocking HTTP access to plugin assets |
ob_start() callback |
Works reliably, proven pattern |
Injection order:
<style> with CSS<script> with PHP-to-JS configuration (window.PriorityIconsConfig)<script> with JavaScript logicDOM Traversal:
TreeWalker API for efficient DOM walkingPJAX Support:
pjax:end event handler via jQueryPerformance:
data-priority-icon (no double processing)defer attribute for non-blocking script loadXSS Protection:
JSON_HEX_TAG | JSON_HEX_APOS (prevents </script> injection)innerHTML)Double-Injection Protection:
data-plugin="priority-icons" in output before injectionAJAX Skip:
Asset Protection (.htaccess):
/assets/ blocked.sr-only elementaria-label: Each icon has aria-label="Priority: {name}"cursor: help: Indicates tooltip availabilityprefers-reduced-motion: Disables pulse animation and transitions97 tests (PHPUnit 11):
PriorityIconsPluginTest)PriorityIconsConfigTest)composer test # Run tests
composer analyse # PHPStan static analysis
Q: Does the plugin work in the Client Portal?
A: The plugin is designed for the Staff Panel. Priorities are typically not displayed in the Client Portal, so the plugin has no effect there.
Q: Can I use custom priority names?
A: Currently only the default priority names (Emergency, High, Normal, Low) and their German translations (Notfall, Hoch, Niedrig) are supported. Custom names require modifying the $priorityMap in class.PriorityIconsPlugin.php.
Q: What happens if I disable the plugin?
A: The original priority text labels are immediately displayed again. No data is modified - the plugin works entirely client-side.
Q: Is the plugin compatible with other osTicket plugins?
A: Yes. The plugin does not modify core files and uses its own namespace (data-plugin="priority-icons"). Conflicts are unlikely unless another plugin manipulates the same DOM elements.
Q: Why are assets loaded inline instead of as external files?
A: osTicket's include/.htaccess contains Deny from all, which blocks HTTP access to all files in the include/ directory. Inline injection bypasses this without modifying core files.
Q: Why does the plugin use ob_start() instead of Signal..connect()?
A: The osTicket signals apps.scp and apps.admin only fire on the Apps page - not on regular pages like the ticket list. $ost->addExtraHeader() also doesn't work because global $ost is still NULL during bootstrap(). ob_start() with a callback is the only reliable pattern.
Q: Does it work with NGINX?
A: Yes. Since all assets are injected inline, there are no external file requests that could be blocked by web server configurations.
Q: How do I change the icon size?
A: The icon size is controlled via CSS custom properties:
:root {
--priority-icon-size: 16px; /* Default: 12px */
}
This plugin is released under the GNU General Public License v2, compatible with osTicket core.
See LICENSE for details.
For questions or issues, please create an issue on GitHub:
Issue Tracker: https://github.com/markus-michalski/osticket-priority-icons/issues
When reporting issues, please include:
php -v)Developed by Markus Michalski
Contributions welcome!
See CHANGELOG.md for version history.