From Cerb Wiki
(Redirected from 5.0.0)
Jump to: navigation, search

Cerb5 (5.0) is a Stable Release as of May 17th 2010 and it contains over 307 improvements from community feedback. There are 20 additional improvements in 1 maintenance update.

This page will highlight the most interesting changes. You can find the full changelog in the forums.

Release Notes


  • All licenses (free and paid) allow unlimited worker accounts to be configured.
  • Licensing is based on 'seats': the maximum number of workers able to sign on and work at the same time. This should allay most past concerns about pricing for environments with high-turnover workers (temps, interns, part-timers, volunteers) and maintaining history for deactivated accounts. A single seat can be shared by several infrequent workers (such as executives who take an occasional peek).
  • Seats are $100/each for Cerb5 licenses. They're a one-time cost for the duration of 5.x development.
  • New licenses receive one month of feature updates.
  • You are always entitled to fixes for a feature release (e.g. 5.0.x, 5.1.x, 5.2.x) if your license covered its initial release.
  • Additional updates are $15/seat/update, or 1 year of feature updates for $40/seat.
  • Cerb5 On-Demand is now $20/seat/month. This lowers the price most people have been paying (since the number of required seats is generally lower than the number of required workers), but it more accurately reflects that our costs to scale the service rise with concurrent workers (not a high amount of idle worker accounts).
  • "Free Mode" (with no license) is limited to a single seat but has no other restrictions (the tagline is gone; there is no worker or group limit; the CRM + Permissions functionality is unlocked).
  • We now issue free "Community" licenses for 3 seats if you complete the survey at the end of the Cerb5 installation. These licenses do not include any feature updates, but future updates are available for the same cost as paid licenses ($15/seat/one-time, $40/seat/year).

Upgrade Considerations

  • Upgrade instructions.
  • Application-provided plugins have moved to /features; and user-provided plugins have moved to /storage/plugins. This means the only place the application writes data is the /storage filesystem; and consequently that's now the only place you need to backup or replicate.
  • Make sure you update the index.php file for any deployed Support Center instances.
  • Our officially recommended PHP opcode cache is now the XCache extension rather than APC.
  • Our Subversion distribution repository for Cerb5 has moved to http://svn.webgroupmedia.com/cerb5/branches/stable. It is recommended that you replace your Cerb4 files entirely (and only preserve your DB_ settings from framework.config.php and your /storage directory content.
  • Optional plugins can be found at http://svn.webgroupmedia.com/cerb5/branches/stable/plugins/
  • Devblocks files are no longer located in an external repository using svn:external; they've been moved into the Cerb5 repository to simplify distribution and merging.

Highlights of 5.0

  • Friendly licensing: unlimited workers accounts; buy simultaneous worker "seats"; no features are locked.
  • Major performance improvements: from fast to faster; CSS sprites; smarter caching; faster queries; less memory.
  • Cutting-edge tools: Devblocks2; Smarty3; jQuery/UI; Nginx-friendly.
  • Lightweight: Goodbye ADODB, YUI, Zend Framework.
  • Mail drafts: auto-save; shared; visible in the conversation history.
  • Failure-proofing: failed mail is now automatically saved as a draft.
  • Support Center: completely customize every template for each community portal; custom fields on portals; display any custom fields for addresses or organizations on 'My Account'; share template designs.
  • Broadcast: send personalized replies to an entire worklist using all data and custom fields.
  • Snippets: reuse conversational fragments that know everything about your customers that you do; all custom fields; relationships between records.
  • Search: major improvements in search performance and relevancy.
  • Storage: archive/unarchive content to/from disk, database, and Amazon S3 based on activity.
  • Explorer: navigate the contents of any worklist; share search results via URL with your team.
  • Mail Queue: send large amounts of mail efficiently.
  • Knowledgebase: Markdown support; visual editor; permalinks; preview; custom fields.
  • Web-API (JSON/XML): completely rewritten; simplified for mobile development; worker-auth based; read/write custom fields for all major records; plugin-ready.
  • and much more...!


  • Devblocks2
  • Smarty3
  • YUI->jQuery/jQuery UI
  • ADODB->Devblocks2
  • Refactored out 'DEMO_MODE' since it wasn't being used and was implemented inconsistently.
  • Implemented 'DEVELOPMENT_MODE' to assist with development vs production use (compile_check Smarty3 templates, debug output, logger, non-combined + non-minified styles + scripts, etc).
  • Phased out Zend Framework as a Devblocks dependency. Devblocks2 now provides its own efficient implementation of caching, logging, and RSS/Atom/RDF feed parsing (DevblocksPlatform::parseRss). The ~2MB of files associated with Zend Framework has been deleted (which helps reduce download size, compile times, memory use, and wasted caches in APC+XCache).
  • Removed the dependency on ADODB and migrated all database interaction to Devblocks2. This reduces the number of open files, reduces memory, and improves compile times. We didn't need a multi-platofrm abstraction layer since our MySQL support is exclusive, and the wrappers around the native MySQL drivers had a performance hit.
  • Revamped the /update system. Patches are now run in dependency order per release; so an original Cerb 4.0RC1 install will patch core to 4.1 and update all plugins to 4.1, then patch to 4.1.1 and update all plugins, until current. Plugins can assume their dependencies have been loaded and updated to the same version before them. Failing patches on plugins will cause that plugin to be disabled but won't prevent an update from happening (since it can be assumed some plugins won't be current with new releases on release day).


  • YUI->jQuery Tabs
  • YUI Panel->jQuery Dialog
  • YUI Connect->jQuery Ajax
  • YUI Autocomplete->jQuery+Autocomplete
  • YUI.Chart->jQuery+Flot
  • YUI.Calendar->jQuery DatePicker
  • LiveValidation->jQuery+Validation
  • Removed YUI dependency
  • Refactored most genericAjaxPanel calls since jQuery now parses <script> blocks in Ajax content. We no longer have to handle this on the client in every link.
  • Switched from Devblocks implementation of 'toggleClass' to jQuery.
  • Switched from Devblocks implementation of 'clearDiv' to jQuery.
  • Switched from Devblocks implementation of 'radioValue' to jQuery.


  • Combined the jQuery scripts into a single minified include. Also combined cerberus.js and display.js to reduce the number of HTTP requests required with an empty cache.
  • Converted the most popular icons to CSS sprites to remove many needless concurrent HTTP requests. This should help the most w/ empty cache page views and in high traffic environments (including On-Demand).
  • Peak memory usage has been reduced by proper usage of mysql_free_result().
  • Split the major DAO/Model objects into their own files to reduce file size and memory usage (which is especially helpful in production environments that don't utilize opcachers like APC/XCache/etc).
  • Fixed an inefficiency where content was requested twice (once in the controller and once in the template) per message on the /display page.
  • Minor performance improvements (cached the ACL-filtered extension list of a worker for the duration of the request, which makes 90% fewer calls to DevblocksExtensionDelegate; removed strcasecmp() calls in the Extension Registry since extension points are case-sensitive).
  • DAO_Worker::logActivity() will only write once per 30 seconds per worker. This should reduce noisy and unnecessary SQL traffic.
  • The session system will only write session data to the DB if it changed (by comparing to the session read on open).
  • Session writes will always try to UPDATE and then INSERT on fail, rather than SELECT and making a decision. One fewer query per request.

Support Center

  • Each portal can now have its own custom version of all the templates used to display the Support Center. The biggest limitation of the Support Center before Cerb5 was that the templates were shared between all instances, and tweaking HTML fragments for header/footer/CSS didn't provide enough flexibility. In Cerb5, each portal can overload the templates and change them entirely. Anything not overloaded is shared from the disk as usual. Templates are grouped into 'sets' (such as 'Support Center' or 'System E-mail Templates'). Templates have browser-editing enabled through their plugin.xml manifest.
  • Community Portals are now managed using a worklist view, and configured using a display page with tabs. This makes it much easier to manage portals.
  • You can now add custom fields to community portals. Combined with the new portal worklist this allows you infinite flexibility on how you manage your portals. For example, you can add a custom field for 'region' (Americas/Europe/Asia/etc) to group your portals based on their intended market.
  • Any previous configuration information for header, footer, style, and 'home' content will be migrated into custom templates per portal automatically.
  • The concept of 'Communities' has been removed from portals. Any communities you had defined will be automatically migrated to a portal custom field. If you no longer find the community grouping useful you can simply delete the custom field and choose other grouping characteristics.
  • When defining custom templates for the Support Center portals, you can now customize the colors of the CAPTCHA image by adding 'color' and 'bgcolor' query arguments to the '/captcha' URL. The format of the values is 8-bit RGB where each color is provided as a number between 0 (0%) and 255 (100%); for example: /captcha?color=250,50,50&bgcolor=10,10,100
  • You can now import and export arbitrary sets of custom templates for community portals. This enables the community to design and share countless Support Center remixes. It also opens up a new market for community-sourced customization services.
  • Added a 'renderSidebar' method to Support Center page extensions. This provides a context-sensitive hook for rendering sidebar context appropriate for the current request. For example, when browsing the public knowledgebase the sidebar could show a 'search' box on every page. When displaying a knowledebase article, the sidebar could additionally display a list of related articles. This reduces the redundancy of needing to certain content (like a search box) on every page of content, which allows for a cleaner UI/UX.
  • When displaying Knowledebase pages in the Support Center, the sidebar will now always provide a 'search' box. This allows your users to search from every KB page, when previously certain pages (such as displaying an article) required navigating back before searching again.


  • The e-mail autocomplete functionality will now ignore 'banned' senders, and it will sort matches in 'num_nonspam' order; meaning the contacts you talk to the most will be returned as the most likely matches.
  • Added two new options to Quick Search: 'Messages (all words)' and 'Messages (phrase)'. These use the new full text search system for much better relevancy than in Cerb4.
  • Comments in the ticket conversation are now deleted with an Ajax request, and no longer force a page reload or the selection of the 'Comments' tab.
  • Due to the recent introduction of drafts functionality, replying to an unassigned ticket will no longer auto-assign it to you. The original intent of this functionality was to prevent workers from replying to the same ticket, but it only worked for unassigned tickets and it complicated behavior which watched assignments (like the assignment notification). The confusing 'Discard & Surrender' button has been removed from the reply form as well.
  • [CHD-896] The 'cc' and 'bcc' fields will now autocomplete e-mail addresses on the compose and reply forms. Previously only the 'to' field would autocomplete.
  • For aesthetic reasons, the brackets around the tags in the ticket conversation (e.g. inbound/outbound/comment/draft/sticky note) have been removed.
  • Outgoing replies in the ticket conversation will now show the name of the worker that sent them opposed to the helpdesk e-mail address (which is still shown as 'From:' in the message headers). This makes it much easier to read the conversation history without needing to scroll down to the signature of every message to see who sent it.
  • The conversation history on tickets now shows queued messages along with drafts.
  • The ticket 'peek' dialog will now automatically hyperlink URLs from the displayed e-mail message.
  • [CHD-219] Hide long blocks of quoted text with DHTML (similar to Gmail). (Jeff@WGM: This works for Display Ticket and 'peek').
  • Messages are no longer added to the ticket conversation history if they weren't sent via SMTP successfully; instead, a draft is generated (or preserved) and shown in the discussion. This prevents the issue where multiple unsuccessful attempts would each add a failed message (with an attached sticky note). This works for worker-initiated mail like compose/create/reply, as well as for automated mail like autoreplies and watcher emails; although worker-less mail is saved directly to the mail queue rather than as drafts.
  • Group auto-replies can now use all the snippet tokens from the 'ticket' context. A snippet tester has been provided for open and close auto-reply events. Existing auto-reply templates will be automatically migrated by the upgrade to Cerb5.
  • [CHD-1000] Fixed a parser issue where the content-type wasn't being checked properly in the envelope headers, but only for mimeparts. Mailparse populates a 'charset' global info property in all cases, and the previous 'content-charset' was only available if a mimepart *and* if explicitly defined. This fix should allow the parser to properly sanitize invalid UTF-8 in all cases.
  • The parser will now use the current time as the 'updated' property for all new tickets, while still retaining the 'created' date based on the headers.


  • [CHD-329] Implemented e-mail 'drafts' functionality. You can now save compose or reply messages as drafts instead of sending them, and resume them later. Drafts auto-save every 30 seconds on compose or while replying to a ticket. There is a new tab in 'Mail->Drafts' to show workers their pending drafts. On the reply form there is now a 'Continue Later' button that will save the message as a draft and return to the ticket conversation. Reply drafts are shown in the ticket conversation (along with replies, comments, and notes); and they can be resumed or discarded by their owners from the conversation. This means workers can see a reply-in-progress while it's being saved and before it's being sent (which is incredibly helpful for having someone else proofread or sign off on outgoing messages before you hit the 'send' button). Drafts dispose of themselves when they are successfully sent. The Display Ticket screen will show you an alert about the number of pending drafts on the current ticket, along with their ages (which helps determine if someone else is already responding to the current ticket).

Mail Queue

  • Implemented a mail queue service that can be used by all functionality to send large amounts of mail in an efficient manner. A 'mail queue' scheduled task has been added for this purpose. Queued mail can be given a priority (e.g. replies to customers will be moved to the top of the queue, rather than waiting for all 1,000 bulk messages to be sent). This enables a lot of new functionality to be developed that would have created inefficient server loads in the past. For example, 'bulk update' could now have a 'mass reply' feature that would send replies to any number of tickets from a worklist; and these replies could be queued for delivery rather than being sent in real-time (which returns control of the browser back to the worker almost immediately).


  • Implemented a new 'snippets' service which replaces e-mail templates. Unlike e-mail templates, snippets are not limited to a single piece of functionality (like replies vs. compose mail). Snippets are context-aware, meaning they can be used for more than just tickets (e.g. tasks, workers, opportunities, etc). Contexts can be joined together, so a ticket with a first+last sender links to an 'address' context for each of them. A 'task' context links to a 'worker' context for the assignee. This means that all your custom fields and properties are available as replacement tokens: ticket->sender->org->customfield; allowing for very flexible and informed snippets. A 'plaintext' context is also provided for snippets that may be used in any context (such as your business address). Snippets also support 'Twig' syntax, so you can do modifiers (e.g. date formatting) and conditional logic (e.g. if/then) or loops. You can check if you know the first name of an e-mail address and address them by name -or- use a generic greeting. The more information you store about people and organizations (CRM), the more personalized your interaction will be courtesy of snippets. Because of conditional logic, you also don't need to 'babysit' snippets, because they'll adapt to information you do or don't have; they are automation-friendly. Snippets also come with an Ajax-driven tester to make sure they're formatted properly and adapt in different situations. You can edit your mail-related snippets in the Mail->Snippets tab. Your existing mail templates will be automatically converted to snippets by the Cerb5 update.
  • New template syntax allows conditional logic (if/else) and loops (for) using the Twig template language (http://www.twig-project.org/). We went with Twig over Smarty for this functionality because it has an emphasis on being secure and providing sandboxes for templates; which means we can safely allow worker-provided and user-provided templates. With Smarty, too much information was available to the template scope.
  • You can now use all worker custom fields as tokens in signatures.
  • Signature templates can also access the literal value of custom fields with the 'worker_custom.*' variable namespace. For example {{worker_custom.10}} would return the variable of worker custom field #10 rather than a string. If this was a multiple-selection field, you could use template logic on the array like "{% if 'value' in worker_custom.10 %}".
  • Implemented 'cerberusweb.snippet.token' extensions for providing custom tokens on any template. A single token can bind itself to multiple template types (signatures, email, autoreply, etc); and the proper interface will be invoked to generate a token value based on the context + scope. For example, you may create a new template token called {{ad_rotator}} that will rotate between special offers to display in the signatures of your outgoing mail. You could also create a token to display an estimated wait time in autoreplies based on the Group workload of the incoming message (and/or the number of active workers, etc).


  • [CHD-224] Workers with the proper permissions can now 'Broadcast Reply' to a worklist of tickets from 'bulk update'. These replies can be created as drafts or queued for immediate delivery. This can be used for so many things: replying to a list of tickets about the same service outage, replying to a list of leads about the same promotion, etc. In the very near future this feature will also support e-mail templates to personalize each message to its recipient. By combining this functionality with 'bulk update', you can also set any associated custom fields or properties (such as closing the tickets, or marking them 'waiting for reply').
  • Sending a broadcast reply from 'bulk update' on ticket worklists can now use email templates to personalize the generated responses for each ticket in the list. You can also use conditional logic (e.g. if/elseif/else) and loops. For syntax, see: http://www.twig-project.org/book/02-Twig-for-Template-Designers
  • Added a template tester to the 'broadcast' action on ticket worklist 'bulk update'. Not only will the tester report any syntax errors in your template, but it will also pull a random sample from the current worklist every time you test to show you rendered output for various situations. Simply click the 'test' button until you're satisfied things are working as you expect and then send it.
  • Workers with the proper privileges can now broadcast compose using snippets from opportunity lists. Snippets can be used to send personalized messages to every lead (including the subject and body). The opportunity snippet context also provides links to the assigned worker and lead e-mail contexts (including custom fields on all objects). To broadcast, click 'bulk update' from any opportunity list. You can choose to create drafts or queue generated e-mail for delivery.
  • Added 'broadcast' compose functionality to the address book. This is available to all workers with the appropriate privileges. You can use all the snippet tokens related to the 'address' context, including custom fields for e-mail addresses and organizations. To send a broadcast from any list of e-mail addresses (e.g. the address book, worklists, search results). Broadcast can generate drafts or directly add email to the outgoing mail queue.

Search Service

  • Implemented DevblocksPlatform::getSearchService() to provide full text indexing for any data source or plugin. The implementation will create 'fulltext_*' tables in the local database for content which may be otherwise distributed. The content is preprocessed before indexing by stripping punctuation and removing common (uninteresting) words. Queries run against the index are also preprocessed by the same rules. This provides far more reliable searching when looking for information like phone numbers that may be entered in multiple formats.
  • Added a 'scope' parameter to OPER_FULLTEXT search criteria. You can now require 'all' words, 'any' words, provide a 'phrase', or 'expert' mode. These modes will automatically rewrite a query to use the appropriate MySQL FULLTEXT query syntax, instead of assuming all users will learn or understand the intricacies of search syntax.
  • Added improved support for fulltext searching 'message content' back to DAO_Ticket::search() and the 'Mail->Search' tab. This should be much more efficient than the Cerb4 implementation, but will require a complete reindex of searchable content (automatically handled by the scheduler).
  • Added a new 'Search Indexer' scheduled task to 'Setup->Scheduler'. This manages asynchronous search indexing of arbitrary content. Plugins can register with the search indexer to have their content crawled.
  • Added 'Search Schemas', which are implemented by plugins to inform the Search Indexer how to batch index their arbitrary content. Currently used by 'message content' and 'kb articles'.

Storage Service

  • Implemented 'DevblocksPlatform::getStorageService()', which provides an abstract platform service for managing long-term data storage. Initally, 'disk' and 'database' options are available, providing more flexibility (some like to store heavy content on the disk since incremental backups are easier with rsync; while others like to store heavy content in the database to simplify running a cluster setup). In the near future we'll be providing additional options, such as FTP and S3. This approach provides a way to keep the local database thinner, which minimizes table locks on backups and snapshots. There is little reason to keep large immutable objects in the database.
  • Implemented storage engines (for the storage service) as extensions. Devblocks provides three storage engine extensions by default: filesystem, database, and Amazon S3. Plugins can contribute additional storage engines (e.g. SFTP, other cloud storage services, MogileFS, etc).
  • Implemented 'storage profiles', which allow user-defined instances of storage engines combined with their configuration parameters (for example, authentication details for Amazon S3). This is all managed by Devblocks, including a simple way to prompt for, and save, profile configuration information.
  • Implemented 'storage schema' extensions to inform the storage service how to handle specific types of content. Schemas take care of updating storage manifest information (extension, profile, size, key) using the appropriate DAO class; which simplifies storing and retrieving content from various locations in the code base. Storage schemas should implement a class in the Storage_* namespace, using the appropriate abstract extension class, to provide static ::get(), ::put(), and ::delete() methods. This allows single-line, abstract management of content (such as saving or loading attachments or message bodies).
  • Added a 'Storage' tab to 'Helpdesk Setup' as a place to manage Storage Profiles and Storage Schemas.
  • Migrated Cerb5 'attachments' to the new Devblocks storage engine, using 'disk' as a backwards-compatible default. The ability now exists to move attachments to the database in environments where this makes sense. In a near-future commit, we're planning to provide the ability to configure storage rules; for example, the ability to archive attachments for closed tickets in S3 while keeping content for open tickets in the local database.
  • Message bodies (DAO_MessageContent) are now stored inside the Devblocks storage service. By default, the service continues to use 'database' as the storage mechanism since the existing Cerb4 content is already there (but the schema has changed and will be migrated by a database patch). The ability now exists to store message bodies in the local filesystem, since they're large blocks of immutable content. Having them as files makes incremental backups much easier (and reduces database bloat).
  • Implemented a 'Storage Manager' scheduled task. It is responsible for moving content between storage engines depending on your preferences. If you have all attachments stored in the database and decide to migrate them elsewhere (disk, S3, etc) then the storage manager will break the work up between crons and handle it for you over time (without bogging the system down). If you want content to move faster you can explicitly run the storage task from 'Setup->Scheduler' and add '&reload=1' to the URL.
  • Storage engines now accept an optional file handle ($fp) parameter for ::get() calls. This allows you to efficiently stream content into a file rather than loading it all into a string, which uses far less memory.
  • Storage engines now allow a polymorphic $data parameter for ::put() calls. This allows you to efficiently stream content from a file rather than passing it as a string, which uses far less memory. This is especially useful for handling files provided by HTML forms, since you'll always have the content in a temporary file on the disk already, and you can simply stream that in small chunks to the proper storage engine.
  • The archive/unarchive process will now use file pointer streams when content is larger than 1MB and in-memory strings when smaller. This should allow for a far greater balance between performance and memory efficiency.

Explorer Service

  • Implemented an 'Explorer' service in the platform, which provides a thin global navigation bar over an arbitrary set of URLs, with next/prev and toolbar functionality. Previously, different pages managed their own 'series' functionality (e.g. tickets, tasks, opps, orgs). This worked fine for a while, but we'd started to notice limitations with the previous approach. Previously, you couldn't have two series open in different browser windows to page through different search results; and the paging was often limited to only 100 or so results. The new explorer functionality no longer has these limitations, and it's better performing. There's no forced limit to the number of results you can page through. As well, any plugin can take advantage of the new explorer functionality. Explorer items are stored with JSON (so any kind of data can be stored along with records). There is a new 'cerberusweb.explorer.toolbar' extension point that will let you render your own toolbar at the top of the explorer page. A default maintenance task has been provided to clear explorer data sets that haven't been used in the past 24 hours.
  • Added the ability to 'explore' starting at any row in a worklist. Simply select (checkbox) a row and then click 'explore'. You'll still have access to all the rows around it with next/prev. Without selecting a row, explore will now use the first row of the current worklist page (instead of the very first result).


  • [CHD-1154] [Who's Online] For better tracking of worker status, show the IP address and time of last activity.

Plugin Development

  • Devblocks itself is now a Devblocks plugin, which is able to provide extensions, events, and other manifest information in the libs/devblocks/plugin.xml file. This plugin is always enabled, but should be hidden from plugin configuration by the application layer.
  • Refactored the way that Devblocks handles extension parameters. A DAO_DevblocksExtensionPropertyStore class has been added to manage the loading and setting extension properties. It also provides an extension registry-wide cache for performance. As a consequence, it's now possible to statically save and load properties for an extension (i.e. without needing to instance it first).
  • Consistency: Model_*, View_*
  • Added a '|devblocks_prettybytes' modifier to templates that will format a number of bytes as bytes, KB, MB, GB; to a specified number of decimal places.
  • Added DevblocksPlatform::getTempFile() to create temporary files and automatically clean them up after the request runs.
  • Added DevblocksPlatform::getTempFileInfo() to give information about a previously created temporary file (when it matters).
  • Registered a PHP 'shutdown' function for Devblocks so the platform has a chance to take action when the script has finished (including after 'exit' and 'die').
  • Added the ability to clear a single cache using DevblocksPlatform::clearCache($cache_id).
  • DevblocksORMHelper::_getWhere() (and subsequently, most DAO_*::getWhere() calls) can now accept arrays for the sortBy and sortAsc parameters. This allows sorting results by more than one column without writing direct SQL statements.
  • Added a $view->renderTotal property to abstract views. This tells View::getData() and DAO::search() whether or not to compute the number of total rows in the result set when paging through a view. This is particularly efficient for procedurally paging through views (e.g. bulk update) because it won't run a second COUNT() query for each page.
  • Implemented a 'devblocks_hyperlinks' Smarty modifier to create hyperlinks from URLs found in plaintext.
  • Converted DevblocksPlatform::getDateService() to PHP 5.2's DateTime/DateTimeZone classes. This also added a new optional 'is_gmt' argument to the '|devblocks_date' template modifier (which ignores the timezone conversion when printing dates).
  • It's now possible for plugins to change paths on the disk (/features -> /storage/plugins) without their manifests being deleted and recreated within Devblocks. This prevents issues with upgrades where active plugins may become disabled because they were relocated within the directory structure. All that must match for a plugin manifest is the ID -- any other updated details will be refreshed on the same record.
  • C4_AbstractViewModel will now persist two additional properties: renderTotal and renderTemplate. renderTotal is a performance optimization that tells a view to not calculate the total number of results in a second getData() query. renderTemplate allows $view>render() to display different templates for different situations (e.g. a slimmed down mobile template, a peek version of a worklist, etc). The $view->render() template file itself doesn't necessarily need to change, but the template parameter can be used to set additional data in the template scope and adapt.
  • You no longer need to define a 'devblocks.i18n.strings' extension for your plugin to provide translations. Just place a strings.xml file in the root of your plugin directory.
  • Devblocks PatchContainers have been removed. Patch information is now stored in the plugin.xml manifest. Patches are now linked to a specific application release (e.g. 5.0.0-beta).
  • Devblocks will now give precedence to 'c' (controller) and 'a' (action) parameters in the $_GET scope over the $_POST scope, but both will be checked. This is to allow genericAjaxPost() on HTML forms to override the destination in an Ajax post, even though the form contains a controller+action in hidden <input> fields.
  • Added ticket.last_message_id to complement ticket.first_message_id
  • Added 'delta' support as the first argument to the '|devblocks_prettytime' Smarty modifier. This takes a number of seconds and formats it as "+3d" or "-3m".
  • [CHD-1481] Added a new event point ('task.create') for observing task creation.
  • [CHD-1479] Implemented a new event listener ('opportunity.create') for observing the creation of new opportunities.


  • [Plugins] The 'cerberusweb.mobile' plugin has moved into the optional plugins repository and is no longer a part of the Cerb5 core.
  • [Plugins] The 'wgm.google_cse' (Google Custom Search Engines) plugin has moved into the optional plugins repository and is no longer a part of the Cerb5 core.
  • [Plugins] The 'cerberusweb.webapi' plugin has moved into the optional plugins repository and is no longer a part of the Cerb5 core. It is being replaced by the 'cerberusweb.restapi' plugin.
  • [Mail] [CHD-1844] The 'drafts' and 'snippets' tabs will now save their focus if you navigate away and come back.
  • [Activity] The previously selected activity tab will now retain focus if you navigate away and return.
  • [Contexts/Snippets] Added a 'notification' context.
  • [Contexts/Snippets] Added a 'task' context.
  • [Project] The Community Edition and the Free Version have merged into a simpler free version. There is no more tagline or limitation on the number of groups you can have without a license. You no longer need to complete the /install survey to receive a Community license (it's the default for all new installations). Instead, the /install survey will grant you a special one-time discount coupon for a future purchase.
  • [UI/UX/Setup] Prettied up the 'Plugins & Features' tab in Setup. Plugin manifests can now provide an image/screenshot to be displayed next to the plugin description.
  • [Web-API] Implemented a much improved new Web-API plugin for Cerb5, providing a RESTful JSON/XML gateway to helpdesk data using GET/PUT/POST/DELETE over standard HTTP connections. Extensions can provide new REST controllers to expose plugin-provided information to the gateway as well. The platform will automatically handle the serialization of array data and primitives into JSON or XML (simply by appending .json or .xml to a request). An error handling framework is also provided. Authentication has been simplified compared to Cerb4's Web-API, and has been tested in Java/PHP/Objective-C (and anything else should work too). Authentication is based on worker logins, making it much easier to build tools on mobile phones and desktops. Security is handled by the same ACL/Permissions as the main helpdesk (i.e. if a worker can't delete tickets in the GUI then they can't through the API). The current implementations use CerberusContext to provide detailed, linked objects in a flat format (e.g. ticket->worker->org->customfield); making parsing results in many environments easier w/o a deep hierarchy.
  • [Plugins] Moved 'Forum Explorer' to the optional plugin repository.
  • [Contexts] Added a 'feedback' context.
  • [Contexts] Added an 'attachment' context.
  • [Contexts] Added a 'time tracking' context.
  • [KB/Performance] Added a DAO_KbCategory::getAll() cache.
  • [Contexts] Added a 'kb article' context.
  • [Workspaces] [CHD-1765] Workspace delete removes wrong workspace
  • [Mail/Drafts] If the subject and body are empty on an auto-save from /compose or /create, then the draft won't be saved. This prevents having to deal with empty drafts from simply opening the compose screens.
  • [Mail/Compose] Better form validation (to/subject/body).
  • [Mail/Log Ticket] Better form validation (from/requesters/body).
  • [Mail/Usability] [CHD-1554] The quote line ("on date, so-and-so wrote:") is now more brief on replies. Either the sender's personal name or their e-mail address is shown, rather than both. The date shows the day/month/year, but not the hours/mins/secs or GMT offset. (Suggested by Brett Garrett)
  • [CHD-1510] [CHD-1511] [Mail/Scheduler] The 'cron.pop3', 'cron.parser', and 'cron.mail_queue' scheduled jobs will refuse to run if the 'imap' or 'mailparse' extensions are missing. These extensions tend to disappear when hosts upgrade PHP and don't include all the previous configuration (from installation requirements).
  • [CHD-1506] [Quick Search] Does not add group filters automatically like traditional search
  • [Mail] [CHD-1450] Fixed an issue where worker 'assignment' notifications could be sent to workers that were already assigned to a ticket when another worker replied to it.
  • [CHD-1496] [Notifications] Notifications don't seem to be getting purged out of the database.
  • [Platform] [CHD-1851] Fixed an issue where plugins that no longer exist on disk wouldn't clean up their records in the database. The 'cleanupPluginTables' code was using 'getPluginRegistry' -- but the registry automatically filters out any plugin that's not on the disk. Now the clean-up code accesses the database directly.
  • [CHD-1473] [Mail] "Reply to all" exclude list does not block requesters from merged tickets.
  • [CHD-829] [Requesters] Include a checklist of e-mail addresses used in the ticket, so you could easily add/drop requesters. (Jeff@WGM: You can now modify the requester list in a textbox during replies).
  • [Mail] Improved the 'Auto-requester To/Cc' setting in 'Setup->Mail' into a global 'Always exclude these addresses as recipients' list. This prevents specific addresses from becoming requesters from anywhere. It's especially useful in situations where you receive an automated receipt from a payment processor that you merge into an order ticket. By preventing the receipt address from becoming a requester, you won't have to constantly modify the requester list after merging.
  • [Mail] The current recipients list is now shown at the top of Display Ticket. Clicking on a recipient will pull up the address peek dialog. You can add or remove recipients by clicking on the "..." ellipses.
  • [Mail] A warning has been added to the top of Display Ticket when there are no recipients.
  • [Mail/Drafts] Implemented drafts functionality when forwarding messages on tickets.
  • [Parser] Autoreplies will not be sent to initial requester addresses that aren't recipients; i.e. if those recipients were 'excluded' from being added to the ticket when the ticket was received (e.g. automated receipts from a payment gateway).
  • [Plugins/Platform/Sessions] Added several new methods to the Session service: getAll() to retrieve all active sessions; decodeSession($data) to decode the PHP session variables without restoring to the current $_SESSION scope; clear($key) to expire a specific session. These changes allow session management functionality (e.g. kicking specific logins).
  • [Login] The login form will now display a clear error when authentication fails.
  • [Licensing] Licenses are now based on seats rather than worker accounts. This means that as of 5.0rc2 all Cerb5 installations can create unlimited worker accounts. Your license determines the number of simulatneous workers that may be logged in. For example, if you have 5 seats and 50 workers then your remaining workers may find themselves waiting for a seat to be available ("musical chairs"). Idle sessions will be "kicked" if another worker is trying to log in. We feel this is a far more fair way to license the software, and it resolves many outstanding issues from Cerb4 worker-based licensing: unfriendly license terms for helpdesks with interns/temps/volunteers, penalty to preserving the history of archived workers, single-account evaluations, etc. The benefits of Cerb5 are more related to teamwork rather than having many infrequently-used worker accounts. The 'Evaluation Edition' (no license) now restricts Cerb5 to a single worker logged in at a time, but you may create unlimited worker accounts. The 'Community Edition' (granted after the installation survey) permits 3 simultaneous workers and no longer restricts the total number of workers. Purchased licenses increase the seat capacity beyond that point, and provide ongoing software updates.
  • [Updater] When running /update with an expired license, you're now given the options to renew, remove your expired license and enter Evaluation Mode, or downgrade.
  • [Who's Online] The signed on worker list now uses actual session data rather than "last activity" information. This is far more accurate.
  • [Sessions] Tweaked seat management and authentication so idle sessions aren't logged off unless at capacity.
  • [Mail Queue/Setup] [CHD-1852] Added a 'Mail Queue' tab in Setup that allows administrators to monitor queued messages.
  • [Mail Queue] Implemented a 'queue_fails' property on queued messages to keep track of the number of consecutive fails for a particular message. The queue will attempt to redeliver messages until they fail 10 times; which prevents a backlog of failing messages from blocking the entire queue. Re-queuing a message will reset the fail counter.
  • [Drafts/Mail Queue] The drafts/queue view now displays rows on two lines. This gives more room to the subject and long 'To:' lists.
  • [Drafts/Mail Queue] Implemented peek functionality. This displays for superusers and the owners of drafts/messages.
  • [Drafts] You no longer need to be a superuser to batch update your drafts.
  • [Mail/Setup] [CHD-849] When you delete the default group, the destination group will become the new default.
  • [Mail/Display Ticket] [CHD-720] Added the ability arbitrary tickets from Display; without needing to have tickets next to each other in a worklist. To merge any two tickets, click into one of the tickets, click the 'more>>' button in the top toolbar, click the 'merge' button, and enter the ID of the other ticket.
  • [Explorer] [CHD-1813] Brackets don't navigate the explorer when focus is in the upper pane.
  • [Mail] [CHD-1551] Moving, or setting custom fields on, a previously closed ticket will resend the "close ticket" auto-reply. (Jeff@WGM: The /display page is now more careful when setting the 'is_closed' property and it will try to avoid setting it to the same value. I considered moving the autoreply to the 'pre-change' event, but the snippets in the template should be aware of its post state).
  • [Storage/Plugins] Implemented 'Model_DevblocksStorageProfile->getUsageStats()', which provides a list of storage schemas using a particular storage profile.
  • [Storage/Setup] Storage schemas will now display their content breakdown by storage profile rather than just storage engine.
  • [Storage/Setup] The storage profile peek panel will now display the schemas using the current profile. Improved the warning displayed when editing the configuration of an active profile, and added a note about not being able to delete a profile until it has no content.
  • [Storage/Setup] [CHD-1861] Implemented the ability to delete storage profiles when they have no associated content.
  • [Research/Plugins] Removed the 'research' page. Any 'cerberusweb.research.tab' plugins should change their extension point to 'cerberusweb.knowledgebase.tab'.
  • [Knowledgebase] Added back the 'knowledgebase' menu + page, and moved the KB out of the deprecated 'research' menu. 'Browse' and 'Search' are now tabs inside the KB, rather than the confusing button toggle from Cerb4.
  • [Research/Knowledgebase] [CHD-1862] Research tab is still visible after disabling the knowledgebase plugin.
  • [Platform/Plugins] Added Markdown parsing support to Devblocks using the BSD-licensed PHP Markdown library from Michel Fortin (based on Markdown by John Gruber). Simply use DevblocksPlatform::parseMarkdown($text).
  • [UI/UX] Made the ticket 'peek' popup a little wider by default to accommodate the automatic wrapping of most email clients at ~78 characters.
  • [Knowledgebase] Added 'Markdown' support to the knowledgebase as the new preferred article format. HTML is still supported as an alternate format, and plaintext articles will be automatically convered to Markdown by the upgrade. Markdown is a good fit for Cerb5 because the markup is easily readable by humans and matches the way people naturally punctuate plain text. It's easier to read, edit, paste into email, or search index.
  • [Knowledgebase] Implemented a markup/visual editor (MarkItUp; by Jay Salvat) in the Knowledgebase and added support for Markdown and HTML syntax. You can use the toolbar to add familiar word processing options (e.g. bold, italics, lists, images, links). There's a live preview button that will render your output as you type. This completely eliminates the tedious process in Cerb4 of tweaking a KB article, clicking it to view, then clicking edit again to make another change. We've avoided adding visual editors to the KB for so long because most of them are bloated. MarkItUp is a good compromise: it's a jQuery plugin, it's 8KB packed, and its other CSS/JS resources can be rolled into the files we already cache. It also doesn't try to be a full WYSIWYG editor -- if you want to visually design complex tables and other markup, use something like Dreamweaver and paste the generated HTML into the textbox.
  • [Knowledgebase] Implemented a 'display' page for individual knowledgebase articles. This provides a future home for tabs, toolbars, attachments, comments, explore, snippets, and other advanced functionality (that is difficult to provide from only a 'peek').
  • [Knowledgebase/UI/UX] Knowledgebase articles are now displayed in an IFRAME to prevent the global stylesheet from wrecking article contents. It's possible we'll add a customizable KB specific stylesheet in the future -- but at least for the time-being articles can provide their own STYLE blocks.
  • [Knowledgebase] [CHD-1643] Permalink ID functionality for KB articles
  • [Knowledgebase] [CHD-1349] Preview or display knowledgebase article after edit
  • [Knowledgebase] [CHD-1345] Resize knowledgebase article
  • [Snippets] [CHD-1868] Admins should be able to delete any snippet.
  • [Mail/Drafts] Drafts in the conversation history will now show their Cc/Bcc headers, if they have them.
  • [Knowledgebase/Mail/UX] Improved the L&F of the knowledgebase search from the Reply screen. Added a minimalistic article worklist that allows paging + sorting. You can now hit [RETURN/ENTER] inside the search box. The search box is automatically focused.
  • [Knowledgebase] Added Explorer functionality to knowledgebase article worklists.
  • [Platform/Plugins/Worklists] Used jQuery to improve worklists: row highlighting, row selection, and Explorer bookmarks.
  • [CHD-1848] [Browsers] Checkbox and selections are slow to respond in Chrome and IE7
  • [Platform/Explorer/Performance] Worklists will no longer calculate the Explorer bookmark every time a row is selected. The Explorer functionality will use the first selected row as the starting point, and will find it only when the 'explore' link is clicked.
  • [Explorer] Clicking on the logo during 'Explorer' mode will return you to the exact page you started from.
  • [Platform] The /update process will now properly flush the Smarty3 cache and all compiled templates.
  • [Support Center] [CHD-1864] Announcements feeds do not use chosen feed title.
  • [Knowledgebase] [CHD-1190] Added custom fields to knowledgebase articles. This provides much more flexibility when organizing worklists: region, language, product, assignee, etc.
  • [Contexts/Web-API] Returned custom fields with knowledgebase articles.
  • [Licensing] If you're licensed for a major software update (e.g. 5.0, 5.1, 5.2, ...) then you'll receive all minor updates in that branch (e.g. 5.1.x) regardless of when your updates coverage expires.
  • [Platform] Implemented 'ONDEMAND_MODE' (toggled from framework.config.php) that disables several Setup options that don't need to be exposed in a software-as-a-service environment: the Storage tab, the Scheduler tab, Licensing, and Authorized IPs.
  • [Support Center] [CHD-1782] You can now choose which fields (including custom fields) to expose to customers in the 'My Account' area of Support Center community portals. Address and Organization fields are available. Each field can be designated as: Hidden (not shown), Read Only (visible but not editable), or Editable (the visitor can manipulate and save the field value). This allows customers to maintain their own contact information, as well as perform some data entry for you (e.g. "Industry", "# Employees", etc).
  • [Support Center] [CHD-1549] Fixed a bug that prevented customers from changing their passwords from 'My Account' in the Support Center.
  • [Watchers] [CHD-1874] Duplicate message ID in header when watcher for incoming mail is triggered to forward mail to external address.
  • [Setup/Storage] [CHD-1876] Storage profiles have checkboxes that serve no purpose
  • [Setup/Storage] [CHD-1878] Make the storage schema configuration more obvious. The fact the H3 titles are links can be easily missed. (Requested by Niek Beernink @ Oxilion; Fixed by Jeff@WGM: Moved the link to an "(edit)" label.)
  • [CHD-1880] [Drafts] Forwarded messages do not show ticket subject in the 'Drafts' tab
  • [CHD-1858] memcached::set expects at most 3 parameters, but 4 are given in devblocks.class.php line 2207 (Jeff@WGM: Abstracted the difference between PECL/Memcache and PECL/Memcached).
  • [Mail/ACL] [CHD-1847] Fixed a bug in the pile sorter that allowed tickets to be moved from groups that the active worker isn't a member of.
  • [Mail/Open Ticket] [CHD-1474] 'Insert Signature' button not working.
  • [Installer] [CHD-1808] Fixed the issue with redirecting to /install when installing Cerb5 in the root path of a domain/subdomain.
  • [Mail/Merge] [CHD-1849] The destination ticket in merges will now have the status (open, waiting, closed, deleted) of the latest updated message.
  • [Reports] [CHD-1658] The 'Custom Field Usage' report will now show human-readable values for checkbox, date, and worker custom fields.
  • [Snippets] Added a filter box to the Snippets chooser which automatically filters the worklist to matching snippets as you type substrings (i.e. 'price' matches 'cerb5 price sheet'). If you want to really categorize your snippets, consider prefixing tags to their titles (e.g. '[Policy]'). This will allow for quick filtering.
  • [Mail/Snippets] Added a 'hits' column to the Snippets chooser. This tracks the uses per snippet per worker, so each user has their own 'most frequently used' list for quickly selecting their most used snippets.
  • [Who's Online] [CHD-1882] ip2long() returns an error on 32-bit systems for some IP addresses.
  • [Setup/Custom Fields] The 'ID' is now displayed next to each custom field in Setup, since it's used by functionality like the REST-based Web-API.
  • [Platform/Plugins] DAO_CustomFieldValue::formatAndSetValues() can now accept values for multi-value fields with '+' or '-' prefixes to designate delta operations. You can set and unset multiple fields in a single operation.
  • [REST/Web-API] Implemented several helper methods for Extension_RestController. _handleSanitizeValue($value,$type) will enforce a data types for provided values; _handleRequiredFields($required,$fields) will enforce required fields for a REST operation (e.g. POST /create.xml); _handleCustomFields($scope_array) will parse custom fields from the $_POST/$_REQUEST scope and return an assoc array ($id=>$vals).
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Address records.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Org records.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Worker records.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Task records.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Worker Event (Notification) records.
  • [Platform/Plugins] Added a new 'DevblocksPlatform::importVar()' utility method to sanitize user-provided data. It currently supports: 'array', 'float' (123.45), 'string', 'integer', 'bit' (0/1), 'boolean' (true/false), 'timestamp' (string or unix timestamp). These types are now also available when using 'DevblocksPlatform::importGPC()'.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Opportunity records.
  • [REST/Web-API] Implemented (POST /parser/parse.xml) which accepts MIME message content in a POST variable called 'content' and returns a ticket_id on success.
  • [REST/Web-API] Implemented (POST /create.xml) and (PUT /id.xml) for Feedback records.
  • [REST/Web-API] Implemented (PUT /tickets/id.xml) for Ticket records w/ custom field support. Also enforced group memberships on DELETE and GET actions.
  • [REST/Web-API] [CHD-1883] Creating workers through the Web-API will now properly register their e-mail addresses as worker addresses.
  • [REST/Web-API] Implemented 'POST /tickets/123/comment.xml'
  • [REST/Web-API] Implemented 'POST /tasks/123/note.xml'
  • [REST/Web-API] Implemented 'POST /orgs/123/note.xml'
  • [REST/Web-API] Implemented 'POST /opps/123/note.xml'
  • [UI/UX/Notes] Improved the display of notes on Orgs, Opps, and Tasks. Added Ajax-driven delete functionality so the page doesn't need to refresh to remove a note. Refactored redundant code.
  • [UI/UX/Notes] Fixed a bug that prevented notes from consistently listing in reverse chronological order.
  • [Platform] Switched from $_SERVER['PHP_SELF'] to $_SERVER['SCRIPT_NAME'] for determining HTTP request information. This was necessary for non-Apache webservers like Nginx/Lighttpd that interface with FastCGI.
  • [Mail] [CHD-1884] Comments notify workers checkbox no longer works if you opened the notify workers list for a sticky note first (Reported by Niek Beernink @ Oxilion).


  • [CHD-1890] [Translations] Smarty 'capitalize' modifier considers umlauts to be word breaks.
  • [CHD-1900] [Parser] Disallow CR/LF in subject lines
  • [CHD-1905] [My Account] Always use 'read all' mode not working.
  • [CHD-1909] [Mail/Reply] When replying to a ticket, wait for confirmation about the final save of the draft before submitting the FORM.
  • [Mail/Reply] [CHD-1899] After replying to a ticket, the browser URL will now re-display the full path to the ticket (/cerb5/display/ABC-12345-678). This is slightly less efficient but far more convenient.
  • [Reports] [CHD-1908] The report graphs do not render in Internet Explorer.
  • [Reports] The Worker Average Response Time report will now filter out data from deactivated workers.
  • [Notes] Fixed the lack of a margin at the top of Opp/Org/Task notes.
  • [Windows/Platform/Support Center] [CHD-1912] A colon (:) is not valid in Windows filenames, but it's being used in the SC templates with "devblocks:" resources defining a ":portal_xxxxxx". This has been fixed by changing the template syntax to "devblocks:plugin_id:portal_xxxxxx:/path/to/plugin/template". You *MUST* update any custom templates to use this format if defined in Setup->Community Portals.
  • [Worklist] [CHD-1913] Columns, rows per page, and "sort by" preferences not saved between sessions.
  • [CRM/Opportunities] [CHD-1915] When doing a Bulk Update on an Opps list with pre-selected items, selecting 'Whole List' still only affects only the checked items.
  • [Address Book/UX] [CHD-1910] Allow fields in e-mail window to be saved with ENTER key rather than tabbing to the save button. This saves a lot of keystrokes when doing data entry.
  • [Knowledgebase] [CHD-1914] Editing changes from the regular interface (not peek) sends you to a non-index.php URL.
  • [Mail/Parser] [CHD-1918] The parser is not pulling filenames from the 'content-disposition' header when attachments don't provide a 'content-name' or 'content-filename'.
  • [CHD-1924] [Scheduler/Maintenance] Call to a member function delete() on a non-object in message.php on line 515.
  • [CHD-1923] [Mail/Merge] Merging tickets by masks from Display Ticket works, but using an 'ID' does not.
  • [CHD-1931] [Mail/Compose] Auto-response is being queued without requesters or a subject when closed immediately.
  • [CHD-1930] [Address Book] Editing an address via peek throws error in Internet Explorer.
  • [CHD-1932] [Mail/Drafts] [Chrome/Firefox] jquery.combined.min.js goes unresponsive after a few seconds.
  • [CHD-1940] [Mail/Display] Fixed a potential bug where a worker would be taken to an invalid '/display' URL after replying to a ticket. This appears to happen if there's no mask available for a ticket. In these situations the ticket's internal ID will be used instead.