array(
            'name' => 'panel_body',
            'columns' => 2,
            'labelsOnTop' => true,
            'placeholders' => true,
            'fields' => array(
                array(
                    'name' => 'feed_url',
                    'label' => 'LBL_RSS_FEED_URL',
                    'type' => 'text',
                    'span' => 12,
                    'required' => true,
                ),
                array(
                    'name' => 'limit',
                    'label' => 'LBL_RSS_FEED_ENTRIES_COUNT',
                    'type' => 'enum',
                    'options' => 'tasks_limit_options',
                ),
                array(
                    'name' => 'auto_refresh',
                    'label' => 'LBL_DASHLET_REFRESH_LABEL',
                    'type' => 'enum',
                    'options' => 'sugar7_dashlet_reports_auto_refresh_options',
                ),
            ),
        ),
    ),
);
Controller
The rssfeed.js controller file, shown below, contains the JavaScript to render the news articles on the dashlet. The Dashlet view must include 'Dashlet' plugin and can override initDashlet to add additional custom process while it is initializing.
./clients/base/views/rssfeed/rssfeed.js
/*
 * Your installation or use of this SugarCRM file is subject to the applicable
 * terms available at
 * http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
 * If you do not agree to all of the applicable terms or do not have the
 * authority to bind the entity as an authorized representative, then do not
 * install or use this SugarCRM file.
 *
 * Copyright (C) SugarCRM Inc. All rights reserved.
 */
/**


*
 * Copyright (C) SugarCRM Inc. All rights reserved.
 */
/**
 * RSS Feed dashlet consumes an RSS Feed URL and displays it's content as a list
 * of entries.
 *
 * The following items are configurable.
 *
 * - {number} limit Limit imposed to the number of records pulled.
 * - {number} refresh How often (minutes) should refresh the data collection.
 *
 * @class View.Views.Base.RssfeedView
 * @alias SUGAR.App.view.views.BaseRssfeedView
 * @extends View.View
 */
({
    plugins: ['Dashlet'],
    /**
     * Default options used when none are supplied through metadata.
     *
     * Supported options:
     * - timer: How often (minutes) should refresh the data collection.
     * - limit: Limit imposed to the number of records pulled.
     *
     * @property {Object}
     * @protected
     */
    _defaultOptions: {
        limit: 5,
        auto_refresh: 0
    },
    /**
     * @inheritdoc
     */
    initialize: function(options) {
        options.meta = options.meta || {};
        this._super('initialize', [options]);
        this.loadData(options.meta);
    },
    /**
     * Init dashlet settings
     */
    initDashlet: function() {
        // We only need to handle this if we are NOT in the configure screen
        if (!this.meta.config) {
            var options = {};
            var self = this;
            var refreshRate;
            // Get and set values for limits and refresh
            options.limit = this.settings.get('limit') || this._defaultOptions.limit;
            this.settings.set('limit', options.limit);


this.settings.set('limit', options.limit);
            options.auto_refresh = this.settings.get('auto_refresh') || this._defaultOptions.auto_refresh;
            this.settings.set('auto_refresh', options.auto_refresh);
            // There is no default for this so there's no pointing in setting from it
            options.feed_url = this.settings.get('feed_url');
            // Set the refresh rate for setInterval so it can be checked ahead
            // of time. 60000 is 1000 miliseconds times 60 seconds in a minute.
            refreshRate = options.auto_refresh * 60000;
            // Only set up the interval handler if there is a refreshRate higher
            // than 0
            if (refreshRate > 0) {
                if (this.timerId) {
                    clearInterval(this.timerId);
                }
                this.timerId = setInterval(_.bind(function() {
                    if (self.context) {
                        self.context.resetLoadFlag();
                        self.loadData(options);
                    }
                }, this), refreshRate);
            }
        }
        // Validation handling for individual fields on the config
        this.layout.before('dashletconfig:save', function() {
            // Fields on the metadata
            var fields = _.flatten(_.pluck(this.meta.panels, 'fields'));
            // Grab all non-valid fields from the model
            var notValid = _.filter(fields, function(field) {
                return field.required && !this.dashModel.get(field.name);
            }, this);
            // If there no invalid fields we are good to go
            if (notValid.length === 0) {
                return true;
            }
            // Otherwise handle notification of invalidation
            _.each(notValid, function(field) {
                 var fieldOnView = _.find(this.fields, function(comp, cid) {


var fieldOnView = _.find(this.fields, function(comp, cid) {
                    return comp.name === field.name;
                 });
                 fieldOnView.model.trigger('error:validation:' + field.name, {required: true});
            }, this);
            // False return tells the drawer that it shouldn't close
            return false;
        }, this);
    },
    /**
     * Handles the response of the feed consumption request and sets data from
     * the result
     *
     * @param {Object} data Response from the rssfeed API call
     */
    handleFeed: function (data) {
        if (this.disposed) {
            return;
        }
        // Load up the template
        _.extend(this, data);
        this.render();
    },
    /**
     * Loads an RSS feed from the RSS Feed endpoint.
     *
     * @param {Object} options The metadata that drives this request
     */
    loadData: function(options) {
        if (options && options.feed_url) {
            var callbacks = {success: _.bind(this.handleFeed, this), error: _.bind(this.handleFeed, this)},
                limit = options.limit || this._defaultOptions.limit,
                params = {feed_url: options.feed_url, limit: limit},
                apiUrl = app.api.buildURL('rssfeed', 'read', '', params);
            app.api.call('read', apiUrl, {}, callbacks);
        }
    },
    /**
     * @inheritdoc
     *
     * New model related properties are injected into each model:
     *
     * - {Boolean} overdue True if record is prior to now.
     */
    _renderHtml: function() {
        if (this.meta.config) {


_renderHtml: function() {
        if (this.meta.config) {
            this._super('_renderHtml');
            return;
        }
        this._super('_renderHtml');
    }
})
Workflow
When triggered, the following procedure will render the view area:
Retrieving Data
Use the following commands to retrieve the corresponding data:
Data Location
Element
Command
Main pane
Record View
this.model
Record View
this.context.parent.get("model")
List View
this.context.parent.get("collection")
Metadata
Â
this.dashletConfig['metadata_key']
Module vardefs
Â
app.metadata.getModule("ModuleName")
Remote data
Bean
new app.data.createBean("Module")new app.data.createBeanCollection("Module")
RestAPIÂ
app.api.call(method, url, data, callbacks, options)
Ajax CallÂ
$.ajax()
User inputs
Â
this.settings.get("custom_key")
Handlebar Template
The rssfeed.hbs template file defines the content of the view. This view is used for rendering the markup rendering in the dashlet content.
./clients/base/views/rssfeed/rssfeed.hbs
{{!--
/*
 * Your installation or use of this SugarCRM file is subject to the applicable
 * terms available at
 * http://support.sugarcrm.com/Resources/Master_Subscription_Agreements/.
 * If you do not agree to all of the applicable terms or do not have the
 * authority to bind the entity as an authorized representative, then do not
 * install or use this SugarCRM file.
 *
 * Copyright (C) SugarCRM Inc. All rights reserved.
 */
--}}
{{#if feed}}
    <div class="rss-feed">
        <h4>


            {{#if feed.link}}{{/if}}
            {{feed.title}}
            {{#if feed.link}}{{/if}}

        {{#each feed.entries}}

                Dashlets
                {{#if author}} - {{str "LBL_RSS_FEED_AUTHOR"}} {{author}}{{/if}}

        {{/each}}

{{else}}

        {{#if errorThrown}}
        {{str "LBL_NO_DATA_AVAILABLE"}}
        {{else}}
        {{loading 'LBL_ALERT_TITLE_LOADING'}}
        {{/if}}

{{/if}}
  	Last modified: 2023-02-03 21:04:03


Sidecar
Overview
Sidecar is a platform that moves processing to the client side to render pages as single-page web apps. Sidecar contains a complete Model-View-Controller (MVC) framework based on the Backbone.js library.
By creating a single-page web app, server load drastically decreases whileÂ the client's performance increases because the application is sending pure JSON data in place of HTML. The JSON data, returned by the v10 API, defines the application's modules, records, and ACLs, allowing UI processing to happen on the client side and significantly reducing the amount of data to transfer.Â
Â
Composition
Sidecar containsÂ the following parts, which are briefly explained in the sections below:
Backbone.js
Components (Layouts,Â Views, and Fields)
Context
Backbone.js
Backbone.js is a lightweight JavaScript framework based on MVP (modelâviewâpresenter) application design. It allows developers to easily interact with a RESTful JSON API to fetch models and collections for use within their user interface.
For more information about Backbone.js, please refer to their documentation atÂ Backbone.js.
Components
Everything that is renderable on the page is a component. A layout is a component that serves as a canvas for one or more views and other layouts. All pages will have at least one master layout, and that master layout can contain multiple nested layouts.
Layouts
Layouts are components that render the overall page. They define the rows, columns, and fluid layouts of content that gets delivered to the end user.
Example layouts include:
Rows
Columns
Bootstrap fluid layouts
Drawers and dropdowns
For more information about the various layouts, please refer to the Layouts page of this documentation.
Views


Views
Views are components that render data from a context and may or may not include field components. Example views include not only record and list views but also widgets such as:
Graphs or other data visualizations
External data views such as Twitter, LinkedIn, or other web service integrations
The global header
For more information about views, please refer toÂ the Views pageÂ of this documentation.
Fields
Fields render widgets for individual values that have been pulled from the models and also handle formatting (or stripping the formatting of) field values. Like layouts and views, fields extend Backbone views.Â
For more information about the various layouts, please refer toÂ the Fields page of this documentation.
Context
A Context is a container for the relevant data for a page, and it has three major attributes:
Module : The name of the module this context is based on
Model : The primary or selected model for this context
Collection : The set of models currently loaded in this context
Contexts are used to retrieve related data and to paginate through lists of data.
Â
  	Last modified: 2023-02-03 21:04:03


Routes
Overview
Routes determine where users are directedÂ based on patterns in the URL.
Routes
Routes, defined in ./include/javascript/sugar7.js, are URLÂ patterns signified by aÂ hashtag ("#") in theÂ URL.Â An example moduleÂ URL pattern for the Sugar application isÂ http://{site url}/#<module>.Â This route wouldÂ direct a user to the list view for a given module. The following sections will outline routes and how they are defined.
Route Definitions
The router accepts route definitions in the following format:
routes = [
    {
        name: "My First Route",
        route: "pattern/to/match",
        callback: function()
        {
            //handling logic here.
        }
    },
    {
        name: "My Second Route",
        route: "pattern/:variable",
        callback: "<callback name>"
    }
]
A route takes in three properties: the name of the route, the route pattern to match, and the callback to be called when the route is matched. If a default callback is desired, you can specify the callback name as a string.
Route Patterns
Route patterns determine where to direct the user. An example of routing is done when navigating to an account record. When doing this you may notice that your URL is:
http://{site url}/#Accounts/aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee
A stockÂ route's definition is defined in ./include/javascript/sugar7.js as:
{
    name: "record",
    route: ":module/:id"
},
Variables in the route pattern areÂ prefixed with a colon such asÂ :variable. The route pattern above contains two variables:
module
id
Custom Routes


module
id
Custom Routes
As of 7.8.x, you can add the routes during the initialization of the Router, so custom routes can be registered in the Sidecar router during both router:init andÂ router:startÂ events. ItÂ is recommended to register them in the Initialization eventÂ before any routing has occurred. There are two methods in the Sidecar Router, which allow for adding custom routes:
route()
Arguments
Name
Required
Type
Description
route
true
string
The Route pattern to be matched by the URL Fragment
name
true
stringÂ
The unique name of the Route
callback
true
functionÂ
The callback function for the Route
Example
The following example registers a custom Route during the router:init event, using the route() method.
./custom/javascript/customRoutes.js
(function(app){
    app.events.on("router:init", function(){
      //Register the route #test/123
      app.router.route("test/:id", "test123", function() {
          console.log(arguments);
          app.controller.loadView({
              layout: "custom_layout",
              create: true
          });
      });
    })
})(SUGAR.App);
addRoutes()


});
      });
    })
})(SUGAR.App);
addRoutes()
When you need to add multiple routes, you can define the routes in an array and pass the entire array to the addRoutes() method on the Sidecar Router to ensure they are registered. Please note, the addRoutes() method utilizes the above route() method to register the routes with the Backbone Router. The Backbone router redirectsÂ after the first matching route. Due to this, the order in which the routes are listed in the array is importantÂ as it will determine which route willÂ be used by the application. It is recommended that the most specific routes be listed first in the array so that they are recognized first, instead of those routes which may contain a variable.
Arguments
Name
Required
Type
Description
routes
true
array
An array of route definition as defined above.
Example
The following example registers custom Route during the router:init event, using the addRoutes() method.
TheÂ route's JavaScript controller can exist anywhere you'd like. For our purposes, we created it inÂ ./custom/javascript/customRoutes.js. This file will contain your custom route definitions.
./custom/javascript/customRoutes.js
(function(app){
    app.events.on("router:init", function(){
        var routes = [
    	    {
                route: 'test/doSomething',
                name: 'testDoSomething',
                callback: function(){
             	    alert("Doing something...");
                }
            },
            {
                route: 'test/:id',
                name: 'test123',
                callback: function(){
             	    console.log(arguments);
                    app.controller.loadView({
                        layout: "custom_layout",
                        create: true
                    });
                }
            }
        ];
        app.router.addRoutes(routes);
    })


}
            }
        ];
        app.router.addRoutes(routes);
    })
})(SUGAR.App);
Next, create the JSGrouping extension. This file will allow Sugar to recognize that you've added custom routes.Â
./custom/Extension/application/Ext/JSGroupings/myCustomRoutes.php
<?php
foreach ($js_groupings as $key => $groupings) {
Â Â Â  $target = current(array_values($groupings));
Â Â Â  //if the target grouping is found
Â Â Â  if ($target == 'include/javascript/sugar_grp7.min.js') {
Â Â Â Â Â Â Â  //append the custom JavaScript file
Â Â Â Â Â Â Â  $js_groupings[$key]['custom/javascript/customRoutes.js'] = 'include/javascript/sugar_grp7.min.js';
Â Â Â  }
}
Once your files are in place, navigate to Admin > Repairs > Quick Repair & Rebuild. For additional information, please refer to theÂ JSGroupingsÂ framework.
  	Last modified: 2023-02-03 21:04:03


Handlebars
Overview
The Handlebars library, located in ./sidecar/lib/handlebars/, is a JavaScript library that lets Sugar createÂ semantic templates. Handlebars help render content for layouts, views, and fields for Sidecar. Using Handlebars, you can make modifications to the display of content such as adding HTML or CSS.Â Â
For more information on the Handlebars library, please refer to their website atÂ http://handlebarsjs.com.Â
Templates
The Handlebars templates are stored in the filesystem as .hbs files. These files are stored along with the view, layout, and field metadata and are loaded according to the inheritanceÂ you have selected in your controller. To view the list of available templates, or to see if a custom-created template is available, you can open your browser's console window and inspect the Handlebars.templates namespace.
Debugging Templates
When working with Handlebar templates, it can be difficult to identify where an issue is occurring or what a variable contains. To assist with troubleshooting this, you can use the log helper. The log helper will output the contents of this and the variable passed to it in your browser's console.
This is an example of using the logger in aÂ handlebars template:
{{log this}}
Helpers
Handlebar Helpers are a way of adding custom functionality to the templates. Helpers are located in the following places:
./sidecar/src/view/hbs-helpers.jsÂ : Sidecar uses these helpers by default
./include/javascript/sugar7/hbs-helpers.jsÂ :Â Additional helpers used by the base client
Creating Helpers
When working with Handlebar templates, you may need to create your helper. To do this, follow these steps:


Create aÂ Handlebars helper file in theÂ ./custom/ directory. For this example, we will create two functions to convert a string to uppercase or lowercase:
./custom/JavaScript/my-handlebar-helpers.jsÂ
/**
 * Handlebars helpers.
 *
 * These functions are to be used in handlebars templates.
 * @class Handlebars.helpers
 * @singleton
 */
(function(app) {
    app.events.on("app:init", function() {
        /**
         * convert a string to upper case
         */
        Handlebars.registerHelper("customUpperCase", function (text)
        {
            return text.toUpperCase();
        });
        /**
         * convert a string to lower case
         */
        Handlebars.registerHelper("customLowerCase", function (text)
        {
            return text.toLowerCase();
        });
    });
})(SUGAR.App);
Next, create aÂ JSGrouping extension in ./custom/Extension/application/Ext/JSGroupings/.Â Name the file uniquely for your customization. For this example,Â we will create:
Â ./custom/Extension/application/Ext/JSGroupings/my-handlebar-helpers.php
<?php
//Loop through the groupings to find include/javascript/sugar_grp7.min.js
foreach($js_groupings as $key => $groupings) {
    foreach($groupings as $file => $target) {
        if ($target == 'include/javascript/sugar_grp7.min.js') {
            //append the custom helper file
            $js_groupings[$key]['custom/JavaScript/my-handlebar-helpers.js'] = 'include/javascript/sugar_grp7.min.js';
        }
        break;
    }
}
Finally, navigate to Admin > Repair and perform the following two repair sequences to include the changes:
Quick Repair and Rebuild


Quick Repair and Rebuild
Rebuild JS Groupings.
You can nowÂ use your custom helpers in the HBSÂ files by using:
{{customUpperCase "MyString"}}
{{customLowerCase "MyString"}}
Note: You can also access the helpers function from your browsers developer console usingÂ Handlebars.helpers
  	Last modified: 2023-02-03 21:04:03


Views
Overview
Views are component plugins that render data from a context. View components may contain field components and are typically made up of a controller JavaScript file (.js) and at least one Handlebars template (.hbs).
Load Order Hierarchy Diagram
The view components are loaded in the following manner:
Note: The Sugar application's client type is "base". For more information on the various client types, please refer toÂ the User Interface page.
Components
Views are made up of a controller and a Handlebar template.
Controller
The view's controller is what controls the view in how data is loaded, formatted, and manipulated. The controller is the JavaScript file named after the view. A controller file can be found in any of the directories shown in theÂ hierarchy diagramÂ above. In the example of the record view, the main controller file is located in ./clients/base/views/record/record.jsÂ and anyÂ modules extending this controller will have a file located in ./modules/<module>/clients/base/views/record/record.js. Â
Handlebar Template
The views template is built on Handlebars and is what adds the display markup forÂ the data. The template is typically named after the view or an action in the view. In the example of the record view, the main template us located in ./clients/base/views/record/record.hbs. This template will take the data fetched from the REST APIÂ to render the display forÂ the user. More information on templates can be found in the HandlebarsÂ section.
Extending Views


Extending Views
When working with module views, it is important to understand the difference between overriding and extending a view. Overriding is essentially creating or copyingÂ a view to be used by your application that is not extending its parent. By default, some module views already extend the core ./clients/base/views/record/record.js controller. An example of this is the accounts RecordView
./modules/Accounts/clients/base/views/record/record.js
({
    extendsFrom: 'RecordView',
    /**
     * @inheritdoc
     */
    initialize: function(options) {
        this.plugins = _.union(this.plugins || [], ['HistoricalSummary']);
        this._super('initialize', [options]);
    }
})
As you can see, this view has the property:Â extendsFrom: 'RecordView'. This property tells Sidecar that the view is going to extend its parent RecordView. In addition to this, you can see that the initialize method is also callingÂ this._super('initialize', [options]);. Calling this._super tells SidecarÂ to execute the parent function. The major benefit of doing this is that any updates to ./clients/base/views/record/record.js will be reflected for the module withoutÂ any modifications being made to ./modules/Accounts/clients/base/views/record/record.js. You should note that when using extendsFrom, the parent views are calledÂ similarly to the load hierarchy:Â
Â
Create View and Record View Inheritance
The diagram below demonstrates the inheritance of the create and record views for the Quotes module. This inheritance structure is the same for stock and custom modules alike.Â
Basic View Example


Basic View Example
A simple view for beginners is the access-denied view. The view is located in ./clients/base/views/access-denied/ and is what handles the display for restricted access. The sections below will outline the various files that render this view.
Controller
The access-denied.js, shown below, controls the manipulation actionsÂ of the view.
./clients/base/views/access-denied/access-denied.js
({
    className: 'access-denied tcenter',
    cubeOptions: {spin: false},
    events: {
        'click .sugar-cube': 'spinCube'
    },
    spinCube: function() {
        this.cubeOptions.spin = !this.cubeOptions.spin;
        this.render();
    }
})
Attributes
Attribute
Description
className
The CSS class to apply to the view.
cubeOptions
A set of options that are passed to the spinCube function when called.
events
A list of the view events. This view executes the spinCube function when the sugar cube is clicked.
spinCube
Function to control the start and stop of the cube spinning.
Handlebar Template
The access-denied.hbs file defines the format of the views content. As this view is used for restricting access, it displays a message to the user describing the restriction.
./clients/base/views/access-denied/access-denied.hbs

{{str 'ERR_NO_VIEW_ACCESS_TITLE'}}

{{str 'ERR_NO_VIEW_ACCESS_REASON'}}

{{str 'ERR_NO_VIEW_ACCESS_ACTION'}}

{{{subFieldTemplate 'sugar-cube' 'detail' cubeOptions}}}
Helpers
Name
Description
str
Handlebars helper to render the label string
subFieldTemplate


Name
Description
str
Handlebars helper to render the label string
subFieldTemplate
Handlebars helper to render the cube content
Cookbook Examples
When working with views, you may find the follow cookbook examples helpful:
Adding Buttons to the Record View
Adding Field Validation to the Record View
Passing_Data_to_Templates
TopicsMetadataThis page is an overview of the metadata framework for Sidecar modules.
  	Last modified: 2023-02-03 21:04:03


Metadata
Overview
This page is an overview of the metadata framework for Sidecar modules.
View Metadata Framework
A module's view-specific metadata can be found in the modules view file:
./modules/<module>/clients/<client>/views/<view>/<view>.php
Any edits made in Admin > Studio will be reflected in the file:
./custom/modules/<module>/clients/<client>/views/<view>/<view>.php
Note: The Sugar application's client type is "base". For more information on the various client types, please refer to the User Interface page.
Note: In the case of metadata, custom view metadata files are respected over the stock view metadata files.
View Metadata
The Sidecar views metadata is very similar to that of the MVC metadata, however, there are some basic differences. All metadata for Sidecar follows the format:
$viewdefs['<module>']['base']['view']['<view>'] = array();
An example of this is the account's record layout shown below:
./modules/Accounts/clients/base/views/record/record.php
<?php
$viewdefs['Accounts']['base']['view']['record'] = array(
    'panels' => array(
        array(
            'name' => 'panel_header',
            'header' => true,
            'fields' => array(
                array(
                    'name'          => 'picture',
                    'type'          => 'avatar',
                    'width'         => 42,
                    'height'        => 42,
                    'dismiss_label' => true,
                    'readonly'      => true,
                ),
                'name',
                array(
                    'name' => 'favorite',
                    'label' => 'LBL_FAVORITE',
                    'type' => 'favorite',
                    'dismiss_label' => true,
                ),
                array(


'dismiss_label' => true,
                ),
                array(
                    'name' => 'follow',
                    'label'=> 'LBL_FOLLOW',
                    'type' => 'follow',
                    'readonly' => true,
                    'dismiss_label' => true,
                ),
            )
        ),
        array(
            'name' => 'panel_body',
            'columns' => 2,
            'labelsOnTop' => true,
            'placeholders' => true,
            'fields' => array(
                'website',
                'industry',
                'parent_name',
                'account_type',
                'assigned_user_name',
                'phone_office',
            ),
        ),
        array(
            'name' => 'panel_hidden',
            'hide' => true,
            'columns' => 2,
            'labelsOnTop' => true,
            'placeholders' => true,
            'fields' => array(
                array(
                    'name' => 'fieldset_address',
                    'type' => 'fieldset',
                    'css_class' => 'address',
                    'label' => 'Billing Address',
                    'fields' => array(
                        array(
                            'name' => 'billing_address_street',
                            'css_class' => 'address_street',
                            'placeholder' => 'LBL_BILLING_ADDRESS_STREET',
                        ),
                        array(
                            'name' => 'billing_address_city',
                            'css_class' => 'address_city',
                            'placeholder' => 'LBL_BILLING_ADDRESS_CITY',
                        ),
                        array(
                            'name' => 'billing_address_state',
                            'css_class' => 'address_state',
                            'placeholder' => 'LBL_BILLING_ADDRESS_STATE',
                        ),


'placeholder' => 'LBL_BILLING_ADDRESS_STATE',
                        ),
                        array(
                            'name' => 'billing_address_postalcode',
                            'css_class' => 'address_zip',
                            'placeholder' => 'LBL_BILLING_ADDRESS_POSTALCODE',
                        ),
                        array(
                            'name' => 'billing_address_country',
                            'css_class' => 'address_country',
                            'placeholder' => 'LBL_BILLING_ADDRESS_COUNTRY',
                        ),
                    ),
                ),
                array(
                    'name' => 'fieldset_shipping_address',
                    'type' => 'fieldset',
                    'css_class' => 'address',
                    'label' => 'Shipping Address',
                    'fields' => array(
                        array(
                            'name' => 'shipping_address_street',
                            'css_class' => 'address_street',
                            'placeholder' => 'LBL_SHIPPING_ADDRESS_STREET',
                        ),
                        array(
                            'name' => 'shipping_address_city',
                            'css_class' => 'address_city',
                            'placeholder' => 'LBL_SHIPPING_ADDRESS_CITY',
                        ),
                        array(
                            'name' => 'shipping_address_state',
                            'css_class' => 'address_state',
                            'placeholder' => 'LBL_SHIPPING_ADDRESS_STATE',
                        ),
                        array(
                            'name' => 'shipping_address_postalcode',
                            'css_class' => 'address_zip',
                            'placeholder' => 'LBL_SHIPPING_ADDRESS_POSTALCODE',
                        ),
                        array(
                            'name' => 'shipping_address_country',
                            'css_class' => 'address_country',
                            'placeholder' => 'LBL_SHIPPING_ADDRESS_COUNTRY',
                        ),
                        array(
                            'name' => 'copy',


),
                        array(
                            'name' => 'copy',
                            'label' => 'NTC_COPY_BILLING_ADDRESS',
                            'type' => 'copy',
                            'mapping' => array(
                                'billing_address_street' => 'shipping_address_street',
                                'billing_address_city' => 'shipping_address_city',
                                'billing_address_state' => 'shipping_address_state',
                                'billing_address_postalcode' => 'shipping_address_postalcode',
                                'billing_address_country' => 'shipping_address_country',
                            ),
                        ),
                    ),
                ),
                array(
                    'name' => 'phone_alternate',
                    'label' => 'LBL_OTHER_PHONE',
                ),
                'email',
                'phone_fax',
                'campaign_name',
                array(
                    'name' => 'description',
                    'span' => 12,
                ),
                'sic_code',
                'ticker_symbol',
                'annual_revenue',
                'employees',
                'ownership',
                'rating',
                array(
                    'name' => 'date_entered_by',
                    'readonly' => true,
                    'type' => 'fieldset',
                    'label' => 'LBL_DATE_ENTERED',
                    'fields' => array(
                        array(
                            'name' => 'date_entered',
                        ),
                        array(
                            'type' => 'label',
                            'default_value' => 'LBL_BY',
                        ),
                        array(
                            'name' => 'created_by_name',
                        ),
                    ),
                ),
                'team_name',
                array(
                    'name' => 'date_modified_by',
                    'readonly' => true,
                    'type' => 'fieldset',


'readonly' => true,
                    'type' => 'fieldset',
                    'label' => 'LBL_DATE_MODIFIED',
                    'fields' => array(
                        array(
                            'name' => 'date_modified',
                        ),
                        array(
                            'type' => 'label',
                            'default_value' => 'LBL_BY',
                        ),
                        array(
                            'name' => 'modified_by_name',
                        ),
                    ),
                ),
            ),
        ),
    ),
);
The metadata for a given view can be accessedÂ using app.metadata.getViewÂ within your controller. An example fetching the view metadata for the Accounts RecordView is shown below:
app.metadata.getView('Accounts', 'record');
You should note that this can also be accessed in your browser's console window by using the global App Identifier:
App.metadata.getView('Accounts', 'record');
  	Last modified: 2023-02-03 21:04:03


MainLayout
Overview
Sugar's Main navigation is split into two components: Top-Header and Sidebar. The Top-Header is primarily used for search, notifications, and user actions and the Sidebar is the primary tool usedÂ toÂ navigate the front end of the Sugar application.
Layout Components
The Main layout isÂ composed of Top-Header (header-nav) and Sidebar/Rail (sidebar-nav) layouts, and each of those layouts host views.Â
Top Header (header-nav)
The Top Header (header-nav) layout, located in ./clients/base/layouts/header-nav/header-nav.php, is composed of theÂ quicksearch layout as well as the header-nav-logos,Â Â notifications, profileactionsÂ views. To customize these components, you can create your own layout by extending it atÂ ./custom/Extension/application/Ext/custom/clients/base/layouts/header-nav/header-nav.php to reference your own custom components.
Â
Sidebar/Rail (sidebar-nav)
The Sidebar/Rail layout hosts overall Menu options by grouping them into layouts separated by a line/divisor within the sidebar-nav definition.
Rail is collapsed by default and contains two main clickable actions: Primary and Secondary.Â
Link Actions
The following properties define theÂ navigation, display, and visibility of all links in the system:
Name
Description
acl_action
The ACL action is used to verify the user has access to a specific actionÂ required for theÂ link
acl_module
The ACL moduleÂ is used to verify if the user has access to a specific module required for the link
icon
The bootstrap icon to display next to the link (the full list of icons are listedÂ in Admin > Styleguide > Core Elements > Base CSS > Icons)
label
The label key that contains your link's display text
openwindow


label
The label key that contains your link's display text
openwindow
Specifies whether or not the link shouldÂ open in a new window
route
The route to direct the user. For sidecar modules, this is #<module>,Â butÂ modules in backward compatibility mode are routed as #bwc/index.php?module=<module>. Note:Â External linksÂ require the full URL as well as openwindow set to true.
flyoutComponents
An array of sub-navigation linksNote:Â Sub-navigation links contain these same basicÂ link properties.
Primary Action
PrimaryÂ actions are triggered by the click of a button on theÂ sidebar-nav'sÂ views. By default if aÂ routeÂ property is provided in the view object in the layout metadata, the Primary Action will be a link to the route provided. For example:
$viewdefs[...] = [
    'layout' => [
        'type' => 'sidebar-nav-item-group',
        'name' => 'sidebar-nav-item-group-bottom',
        'css_class' => 'flex-grow-0 flex-shrink-0',
        'components' => [
            [
                'view' => [
                    'name' => 'greeting-nav-item',
                    'type' => '<some-custom-view>',
                    'route' => '#Accounts',
                    ...
                ],
            ],
        ],
    ],
];
Otherwise, if you're using a custom view and the controller has aÂ primaryActionOnClickÂ method defined, that will be used in addition to theÂ routeÂ property.Â
Secondary Action


Secondary Action
With the introduction of the sidebar-nav-item component, we're now introducing secondary actions. These appear by way of a kebab menu when hovering on theÂ sidebar-nav-itemÂ container to which they are added.Â Secondary Actions do haveÂ some default behavior. If the template has the following markup present, the kebab will render on hover:
<button class="sidebar-nav-item-kebab bg-transparent absolute p-0 h-full">
   <i class="{{buildIcon 'sicon-kebab'}} text-white"></i>
</button>
If metadata is provided with certain keys, clicking on the kebab icon will render a flyout menu, for example, a metadata definition such as:
<?php
$viewdefs['base']['layout']['sidebar-nav']['components'][] = [
    'layout' => [
        'type' => 'sidebar-nav-item-group',
        'name' => 'sidebar-nav-item-group-bottom',
        'css_class' => 'flex-grow-0 flex-shrink-0',
        'components' => [
            [
                'view' => [
                    'name' => 'greeting-nav-item',
                    'type' => 'greeting-nav-item',
                    'route' => '#Accounts',
                    'icon' => 'sicon-bell-lg',
                    'label' => 'Hello!',
                    'flyoutComponents' => [
                        [
                            'view' => 'sidebar-nav-flyout-header',
                            'title' => 'Greetings',
                        ],
                        [
                            'view' => [
                                'type' => 'sidebar-nav-flyout-actions',
                                'actions' => [
                                    [
                                        'route' => '#Accounts',
                                        'label' => 'LBL_ACCOUNTS',
                                        'icon' => 'sicon-account-lg',
                                    ],
                                ],


'icon' => 'sicon-account-lg',
                                    ],
                                ],
                            ],
                        ],
                    ],
                ],
            ],
        ],
    ],
];
The flyoutComponents array will render all the views that are passed to it. In this case, we load aÂ sidebar-nav-item-headerÂ component and aÂ sidebar-nav-item-flyout-actionsÂ component. Similar to a Primary Action, you can override the defaultÂ secondaryActionOnClickÂ method in your custom view controller to change the behavior of clicking on the kebab menu.Â
$viewdefs[...] = [
    'layout' => [
        'type' => 'sidebar-nav-item-group',
        'name' => 'sidebar-nav-item-group-bottom',
        'css_class' => 'flex-grow-0 flex-shrink-0',
        'components' => [
            [
                'view' => [
                    'name' => 'greeting-nav-item',
                    'type' => 'greeting-nav-item',
                    'route' => '#Accounts',
                    ...
                ],
            ],
        ],
    ],
];
Â
The following components define how the Sidebar/Rail layout is displayed.
Home
The first group before the line/divisor contains the "hamburger" icon menu whose sole purpose is to expand/collapse the side nav.
The second group contains:
Home menu dedicated to Dashboards
Quick Create menu dedicated to creating new records
Home Menu


Home menu dedicated to Dashboards
Quick Create menu dedicated to creating new records
Home Menu
The Home menu view is composed of the sidebar-nav-flyout-module-menuÂ (responsible to display the Secondary Action menus with dashboards and recent items),Â sidebar-nav-item-moduleÂ (responsible to display the menu's title) views. To customize these components, you can create your own layout by extending them atÂ ./custom/Extension/application/Ext/custom/clients/base/viewsÂ and locating its folder with the same nameÂ for your own custom components.
Quick Create
Â
Quick Create view has been redesigned and presents the modules on click.
Note this view does not require secondary action as others do with submenu
Quick Create View
The Quick Create view is composed of the sidebar-nav-item-quickcreateÂ (responsible to display the Quick Create menu and its icon),Â sidebar-nav-flyout-headerÂ (responsible to display the menu's title) and sidebar-quickcreateÂ (responsible to display Secondary Action/submenu) views. To customize these components, you can create your own layout by extending them atÂ ./custom/Extension/application/Ext/custom/clients/base/viewsÂ and locating its folder with the same nameÂ for your own custom components.
Modules


Modules
The Modules layout, located in ./clients/base/layouts/sidebar-nav-item-group-modules/sidebar-nav-item-group-modules.js, contains the logic to load modules metadata, build the module list and display them accordingly depending on the Sidebar/Rail state (expanded or collapsed) as well as respect the Pinned Items and order it should be displayed.Â To customize this component, you can create your own by extending it atÂ ./custom/Extension/application/Ext/custom/clients/base/layouts/sidebar-nav-item-group-modules/sidebar-nav-item-group-modules.js,Â to reference your own custom logic and make sure you extend from the view SidebarNavItemModuleView or layoutÂ SidebarNavItemGroupModulesLayout
Â
Â
if (isset($viewdefs['<module>']['base']['menu']['header'])) {
    foreach ($viewdefs['<module>']['base']['menu']['header'] as $key => $moduleAction) {
        //remove the link by label key
        if (in_array($moduleAction['label'], array('<link label key>'))) {
            unset($viewdefs['<module>']['base']['menu']['header'][$key]);
        }
    }
}
Once you have created theÂ extension files, navigate to Admin > Repair > Quick Repair and Rebuild.Â This willÂ removeÂ theÂ menuÂ actionÂ item from the existing list of links.
Â
Profile Action Links
Profile actions are the links listed under the user's profile menu on the right side of the Top Header. Profile action extension files areÂ located inÂ ./custom/Extension/application/Ext/clients/base/views/profileactions/ and are compiled into Â ./custom/application/Ext/clients/base/views/profileactions/profileactions.ext.php.
Adding Profile Action Links


Adding Profile Action Links
The example below demonstrates how to add a profile action link to the Styleguide. To define your own profile action link, create your own label extension for the link's display label.Â
./custom/Extension/application/Ext/Language/en_us.addProfileActionLink.php
<?php
//create the links label
$app_strings['LNK_STYLEGUIDE_C'] = 'Styleguide';
Next, create theÂ profile action link extension:
./custom/Extension/application/Ext/clients/base/views/profileactions/addProfileActionLink.php
<?php
$viewdefs['base']['view']['profileactions'][] = array(
    'route' => '#Styleguide',
    'label' => 'LNK_STYLEGUIDE_C',
    'icon' => 'icon-link',
);
Once you have created theÂ extension files, navigate to Admin > Repair > Quick Repair and Rebuild.Â This will append your profile actionÂ item to the existing list of links.
Note: You may need to refresh the page to see the new profile menu items.
Removing Profile Action Links
To remove a profile action link, loop through the list of profile actions and remove the item by one of its properties. For your reference, the stock profile actions can be found in ./clients/base/views/profileactions/profileactions.php.
./custom/Extension/application/Ext/clients/base/views/profileactions/removeProfileActionLink.php
<?php
if (isset($viewdefs['base']['view']['profileactions'])) {
    foreach ($viewdefs['base']['view']['profileactions'] as $key => $profileAction) {
        //remove the link by label key
        if (in_array($profileAction['label'], array('LNK_ABOUT'))) {
            unset($viewdefs['base']['view']['profileactions'][$key]);
        }
    }
}


}
    }
}
Once you have created theÂ extension files, navigate to Admin > Repair > Quick Repair and Rebuild.Â This will removeÂ theÂ profile actionÂ item from the existing list of links.
Note:Â You may need to refresh the page to see the profile menu items removed.
  	Last modified: 2023-02-03 21:04:03


Drawers
Overview
The drawer layout widget, located in ./clients/base/layouts/drawer/, is used to display a window of additional content to the user. This window can then be closed to display the content the user was previously viewing.
Methods
app.drawer.open(layoutDef, onClose)
The app.drawer.open(layoutDef, onClose) methodÂ displays a new content window over the current view.
Parameters
Name
Required
Description
layoutDef.layout
yes
The id of the layout to load.
layoutDef.context
no
Additional data you would like to pass to the drawer. Data passed in can be retrieved from the view using:
this.context.get('<data key>');
Note: Be very careful about what you pass in as data to the drawer. As the data is passed in by reference, when the drawer is closed, the context is destroyed.
onClose
no
Optional callback handler for when the drawer is closed.
Example
app.drawer.open({
    layout: 'my-layout',
    context: {
        myData: data
    },
},
function() {
    //on close, throw an alert
    alert('Drawer closed.');
});
app.drawer.close(callbackOptions)
The app.drawer.close(callbackOptions) method dismisses the topmost drawer.
Parameters
Name
Required
Description
callbackOptions
no
Any parameters passed into the close method will be passed to the callback.
Standard Example
app.drawer.close();
Callback Example
//open drawer
app.drawer.open({
    layout: 'my-layout',
},
function(message1, message2) {
    alert(message1);
    alert(message2);
});
//close drawer
app.drawer.close('message 1', 'message 2');
app.drawer.load(options)
Loads a new layout into an existing drawer.
Parameters
Name
Description
options.layout


Loads a new layout into an existing drawer.
Parameters
Name
Description
options.layout
The id of the layout to load.
Example
app.drawer.load({
    layout: 'my-second-layout',
});
app.drawer.reset(triggerBefore)
The app.drawer.reset(triggerBefore) method destroys all drawers at once. By default, whenever the application is routed to another page, reset() is called.
Parameters
Name
Required
Description
triggerBefore
no
Determines whether to triggerBefore. Defaults to false.
Example
app.drawer.reset();
  	Last modified: 2023-02-03 21:04:03


Fields
Â
Overview
Fields are component plugins that render and format field values. TheyÂ are made up of a controller JavaScript file (.js) and at least one Handlebars template (.hbt). For more information regarding the data handling of a field, please refer the data framework fields documentation. For information on creating custom field types, please refer the Creating Custom Field Types cookbook example.
Hierarchy Diagram
The field components are loaded in the following manner:
Note: The Sugar application's client type is "base". For more information on the various client types, please refer toÂ the User Interface page.
Field Example
The bool field, located in ./clients/base/fields/bool/, handles the display ofÂ checkbox boolean values. The sections below outline the various files that render this field type.
Controller
The bool.js, file is shown below, overrides the base _render function to disable the field. The format and unformat functions handle the manipulation of the field's value.
./clients/base/fields/bool/bool.js
({
    _render: function() {
        app.view.Field.prototype._render.call(this);
        if(this.tplName === 'disabled') {
            this.$(this.fieldTag).attr("disabled", "disabled");
        }
    },
    unformat:function(value){
        value = this.$el.find(".checkbox").prop("checked") ? "1" : "0";
        return value;
    },
    format:function(value){
        value = (value=="1") ? true : false;
        return value;
    }
})
Attributes
Attribute
Description
_render
Function to render the field.
unformat
Function to dynamically check the checkbox based on the value.
format
Function to format the value for storing in the database.
Handlebar Templates


format
Function to format the value for storing in the database.
Handlebar Templates
The edit.hbs file defines the display of the control when the edit view is used. This layout is for displaying the editable form element that renders a clickable checkbox control for the user.
./clients/base/fields/bool/edit.hbs
{{#if def.text}}
    <label>
        <input type="checkbox" class="checkbox"{{#if value}} checked{{/if}}> {{str def.text this.module}}
    </label>
{{else}}
    <input type="checkbox" class="checkbox"{{#if value}} checked{{/if}}>
{{/if}}
Helpers
Helpers
Description
str
Handlebars helper to render the label string.
The detail.hbs file defines the display of the control when the detail view is used. This layout is for viewing purposes only so the control is disabled by default.
./clients/base/fields/bool/detail.hbs
<input type="checkbox" class="checkbox"{{#if value}} checked{{/if}} disabled>
The list.hbs file defines the display of the control when the list view is used. This view is also for viewing purposes only so the control is disabled by default.
./clients/base/fields/bool/list.hbs
<input type="checkbox" class="checkbox"{{#if value}} checked{{/if}} disabled>
Cookbook Examples
When working with fields, you may find the follow cookbook examples helpful:
Creating Custom Field Types
Converting Address' Country Field to a Dropdown
  	Last modified: 2023-02-03 21:04:03


Architecture
Overview
This section of Sugar's Developer Guide begins with a high-level overview of the Sugar platform's architecture and contains documentation on granular concepts in Sugar such as logic hooks, caching, logging, extensions, job queue, and more.
Please continue to the bottom of this page or use the navigation on the left to exploreÂ the related content.
Platform
SugarÂ® is built on open standards and technology such as HTML5, PHP, and JavaScript, and runs on a variety of free and open-source technology like Linux, MySQL, and Elasticsearch. The Sugar platform also supports common proprietary databases such as Oracle, IBM DB2, and Microsoft SQL Server.
All of Sugar's customers and partners have access to source code that they can choose to deploy on-premise or utilize Sugar's cloud service for a SaaS deployment.
Out of the box, Sugar uses a consistent platform across all clients and devices (e.g. mobile, web, plug-ins, etc.).
Front-End Framework
Our clients are based on a front-end framework called Sidecar. Sidecar is built on open source technology: Backbone.js, jQuery, Handlebars.js, and Bootstrap. The Sidecar framework provides a responsive UI (to support a variety of form factors) and uses modern, single-page client architecture. Sugar clients connect to Sugar server application via our client REST API. The REST API is implemented in PHP and drives server-side business logic and interacts with a database. If it can be accomplished via one of our clients, then its equivalent functionality can be accomplished using our REST API.
The Sugar platform uses modules. Modules are a vertically integrated application component that is traditionally organized around a single feature or record type (or underlying database table). For example, contact records are managed via a Contacts module that contains all the business logic, front-end interface definitions, REST APIs, data schema,Â andÂ relationships with other modules.


Custom modules can be created and deployed as needed in order to add new features to a Sugar application instance.Â
Metadata
Sugar's modules are defined primarily using Metadata. There are two types of metadata definitions within Sugar: Vardefs, which define the data model for Sugar modules; and Viewdefs, which define the user interface components that are used with a module.
Sugar Metadata is implemented as PHP files that can be modified directly by a Sugar Developer making filesystem changes, or indirectly through the use of Sugar Studio and Module Builder by a Sugar Administrator.
Metadata allows you to configure solutions instead of having to write countless lines of custom code in order to implement common customizations such as adding custom fields, calculated values, and changing user interface layouts.
Extensions
Beyond metadata, Sugar is highly customizable and includes an extensive Extensions Framework that provides Sugar Developers the capability to contribute to pre-defined extension points within the application in a way that is upgrade-safe and will not conflict with other customizations that exist in the system.


TopicsAutoloaderThe autoloader is an API that allows the unified handling of customizations and customizable metadata while reducing the number of filesystem accesses and improving performance.CachingMuch of Sugar's user interface is built dynamically using a combination of templates, metadata and language files. A file caching mechanism improves the performance of the system by reducing the number of static metadata and language files that need to be resolved at runtime. This cache directory stores the compiled files for JavaScript files, Handlebars templates, and language files.UploadsThe upload directory is used to store files uploaded for imports, attachments, documents, and module loadable packages.EmailOutlines the relationships between emails, email addresses, and bean records.Email AddressesRecommended approaches when working with email addresses in Sugar.LoggingThere are two logging systems implemented in the Sugar application: SugarLogger and PSR-3. PSR-3 is Sugar's preferred logger solution and should be used going forward.Logic HooksThe Logic Hook framework allows you to append actions to system events such as when creating, editing, and deleting records.LanguagesSugar as an application platform is internationalized and localizable. Data is stored and presented in the UTF-8 codepage, allowing for all character sets to be used. Sugar provides a language-pack framework that allows developers to build support for any language in the display of user interface labels. Each language pack has its own set of display strings which is the basis of language localization. You can add or modify languages using the information in this guide.ExtensionsThe extension framework, defined in ./ModuleInstall/extensions.php, provides the capability to modify Sugar metadata such as vardefs and layouts in a safe way that supports installing, uninstalling, enabling, and disabling without interfering with other customizations.FiltersFilters are a way to predefine searches on views that render a list of records such as list views, pop-up searches, and lookups. This page explains how to implement the various types of filters for record list views.Duplicate CheckThe duplicate-check framework provides the capability


implement the various types of filters for record list views.Duplicate CheckThe duplicate-check framework provides the capability to alter how the system searches for duplicate records in the database when creating records. For information on duplicate checking during imports, please refer to the index documentation.Elastic SearchThe focus of this document is to guide developers on how Sugar integrates with Elastic Search.Global SearchHow to customize the global search results.Sugar LogicSugar Logic, a feature in all Sugar products, enables custom business logic that is easy to create, manage, and reuse on both the server and client.AdministrationThe Administration class is used to manage settings stored in the database config table.ConfiguratorThe Configurator class, located in ./modules/Configurator/Configurator.php, handles the config settings found in ./config.php and ./config_override.php.Module LoaderModule Loader is used when installing customizations, plugins,language packs, and hotfixes, and other customizations into a Sugar instance in the form of a Module Loadable Package. This documentation covers the basics and best practices for creating module loadable packages for a Sugar installation.Module BuilderThe Module Builder tool allows programmers to create custom modules without writing code and to create relationships between new and existing CRM modules. To illustrate how to use Module Builder, this article will show how to create and deploy a custom module.QuotesAs of Sugar 7.9.0.0, the quotes module has been moved out of Backward Compatibility mode into Sidecar. Customizations to the Quotes interface will need to be rewritten for the new Sidecar framework as an automated migration of these customizations is not possible. This document will outline common customizations and implementation methods.SugarBPMSugarBPMâ¢ automation suite is the next-generation workflow management tool for Sugar. Introduced in 7.6, SugarBPM is loosely based on BPMN process notation standards and provides a simple drag-and-drop user interface along with an intelligent flow designer to allow for the creation of easy yet powerful process


user interface along with an intelligent flow designer to allow for the creation of easy yet powerful process definitions.Entry PointsEntry points, defined in ./include/MVC/Controller/entry_point_registry.php, were used to ensure that proper security and authentication steps are applied consistently across the entire application. While they are still used in some areas of Sugar, any developers using custom entry points should adjust their customizations to use the latest REST API endpoints instead.Job QueueThe Job Queue executes automated tasks in Sugar through a scheduler, which integrates with external UNIX systems and Windows systems to run jobs that are scheduled through those systems. Jobs are the individual runs of the specified function from a scheduler.Access Control ListsAccess Control Lists (ACLs) are used to control access to the modules, data, and actions available to users in Sugar. By default, Sugar comes with a default ACL Strategy that is configurable by an Admin through the Roles module via Admin > Role Management. Sugar also comes with other ACL strategies that are located in the ./data/acl/ folder, and are used in other parts of the system such as the Administration module, Emails module, Locked Fields functionality, and many others. They can also be leveraged by customizations and custom ACL strategies can be implemented to control your own customizations.TeamsTeams provide the ability to limit access at the record level, allowing sharing flexibility across functional groups. Developers can manipulate teams programmatically provided they understand Sugar's visibility framework.TagsThe tagging feature allows a user to apply as many "tags" as they choose on any record they want to categorize. This allows the user to effectively group records together from any source within the application and relate them together. Please note that the tag field and Tags module do not support customization at this time.TinyMCEThis section contains information about working with the TinyMCE editor in Sugar.SugarPDFThis section contains information on generating PDFs and configuring PDF settings and fonts in Sugar.DateTimeThe SugarDateTime class, located in,


generating PDFs and configuring PDF settings and fonts in Sugar.DateTimeThe SugarDateTime class, located in, ./include/SugarDateTime.php, extends PHP's built in DateTime class and can be used to perform common operations on date and time values.ShortcutsShortcuts is a framework to add shortcut keys to the application. When shortcut keys are registered, they are registered to a particular shortcut session. Shortcut sessions group shortcut keys, and they can be activated, deactivated, saved, and restored. Global shortcut keys can be registered, but they are not tied to a particular shortcut session. They are rather applied everywhere in the application and can only be applied once.ThemesHow to customize the Sugar theme.Web AccessibilityLearn about the Sugar Accessibility Plugin for Sidecar.Validation ConstraintsThis article will cover how to add validation constraints to your custom code.CLISugar on-premise deployments include a command line interface tool built using the Symfony Console Framework. Sugar's CLI is intended to be an administrator or developer level power tool to execute PHP code in the context of Sugar's code base. These commands are version specific and can be executed on a preinstalled Sugar instance or on an installed Sugar instance. Sugar's CLI is not intended to be used as a tool to interact remotely with an instance nor is it designed to interact with multiple instances.Performance TuningThe Performance Tuning section contains information that will help maximize system performance for your Sugar instance.Backward CompatibilityAs of SugarÂ® 7, modules are built using the Sidecar framework. Any modules that still use the MVC architecture and have not yet migrated to the Sidecar framework are set in what Sugar refers to as "backward compatibility" (BWC) mode.


Last modified: 2023-02-03 21:04:03


Extensions
Overview
The extension framework,Â defined inÂ ./ModuleInstall/extensions.php, provides the capability to modify Sugar metadata such as vardefs and layouts in a safe way that supports installing, uninstalling, enabling, and disabling without interfering with other customizations.
Application extensions are stored under ./custom/Extension/application/Ext/ and module extensions are under ./custom/Extension/modules/<module>/Ext/. The files in each of these directories are aggregated into a single file with a predefined name for the system to use. An example of this is the vardefs extension. The vardef extension directory for Accounts is located in ./custom/Extension/modules/Accounts/Ext/Vardefs/. When a module is installed, uninstalled, enabled, or disabled, the files contained in this directory are merged into ./custom/modules/Accounts/Ext/Vardefs/vardefs.ext.php. A Quick Repair & Rebuild will also cause the files to merge.
The core extension mappings are listed in the Topics section at the bottom of this page.
Extensions Properties
Each extension contains the following properties:
Property
Description
Extension Scope
AllÂ : Extension can be applied to the ./custom/application/ or ./custom/<module>/ directory
ApplicationÂ : Extension can only be applied to the ./custom/application/ directory
ModuleÂ : Extension can only be applied to the ./custom/<module>/ directory
DefinitionÂ Variable
The variable that SugarÂ for utilizing the extension definition. If defined, this variable must be set with the appropriate definition properties.
Extension Directory
The directory that the extension compiles files from
If the customization is for the application, the extension file should be placed in ./custom/Extension/application/Ext/<extension_directory>/
If the customization is for a module, the extension file should be placed in ./custom/Extension/modules/<module>/Ext/<extension_directory>/
Compiled Extension File
The name of the compiled extension file


Compiled Extension File
The name of the compiled extension file
If the extension is for the application, the compiled file will be located in ./custom/application/Ext/<extension>/<extension>.ext.php
If the extension is for a module, the compiled file will be located in ./custom/modules/<module>/Ext/<extension>/<extension>.ext.php
Manifest Installdef
The index of the $installdef in the manifest file for module loadable packages.


TopicsActionFileMapThe ActionFileMap extension maps actions to files, which helps you map a file to a view outside of ./custom/modules/<module>/views/view.<name>.php. This page is only applicable to modules running in backward compatibility mode.ActionReMapThe ActionReMap extension maps new actions to existing actions. This extension is only applicable to modules running in backward compatibility mode.ActionViewMapThe ActionViewMap extension maps additional actions for a module.AdministrationThe Administration extension adds new panels to Sugar's Administration page.Application SchedulersApplication Scheduler extensions add custom functions that can be used by scheduler jobs.ConsoleThe Console extension adds custom CLI commands to Sugar. More information on creating custom commands can be found in the CLI documentation.DependenciesDependencies create dependent actions for fields and forms that can leverage more complicated logic.EntryPointRegistryThe EntryPointRegistry extension maps additional entry points to the system. Please note that entry points will soon be deprecated. Developers should move custom logic to endpoints. For more information, please refer to the Entry Points page.ExtensionsThis extension allows for developers to create custom extensions within the framework. Custom extensions are used alongside the extensions found in ./ModuleInstaller/extensions.php.FileAccessControlMapThe FileAccessControlMap extension restricts specific view actions from users of the system.IncludeThe Modules extension maps additional modules in the system, typically when Module Builder deploys a module.JSGroupingsThe JSGroupings extension allows for additional JavaScript grouping files to be created or added to existing groupings within the system.LanguageThe Language extension adds or overrides language strings.LayoutdefsThe Layoutdefs extension adds or overrides subpanel definitions.LogicHooksThe LogicHooks extension adds actions to specific events such as, for example, before saving a bean. For more information on logic hooks in Sugar, please refer to the Logic Hooks documentation.ModulesThe Modules extension maps additional modules in the system, typically when Module Builder deploys a module.PlatformsThe Platforms extension adds allowed REST API platforms when restricting custom platforms through the use of the disable_unknown_platforms


Platforms extension adds allowed REST API platforms when restricting custom platforms through the use of the disable_unknown_platforms configuration setting.ScheduledTasksThe ScheduledTasks extension adds custom functions that can be used by scheduler jobs. For more information about schedulers in Sugar, please refer to the Schedulers documentation.SidecarThe Sidecar extension installs metadata files to their appropriate directories.TinyMCEThe TinyMCE extension affects the TinyMCE WYSIWYG editor's configuration for backward compatible modules such as PDF Manager and Campaign Email Templates.UserPageThe UserPage extension adds sections to the User Management view.UtilsThe Utils extension adds functions to the global utility function list.VardefsThe Vardefs extension adds or overrides system vardefs, which provide the Sugar application with information about SugarBeans.WirelessLayoutdefsThe WirelessLayoutdefs extension adds additional subpanels to wireless views. This extension is only applicable to modules running in backward compatibility mode.WirelessModuleRegistryThe WirelessModuleRegistry extension adds modules to the available modules for mobile.


This page refers to content that is only available in modules running in backward compatibility mode.
ActionFileMap
Overview
The ActionFileMap extension maps actions to files, which helpsÂ you map a file to a view outside of ./custom/modules/<module>/views/view.<name>.php. This page is only applicable to modules running in backward compatibility mode.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Module
Sugar Variable
$action_file_map
Extension Directory
./custom/Extension/modules/<module>/Ext/ActionFileMap/
Compiled Extension File
./custom/<module>/Ext/ActionFileMap/action_file_map.ext.php
Manifest Installdef
$installdefs['action_file_map']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/modules/<module>/Ext/ActionFileMap/ to map a new action in the system. The following example will create a new action called "example" in a module:
./custom/Extension/modules/<module>/Ext/ActionFileMap/<file>.php
<?php
$action_file_map['new_action'] = 'custom/modules/<module>/new_action.php';
Next, create your action file:
./custom/modules/<module>/new_action.php
<?php
//Encoded as JSON for AJAX layouts
echo '{"content":"Example View"}';
?>
Next, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization intoÂ ./custom/modules/<module>/Ext/ActionFileMap/action_file_map.ext.php
Module Loadable Package
When building a module-loadable package, you can use the $installdefs['action_file_map'] index to install the extension file.Â


Installdef Properties
Name
Type
Description
from
String
The basepath of the file to be installed.Â
to_module
String
The key of the module the file is to be installed to.
The example below demonstrates the proper install definition that should be used in the ./manifest.php file in order to add the Action File Map file to a specific module. You should note that when using this approach, you still need to use the $installdefs['copy'] index for the Action file, but Sugar will automatically execute Rebuild Extensions to reflect the new Action in the system.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'ActionRemap_Example',
    'action_file_map' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/modules/<module>/Ext/ActionFileMap/<file>.php',
            'to_module' => '<module>',
        )
    ),
    'copy' => array(
        array(
            'from' => '<basepath>/Files/custom/example.php',
            'to' => 'custom/example.php'
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index for the Action File Map Extension file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more informationÂ on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


This page refers to content that is only available in modules running in backward compatibility mode.
WirelessLayoutdefs
Overview
The WirelessLayoutdefs extension adds additional subpanels to wireless views. This extension is only applicable to modules running in backward compatibility mode.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Module
Sugar Variable
$layout_defs
Extension Directory
./custom/Extension/modules/<module>/Ext/WirelessLayoutdefs/
Compiled Extension File
./custom/<module>/Ext/WirelessLayoutdefs/wireless.subpaneldefs.ext.php
Manifest Installdef
$installdefs['wireless_subpanels']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/modules/<module>/Ext/WirelessLayoutdefs/ to add a subpanel to a module in the system. The following example will add a new subpanel to a specified module:
./custom/Extension/modules/<module>/Ext/WirelessLayoutdefs/<file>.php
<?php
$layout_defs['<module>']['subpanel_setup']['<subpanel module>'] = array(
    'order' => 10,
    'module' => '<subpanel module>',
    'get_subpanel_data' => '<subpanel name>',
    'title_key' => 'LBL_SUBPANEL_TITLE',
);
Navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization into ./custom/modules/<module>/Ext/WirelessLayoutdefs/wireless.subpaneldefs.ext.php.
Module Loadable Package
When building a module loadable package, you can use the $installdefs['wireless_subpanels'] index to install the extension file.


Installdef Properties
Name
Type
Description
from
String
The base path of the file to be installed
to_module
String
The key for the module where the file will be installed
The example below will demonstrate the proper install definition that should be used in the ./manifest.php file in order to add the subpanel file to a specific module. You should note that when using this approach Sugar will automatically execute Rebuild Extensions to reflect the subpanel in the system.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'wirelessLayoutdefs_Example',
    'wireless_subpanels' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/modules/<module>/Ext/WirelessLayoutdefs/<file>.php',
            'to_module' => '<module>',
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


Modules
Overview
The Modules extension maps additional modules in the system, typically when Module Builder deploys a module.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Application
Sugar Variable
$beanList, $beanFiles, $moduleList
Extension Directory
./custom/Extension/application/Ext/Include/
Compiled Extension File
./custom/application/Ext/Include/modules.ext.php
Manifest Installdef
$installdefs['beans']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/application/Ext/Include/ to register a new module in the system. This extension is normally used when deploying custom modules. The example below shows what this file will look like after a module is deployed:
./custom/Extension/application/Ext/Include/<file>.php
<?php
$beanList['cust_module'] = 'cust_module';
$beanFiles['cust_module'] = 'modules/cust_module/cust_module.php';
$moduleList[] = 'cust_module';
Next, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization into ./custom/application/Ext/Include/modules.ext.php.
Module Loadable Package
When building a module loadable package, you can use the $installdefs['beans'] index to install the extension file.
Installdef Properties
Name
Type
Description
module
String
The key of the module to be installed
class
String
The class name of the module to be installed
path
String
The path to the module's class
tab
Boolean
Whether or not the module will have a navigation tab (defaults to false)


tab
Boolean
Whether or not the module will have a navigation tab (defaults to false)
The example below demonstrates the proper install definition that should be used in the ./manifest.php file, in order to add a custom module to the system. When using this approach, you still need to use the $installdefs['copy'] index for Module directory, however, Sugar will automatically execute the database table creation process, relationship table creation process, as well as Rebuild Extensions to reflect the new Module in the system.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'Beans_Example',
    'beans' => array(
        array(
            'module' => 'cust_Module',
            'class' => 'cust_Module',
            'path' => 'modules/cust_Module/cust_Module.php',
            'tab' => true
        )
    ),
    'copy' => array(
        array(
            'from' => '<basepath>/Files/modules/cust_Module',
            'to' => 'modules/cust_Module'
        )
    )
);
Alternatively, you may use theÂ $installdefs['copy']Â index for copying the Modules definition file into the ./custom/Extension/application/Ext/Include/Â directory. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more informationÂ on theÂ $installdefs['copy']Â index and module loadable packages, please refer to theÂ Introduction to the ManifestÂ page.
  	Last modified: 2023-02-03 21:04:03


Language
Overview
The Language extension adds or overrides language strings.
This extension is applicable to both the application and module framework. For more information, please refer to the Language Framework page.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
All - Application & Module
Sugar Variables
If adding language files to application:$app_strings / $app_list_stringsÂ
If adding language files to <module>:$mod_strings
Extension Directory
Application: ./custom/Extension/application/Ext/Language/
Module: ./custom/Extension/modules/<module>/Ext/Language/
Compiled Extension File
Application: ./custom/application/Ext/Language/<language_key>.lang.ext.php
Module:Â ./custom/modules/<module>/Ext/Language/<language_key>.lang.ext.php
Manifest Installdef
$installdefs['language']
Â
Implementation
The following sections illustrateÂ the various ways to implement a customization to a Sugar instance.
File System
Creating New Application Label
When working directly with the filesystem, you can create a file in ./custom/Extension/application/Ext/Language/ to add Labels for languages to the system.Â The following example will add a new Label 'LBL_EXAMPLE_LABEL' to the system:Â
./custom/Extension/application/Ext/Language/<language>.<file>.php
<?php
$app_strings['LBL_EXAMPLE_LABEL'] = 'Example Application Label';
Navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization into./custom/application/Ext/Language/<language>.lang.ext.php
Creating New Module Label


Creating New Module Label
When working directly with the filesystem, you can create a file in ./custom/Extension/modules/<module>/Ext/Language/ to add Labels for languages to a particular module.Â The following example will add a new Label 'LBL_EXAMPLE_MODULE_LABEL' to a module:
./custom/Extension/modules/<module>/Ext/Language/<language>.<file>.php
<?php
$mod_strings['LBL_EXAMPLE_MODULE_LABEL'] = 'Example Module Label';
Navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization into ./custom/modules/<module>/Ext/Language/<language>.lang.ext.php
Module Loadable Package
When building a module loadable package, you can use the $installdefs['language'] index to install the extension file.Â
Installdef Properties
Name
Type
Description
from
String
The basepath of the file to be installed.Â
to_module
String
The key of the module the file is to be installed to.
language
String
The key of the language the file is to be installed to.
The example below will demonstrate the proper install definition that should be used in the ./manifest.php file, in order to add the Language Extension file to the system. You should note that when using this approachÂ Sugar will automatically execute Rebuild ExtensionsÂ to reflect the new Labels in the system.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'language_Example',
    'language' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/application/Ext/Language/<language>.lang.ext.php',
            'to_module' => 'application',
            'language' => '<language>'
        )
    )
);


'language' => '<language>'
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


Console
Overview
The ConsoleÂ extension adds custom CLI commands to Sugar. More information on creating custom commands can be found in the CLI documentation.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Application
Extension Directory
./custom/Extension/application/Ext/Console/
Compiled Extension File
./custom/application/Ext/Console/console.ext.php
Manifest Installdef
$installdefs['console']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
To create a Sugar consoleÂ extension, please refer to our CLI documentation.
Module Loadable Package
When building a module loadable package, you can use the $installdefs['console'] index to install the extension file.
Installdef Properties
Name
Type
Description
from
String
The basepath of the file to be installed.
The example below demonstrates the proper install definition that should be used in the ./manifest.php file in order to add the console command.Â
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array (
  'id' => 'console_Example',
  'console' => array(
      array(
          'from' => '<basepath>/Files/custom/Extension/application/Ext/Console/RegisterHelloWorldCommand.php'
      )
  ),
  'copy' => array (
    0 => array (
      'from' => '<basepath>/Files/custom/src/Console/Command/HelloWorldCommand.php',
      'to' => 'custom/src/Console/Command/HelloWorldCommand.php',
    ),
  ),
);


),
  ),
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
Download the module loadable example package here.
  	Last modified: 2023-02-03 21:04:03


Administration
Overview
The Administration extension adds new panels to Sugar's Administration page.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Module: Administration
Sugar Variable
$admin_group_header
Extension Directory
./custom/Extension/modules/Administration/Ext/Administration/
Compiled Extension File
./custom/modules/Administration/Ext/Administration/administration.ext.php
Manifest Installdef
$installdefs['administration']
Implementation
The following sections illustrateÂ the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/modules/Administration/Ext/Administration/<file>.php to add new Administration Links in the system. The following example will add a new panel to the Administration pageÂ called "Example Admin Panel", which will contain one link called "Example Link":
The following example will create a new admin panel:
./custom/Extension/modules/Administration/Ext/Administration/<file>.php
<?php
    $admin_option_defs = array();
    $admin_option_defs['Administration']['<section key>'] = array(
        //Icon name. Available icons are located in ./themes/default/images
        'Administration',
        //Link name label
        'LBL_LINK_NAME',
        //Link description label
        'LBL_LINK_DESCRIPTION',
        //Link URL - For Sidecar modules
        'javascript:parent.SUGAR.App.router.navigate("<module>/<path>", {trigger: true});',
        //Alternatively, if you are linking to BWC modules
        //'./index.php?module=<module>&action=<action>',
    );
    $admin_group_header[] = array(
        //Section header label
        'LBL_SECTION_HEADER',
        //$other_text parameter for get_form_header()
        '',


//$other_text parameter for get_form_header()
        '',
        //$show_help parameter for get_form_header()
        false,
        //Section links
        $admin_option_defs,
        //Section description label
        'LBL_SECTION_DESCRIPTION'
    );
Next, we will populate the panel label values:
./custom/Extension/modules/Administration/Ext/Language/en_us.<name>.php
<?php
    $mod_strings['LBL_LINK_NAME'] = 'Example Link';
    $mod_strings['LBL_LINK_DESCRIPTION'] = 'Link Description';
    $mod_strings['LBL_SECTION_HEADER'] = 'Example Admin Panel';
    $mod_strings['LBL_SECTION_DESCRIPTION'] = 'Section Description';
Next, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions, compiling your customization into ./custom/modules/Administration/Ext/Administration/administration.ext.php, and the new panel will appear in the Administration section.
Module Loadable Package
When building a module loadable package, use the $installdefs['administration'] index to install the extension file.
Installdef Properties
Name
Type
Description
from
String
The base path of the file to be installed
The example below demonstrates the proper install definition that should be used in the ./manifest.php file in order to add the Administration file to the system. If you are utilizing a Language file, as recommended above, you must use the $installdefs['language'] index to install the Language definition. Using the $installdefs['administration'] index will automatically execute Rebuild Extensions to reflect the new Administration Links in the system.
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'administration_example',
    'administration' => array(
        array(


'administration' => array(
        array(
           'from' => '<basepath>/custom/Extension/modules/Administration/Ext/Administration/<file>.php'
        )
    ),
    'language' => array(
        array(
            'from' => '<basepath>/custom/Extensions/modules/Administration/Ext/Language/en_us.<file>.php',
            'to_module' => 'Administration',
            'language' =>'en_us'
        )
    )
);
Alternatively, you may also choose to use the $installdefs['copy'] index for the Administration Link Extension file. When using this approach, you may need to manually run a repair action such as a Quick Repair and Rebuild.
For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


This page refers to content that is only available in modules running in backward compatibility mode.
Layoutdefs
Overview
The Layoutdefs extension adds or overrides subpanel definitions.
Note: This extension is only applicable to modules running in backward compatibility mode.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Module
Sugar Variable
$layout_defs
Extension Directory
./custom/Extension/modules/<module>/Ext/Layoutdefs/
Compiled Extension File
./custom/<module>/Ext/Layoutdefs/layoutdefs.ext.php
Manifest Installdef
$installdefs['layoutdefs']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/modules/<module>/Ext/Layoutdefs/ to add Layout Definition files to the system. The following example will add a subpanel definition for a module relationship:
./custom/Extension/modules/<module>/Ext/Layoutdefs/<file>.php
<?php
$layout_defs["<module>"]["subpanel_setup"]['<subpanel key>'] = array (
    'order' => 100,
    'module' => '<related module>',
    'subpanel_name' => 'default',
    'sort_order' => 'asc',
    'sort_by' => 'id',
    'title_key' => 'LBL_SUBPANEL_TITLE',
    'get_subpanel_data' => '<subpanel key>',
    'top_buttons' => array (
        array (
          'widget_class' => 'SubPanelTopButtonQuickCreate',
        ),
        array (
          'widget_class' => 'SubPanelTopSelectButton',
          'mode' => 'MultiSelect',
        ),
    ),
);


'mode' => 'MultiSelect',
        ),
    ),
);
Please note that, if you are attempting to override parts of an existing subpanel definition, you should specify the exact index rather than redefining the entire array. An example of overriding the subpanel top_buttons index is shown below:
<?php
$layout_defs["<module>"]["subpanel_setup"]["<subpanel key>"]["top_buttons"] = array(
    array(
        'widget_class' => 'SubPanelTopButtonQuickCreate',
    ),
);
Next, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customizations to ./custom/modules/<module>/Ext/Layoutdefs/layoutdefs.ext.php .
Module Loadable Package
When building a module loadable package, you can use the $installdefs['layoutdefs'] index to install the extension file.
Installdef Properties
Name
Type
Description
from
String
The base path of the file to be installed
to_module
String
The key for the module where the file will be installed
The example below demonstrates the proper install definition that should be used in the ./manifest.php file in order to add the Layout Definition Extension file to the system. When using this approach, Sugar will automatically execute Rebuild Extensions to reflect the customizations added with the Layout definition.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'layoutdefs_Example',
    'layoutdefs' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/modules/<module>/Ext/Layoutdefs/<file>.php',
            'to_module' => '<module>',
        )
    )
);


'to_module' => '<module>',
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


Utils
Overview
The Utils extension adds functions to the global utility function list.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Application
Extension Directory
./custom/Extension/application/Ext/Utils/
Compiled Extension File
./custom/application/Ext/Utils/custom_utils.ext.php
Manifest Installdef
$installdefs['utils']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/application/Ext/Utils/ to map a new action in the system. The following example will create a new function called 'exampleUtilFunction' that can be used throughout the system:
./custom/Extension/application/Ext/Utils/<file>.php
<?php
function exampleUtilFunction()    '
{
    //logic
}
Next, navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and your customizations will be compiled into ./custom/application/Ext/Utils/custom_utils.ext.php .
Alternatively, functions can also be added by creating ./custom/include/custom_utils.php. This method of creating utils is still compatible but is not recommended from a best practices standpoint.
Module Loadable Package
When building a module loadable package, you can use the $installdefs['utils'] index to install the extension file.
Installdef Properties
Name
Type
Description
from
String
The base path of the file to be installed
The example below demonstrates the proper install definition that should be used in the ./manifest.php file in order to add the utils to the system. You should note that when using this approach, Sugar will automatically execute Rebuild Extensions to reflect the new utils in the system.
./manifest.php
<?php
$manifest = array(


./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'utils_Example',
    'utils' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/application/Ext/Utils/<file>.php',
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module-loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


This page refers to content that is only available in modules running in backward compatibility mode.
TinyMCE
Overview
The TinyMCE extension affects the TinyMCE WYSIWYG editor's configuration for backward compatible modules such as PDF Manager and Campaign Email Templates.
To review the default configuration for TinyMCE, please refer to the code in ./include/SugarTinyMCE.php. Sidecar's TinyMCE configuration can be edited using the Sidecar Framework and editing the htmleditable_tinymce field.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Application
Sugar Variable
$defaultConfig, $buttonConfigs, $pluginsConfig
Extension Directory
./custom/Extension/application/Ext/TinyMCE/
Compiled Extension File
./custom/application/Ext/TinyMCE/tinymce.ext.php
Manifest Installdef
$installdefs['tinymce']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/application/Ext/TinyMCE/ to customize the TinyMCE configuration. The following example will increase the height of the TinyMCE window, remove buttons, and remove plugins from the WYSIWYG Editor:
./custom/Extension/application/Ext/TinyMCE/<file>.php
<?php
$defaultConfig['height'] = '1000';
$buttonConfigs['default'] = array(
    'buttonConfig' => "bold,italic,underline,strikethrough,separator,bullist,numlist",
    'buttonConfig2' => "justifyleft,justifycenter,justifyright,justifyfull",
    'buttonConfig3' => "fontselect,fontsizeselect",
);


'buttonConfig3' => "fontselect,fontsizeselect",
);
$pluginsConfig['default'] = 'advhr,preview,paste,directionality';
Navigate to Admin > Repair > Quick Repair and Rebuild. The system will then rebuild the extensions and compile your customization into ./custom/application/Ext/TinyMCE/tinymce.ext.php
Module Loadable Package
When building a module loadable package, you can use the $installdefs['tinymce'] index to install the extension file.
Installdef Properties
Name
Type
Description
from
String
The base path of the file to be installed
The example below demonstrates the proper install definition that should be used in the ./manifest.php file, in order to add the UserPage file to the system. You should note that when using this approach Sugar will automatically execute Rebuild Extensions to reflect the changes to TinyMCE in the system.
./manifest.php
<?php
$manifest = array(
    ...
);
$installdefs = array(
    'id' => 'tinyMCE_Example',
    'tinymce' => array(
        array(
            'from' => '<basepath>/Files/custom/Extension/application/Ext/TinyMCE/<file>.php',
            'to_module' => 'application'
        )
    )
);
Alternatively, you may use the $installdefs['copy'] index to copy the file. When using this approach, you may need to manually run repair actions such as a Quick Repair and Rebuild. For more information on the $installdefs['copy'] index and module loadable packages, please refer to the Introduction to the Manifest page.
  	Last modified: 2023-02-03 21:04:03


EntryPointRegistry
Overview
The EntryPointRegistry extension maps additional entry pointsÂ to the system. Please note thatÂ entry pointsÂ will soon be deprecated. Developers should move custom logic to endpoints.Â For more information, please refer to the Entry Points page.
Properties
The following extension properties are available.Â For more information, please refer to the Extension Property documentation.
Property
Value
Extension Scope
Application
Sugar Variable
$entry_point_registry
Extension Directory
./custom/Extension/application/Ext/EntryPointRegistry/
Compiled Extension File
./custom/application/Ext/EntryPointRegistry/entry_point_registry.ext.php
Manifest Installdef
$installdefs['entrypoints']
Implementation
The following sections illustrate the various ways to implement a customization to a Sugar instance.
File System
When working directly with the filesystem, you can create a file in ./custom/Extension/application/Ext/EntryPointRegistry/ to map a new entry point in the system. The following example will create a new entry point called exampleEntryPoint that will display the text, "Hello World":
./custom/Extension/application/Ext/EntryPointRegistry/<file>.php
<?php
$entry_point_registry['exampleEntryPoint'] = array(
    'file' => 'custom/exampleEntryPoint.php',
    'auth' => true
);
Next, create the file that will contain the entry point logic. This file can be located anywhere you choose, but we recommend putting it in the custom directory. More information on custom entry points can be found on the Creating Custom Entry Points page.
./custom/exampleEntryPoint.php
<?php
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
echo "Hello World!";