You can enhance your workflow and extend DesktopServer’s features and functionality with plugins. Programmers familiar with PHP programming and WordPress’ API can development DesktopServer compatible plugins. A DesktopServer plugin is a type of extension that lives within a sub-folder of the plugins folder (at C:\ProgramFiles\.ds\plugins on Windows or /Users/Shared/.ds/plugins on Macintosh). A DesktopServer plugin can be turned on or off from DesktopServer’s ‘Services’ page and is executed immediately upon activation. A plugin may alter or extend almost any aspect of the DesktopServer application user interface, virtual host instances, as well as implement a background service, and/or extend or modify the localhost (aka “View Sites”) webpage. A DesktopServer plugin is by far the most powerful way to extend the functionality of the DesktopServer application.

Getting Started

To create a DesktopServer plugin you simply need to create a PHP file with a valid WordPress API plugin header. Typically, the filename should be a pretty permalink compatible name and live within a sub-folder of the same name; inside the DesktopServer plugins folder. The DesktopServer plugins folder can be found at the following locations (based on your operating system platform):

On Macintosh operating systems at:
/Users/Shared/.ds/plugins

On Windows operating systems at:
C:\ProgramData\.ds\plugins

A plugin will not be active until it is “activated” via DesktopServer’s main menu option to “Stop or restart the web and database services” followed by selecting the checkbox (on/off switch) for the given plugin. The list also appears on first application startup (if no services are turned on).

Figure 1 – Services Screen

The WordPress API plugin header format will be reflected within the DesktopServer 5 runtime in the following ways:

  • Plugin Name – this will appear in the Services’ screen list box in bold text.
  • Version – The version number will appear to the right of the plugin name in the list box.
  • Description – The description will appear below the title in the list box.

Global WordPress Plugin Behavior

An activated DesktopServer plugin will function just like a regular WordPress plugin, and will be active inside all virtual hosted WordPress development websites. However, plugin behavior differs slightly in the following ways:

  • No activation/deactivation actions. Like WordPress’ mu-plugins, there are no activation or deactivation event hooks.
  • Plugins must reside in a subfolder of the “.ds/plugins” folder. Unlike regular WordPress plugins that can optionally reside in a sub-folder or top level single file, or mu-plugins that cannot reside in a sub-folder, DesktopServer plugins must reside in a named sub-folder.
  • A call to WordPress’ plugins_url function will return the plugin’s URL path through a “ds-plugins” alias; I.e. the virtual hosted domain, followed by “ds-plugins” and the given plugin folder: http://www.example.dev.cc/ds-plugins/plugin-folder (as opposed to the WordPress plugins’ folder for a locally installed plugin on the virtual host domain: http://www.example.dev.cc/wp-content/plugins/plugin-folder).
  • As long as one DesktopServer plugin is activated, every development website will receive an additional Apache directive to resolve the ds-plugin alias in the URL for the globally accessible plugin folder (including the localhost page, i.e. http://localhost/ds-plugins).
  • The global $ds_runtime object is created before loading any other PHP scripts to be executed.
  • An optional script can be included in the plugin subfolder with the file name of prepend.php or prepend_#.php (where # is a numeric value of 0 to 10). The prepend.php file provides early execution before the virtual hosted site is loaded. 

An example of a global WordPress plugin would be DesktopServer’s own Admin Color Bar plugin. The Admin Color Bar plugin is a simple plugin that changes the color of the admin bar for a given WordPress website. This plugin could be installed locally within a WordPress website; in the most traditional sense: placing the plugin within the site’s own wp-content/plugins sub-folder. I.e. /Users/JSmith/Sites/www.example.dev.cc/wp-content/admin-color-bar. Or the plugin can be made available in all WordPress websites running in DesktopServer by placing the plugin in the folder at /Users/Shared/.ds/plugins/admin-color-bar (on Macintosh) or C:\ProgramData\.ds\plugins\admin-color-bar (on Windows). The latter approach simplifies using the plugin for “design-time” purposes; for when a website developer/designer wishes to utilize the plugin during website development but not necessarily for permanent installation as apart of a deployed website.

Understanding PHP Execution Order & Performance

A DesktopServer plugin’s PHP files are executed in a specific order to extend and modify the DesktopServer application, the virtual hosted sites created by DesktopServer, and the localhost (“View Sites”) home page. At the heart of every instance of PHP execution is the DesktopServer runtime object. This globally accessible object is available under the reserved global variable name $ds_runtime. The global $ds_runtime object governs the loading of additional DesktopServer plugins, the activated plugin’s prepend.php files (if present) and furnishes additional API functions for manipulating the DesktopServer application user interface and services. Whether PHP is invoked from the command line, from within a virtual hosted website, or in the context of the DesktopServer application instance; all PHP runtimes have access to the $ds_runtime. Let’s take a look at the order in which PHP is executed and begins execution:

Figure 2 – Execution Order

A PHP instance will first load the global $ds_runtime object which will in turn load the DesktopServer preferences file. The preferences file contains the master list of activated DesktopServer plugins, version information, a list of virtual hosted websites created in DesktopServer, and other various user settings, and preferences. The various properties of the preferences file are accessible in PHP via $ds_runtime->preferences. Updating the preferences file is possible via $ds_runtime->save(). The actual file is located at the following location, based on platform:

On Macintosh at:
/Users/Shared/.ds/data/preferences.json

On Windows at:
C:\ProgramData\.ds\data\preferences.json

Next, the global $ds_runtime object will parse any prepend files that need to be executed.

About prepend.php Files

Prepend files are a powerful way for DesktopServer plugins to alter the PHP runtime environment. The global $ds_runtime object will first load any prepend.php files within plugin folders of activated DesktopServer plugins. Suffixed PHP files (with an underscore and numeric) will be loaded in priority order whereby 0 is loaded before 1, 2, 3, etc. I.e. the file prepend_1.php file will be loaded before prepend_5.php, etc. If the prepend file is just called prepend.php, the default load priority is equivalent to the file named prepend_5.php. Because prepend.php files are loaded for every instance of PHP (regardless of context), performance within virtual hosted sites can be inhibited. It is important that prepend.php files are used sparingly, only when necessary, and exit/return early if not needed.

The DesktopServer runtime API has implemented a number of core properties to help you determine the context of the runtime environment. You can check these properties to determine if your prepend.php file should continue executing instructions or return to prevent excessive CPU activity. For instance, if you know your prepend.php file only applies to the localhost page; check if the runtime context is localhost using the given runtime property (this behavior is depicted at the beginning of the ds-phpmyadmin/prepend.php file in the DesktopServer phpMyAdmin plugin):

<?php
global $ds_runtime;
if ( false == $ds_runtime->is_localhost ) return;

The DesktopServer runtime API includes properties for checking the running context:

  • $ds_runtime->is_localhost is true when the http://localhost page is being displayed in a web browser.
  • $ds_runtime->is_vhost is true when the URL for the given page is coming from a virtually hosted website (i.e. https://example.dev.cc)
  • $ds_runtime->is_app is true when the PHP execution is bound to the unique DesktopServer Application user interface.

Using the Register Script Function

Sometimes performance can be inhibited in PHP by the mere volume of PHP files that need to be loaded, parsed, and executed. While the prepend.php system is fine for smaller plugins, it is often times more appropriate to avoid loading large blocks of PHP code that the parser will need to evaluate. In these cases it is best to leave the prepend.php as “skinny” as possible and evaluate if additional includes are even necessary. The register script function in the DesktopServer runtime API is suited to provide this:

<?php
global $ds_runtime;
$ds_runtime->register_script("my_localhost_script.php", 1);

The code example above could be used in a prepend.php file to tell the PHP interpreter to only load the file if the user is visiting the http://localhost page. The register_script function takes two parameters; the file to load, followed by the context integer:

/**
 * Registers a script to be executed in a given context type. Use this function within
 * a prepend file to optimize loading subsequent code only if the given context criteria
 * are met. The following integers represent the context type; only when the PHP script
 * will be loaded:
 * 
 * 0 - The DesktopServer Application, only loads within the application user interface.
 * 1 - The localhost page (aka "View Sites"), only when the user visits http://localhost
 * 2 - A virtually hosted website, only when a page is accessed for a created website.
 *  
 * @param string $file The PHP file to load and execute.
 * @param string $context The context determines when the file is loaded and executed
 */

Use the context integer to tell PHP to only load code when the user is 0 – using the DesktopServer application user interface, 1 – when visiting the localhost page, or 2 – when visiting a virtual hosted website created with DesktopServer.

The DesktopServer PHP Runtime API

As shown above, the DesktopServer PHP Runtime API is concentrated within a single global variable know as $ds_runtime. A list of common methods and properties that are important to developers and their description is shown in the table below:

Method or PropertyDescription
$ds_runtime->add_action Hook a function or method to a specific filter action.

@param string $tag The name of the action to add.
@param callback $function_to_add The function to be invoked.
@param integer $priority Determines the execution priority, lower occurring first.
@return bool
$ds_runtime->debugLogAppend to the preferences.debugLog or .ds/temp/logs/ds_error.log if true.

@param mixed $msg Can be string or object to serialized and written to the log file.
$ds_runtime->do_action Execute functions hooked on a specific action hook. This is function invokes all functions attached to action hook $tag. It is possible to create new action hooks by simply calling this function, specifying the name of the new hook using the $tag parameter.

@param string $tag The name of the action to be executed.
@param mixed  $arg Optional. Additional arguments which are passed on to the functions hooked to the action. Default empty.
@return always returns incoming argument, after all callbacks processed.
$ds_runtime->execExecute the given bash compatible shell command within the optional given native folder.

@param string $cmd The command to execute.
@param string $cd The native folder to change to before executing the given command.
@return string The results of the shell_exec.
$ds_runtime->read_sessionRead-only access to the JavaScript ds.session object.

@return Returns the temp/session.json file as a json decoded object or null if none.
$ds_runtime->register_scriptRegisters a script to be executed in a given context type. Use this function within a prepend file to optimize loading subsequent code only if the given context criteria are met. The following integers represent the context type; only when the PHP script will be loaded:

0 – The DesktopServer Application, only loads within the application user interface.
1 – The localhost page (aka “View Sites”), only when the user visits http://localhost
2 – A virtually hosted website, only when a page is accessed for a created website.

@param string $file The PHP file to load and execute.
@param string $context The context determines when the file is loaded and executed
Table 1 – DesktopServer PHP Runtime API

Extending the DesktopServer Application User Interface

The DesktopServer application user interface can be extended in multiple areas. First, it is important to note the common attributes of the application graphical user interface areas:

Figure 3 – Application Areas

These areas consist of (1) The “Navigation Bar”, this is where the DesktopServer logo exists with two semi-hidden buttons to activate the sidebar (left upper corner) and user pull down menu (right upper corner). (2) The “Action Bar” contains buttons to take action based on the the context of the application area. (3) The “Application Area” is where you will find the bulk of functionality, options, and instructions that drive the DesktopServer application behavior. Each of these areas are customizable using DesktopServer’s PHP API.

DesktopServer PHP Action Hooks API

The DesktopServer PHP Action Hooks API provides a number of ways to extend the DesktopServer application using PHP based “action hooks”. DesktopServer’s action hooks are very similar to WordPress action hooks and allow a plugin’s code to interact/modify another piece of code at specific, pre-defined spots. They make up the foundation for how plugins can modify or extend the DesktopServer application. To code for a typical action hook, you will use the global $ds_runtime object’s add_action method. For example, the code below will inject our own JavaScript source code file called “my-script.js” into the header from our own “my-plugin” folder:

<?php
   global $ds_runtime;
   $ds_runtime->add_action('ds_head_main', function($content) {
 
      // Let's inject our own JavaScript into the header
      $content .= '<script src="' . getenv('DS_FOLDER') . '/plugins/my-plugin/my-script.js"></script>';
      return $content;
   });

DesktopServer action hooks function like WordPress’ own filter functions. In the example above, the original contents between the <head> </head> tags for the main menu will appear present in the argument variable $content. Plugins can modify the $content variable and it is important to return the value (modified of otherwise).

The action hooks for the various areas of the application have a named prefix that help identify the area; often followed by a suffix that is unique to the current user interface page the user is viewing. Using the Main Menu (found in the file .ds/runtime/ds-web/htdocs/main.php) as an example; the most common prefixes that you will find are presented in the table below:

Action HookDescription
ds_head_mainThis action hook contains the suffix ‘main’ to denote that it is unique to the Main Menu.
This action hook typically contains the inside of the page’s <head> and </head> tag contents.
ds_navbarThis action hook does not contain a suffix. It occurs on all pages that display the navigation
bar menus.
ds_sidebarThis action hook does not contain a suffix. It occurs on all pages that are able to display the
sidebar. Note that this action is a sub-action (occurs within) the ds_navbar action.
ds_app_mainThis action hook contains the suffix ‘main’ to denote that it is unique to the Main Menu.
This action hook is for the Main Menu application’s title and body area (see Figure 3 – #3,
Application Area).
ds_actionbar_mainThis action hook contains the suffix ‘main’ to denote that it is unique to the Main Menu.
This action hook contains the HTML markup that displays the Main Menu’s action bar buttons
(see Figure 3 – #2, Action Bar).
ds_footer_mainThis action hook contains the suffix ‘main’ to denote that it is unique to the Main Menu.
This action hook is empty by default; it contains any markup to appear above the closing
</body> tag for the given page (in this case the Main Menu).
Table 2 – Common Action Hooks (PHP)

The various suffixes that denote the unique action hook names for a given DesktopServer application user interface screen parallel their filenames. All files that make up the DesktopServer base application user interface can be found in the respective .ds/runtime/ds-web/htdocs folder. For clarity, a screenshot of the unique DesktopServer UI pages and their action hooks are presented here, along with their shared screen area action hooks:

User Interface ScreenAction Hooks
From main.php
ds_head_main – The contents between <head> tags, including title, css, scripts, etc.
ds_app_main – The main application title and body area.
ds_actionbar_main – The bottom button area that includes the View Sites, Close, and Next buttons.
ds_footer_main – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From services.php
ds_head_services – The contents between <head> tags, including title, css, scripts, etc.
ds_app_services- The services application title and body area containing the list of plugins.
ds_actionbar_services – The bottom button area that includes the Quit and Start buttons.
ds_overlay_services – The overlay template used when displaying the waiting screen.
ds_footer_services – The footer area before the closing </body> tag.

* Navigation bar area and sidebar menu is purposely omitted.
** The overlay action hook is specific for services in ds_overlay_services
From edit.php
ds_head_edit – The contents between <head> tags, including title, css, scripts, etc.
ds_app_edit – The main application title and body area.
ds_actionbar_edit – The bottom button area that includes the Back and Next buttons.
ds_footer_edit – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From edit_copy.php
ds_head_edit_copy – The contents between <head> tags, including title, css, scripts, etc.
ds_app_edit_copy – The main application title and body area.
ds_actionbar_edit_copy – The bottom button area that includes the Back and Next buttons.
ds_footer_edit_copy – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From copying.php
ds_head_copying – The contents between <head> tags, including title, css, scripts, etc.
ds_app_copying – The main application title and body area.
ds_actionbar_copying – The bottom button area that includes the View Sites, Close, and Next buttons.
ds_footer_copying – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.

Includes overlay.php
ds_overlay – The overlay template used when displaying the waiting screen.
From edit_move.php
ds_head_edit_move – The contents between <head> tags, including title, css, scripts, etc.
ds_app_edit_move – The main application title and body area.
ds_actionbar_edit_move – The bottom button area that includes the Back and Next buttons.
ds_footer_edit_move – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From moving.php
ds_head_moving – The contents between <head> tags, including title, css, scripts, etc.
ds_app_moving – The main application title and body area.
ds_actionbar_moving – The bottom button area that includes the View Sites, Close, and Next buttons.
ds_footer_moving – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.

Includes overlay.php
ds_overlay – The overlay template used when displaying the waiting screen.
From scrub_options.php
ds_head_scrub_options – The contents between <head> tags, including title, css, scripts, etc.
ds_app_scrub_options – The main application title and body area.
ds_actionbar_scrub_options – The bottom button area that includes the Back and Next buttons.
ds_footer_scrub_options – The footer area before the closing </body> tag.

* Navigation bar area and sidebar menu is purposely omitted.
From create.php
ds_head_create – The contents between <head> tags, including title, css, scripts, etc.
ds_app_create – The main application title and body area.
ds_actionbar_create – The bottom button area that includes the Back and Next buttons.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From blueprints.php
ds_head_blueprints – The contents between <head> tags, including title, css, scripts, etc.
ds_app_blueprints – The main application title and body area.
ds_actionbar_blueprints – The bottom button area that includes the Back and Next buttons.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
The bp_options page only appears and
is loaded if there is a blueprint.php file
present in the selected blueprint when
creating a site *and* has an Action Hook
to populate the title via ds_bp_options_title.

See Creating DesktopServer Blueprints
for more options.
From bp_options.php
ds_bp_options_file – The path to the selected blueprint.php file for the selected blueprint.
ds_bp_options_title – The title to display for the blueprint optional page; see Creating DesktopServer Blueprints.
ds_card_bp_options – The card body of the custom blueprints option page; excluding title area.
ds_app_bp_options – The main application title and body area (including ds_bp_options_card).
ds_actionbar_bp_options – The bottom button area that includes the Back and Next buttons.
ds_footer_bp_options – The footer area before the closing </body> tag.

* Navigation bar area and sidebar menu is purposely omitted.

Includes overlay.php
ds_overlay – The overlay template used when displaying the waiting screen.
From creating.php
ds_head_creating – The contents between <head> tags, including title, css, scripts, etc.
ds_app_creating – The main application title and body area.
ds_actionbar_creating – The bottom button area that includes the View Sites, Close, and Next buttons.
ds_footer_creating – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From aliases.php
ds_head_aliases – The contents between <head> tags, including title, css, scripts, etc.
ds_app_aliases – The main application title and body area.
ds_actionbar_aliases – The bottom button area that includes the Back and Next buttons.
ds_footer_aliases – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From ieother.php
ds_head_ieother – The contents between <head> tags, including title, css, scripts, etc.
ds_app_ieother – The main application title and body area.
ds_actionbar_ieother – The bottom button area that includes the Back and Next buttons.
ds_footer_ieother – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From import.php
ds_head_import – The contents between <head> tags, including title, css, scripts, etc.
ds_app_import – The main application title and body area.
ds_actionbar_import – The bottom button area that includes the Back and Next buttons.
ds_footer_import – The footer area before the closing </body> tag.
ds_import_extensions – An array of supported extensions to browse for; defaults to [‘bz2’, ‘tar’, ‘tbz2’, ‘tgz’, ‘gz’, ‘zip’]
ds_import_unknown_ext – The JavaScript used to pre-process an unknown filename extension for decompression.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
From export.php
ds_head_export – The contents between <head> tags, including title, css, scripts, etc.
ds_app_export – The main application title and body area.
ds_actionbar_export – The bottom button area that includes the Back and Next buttons.
ds_footer_export – The footer area before the closing </body> tag.

Includes navbar.php
ds_navbar – The top navigation bar and upper right-hand user menu.

Includes sidebar.php
ds_init_sidebar – The initialization function for sidebar menus. This is NOT a filter function.
ds_sidebar – The sidebar “flyout” menu; see using Extending the Navigation Bar Menus.
Table 3 – Application Action Hooks (PHP)

Workflows and Utilities API

Workflows are operations that run in a background thread in DesktopServer; often the user interface will display an overlay with a waiting graphic during these operations. A DesktopServer plugin can listen to workflows via action hooks; these action hooks are:

Workflows Action Hooks

Action HookOccurrence
ds_workflow_import_adapterOccurs during an import operation after decompression and/or ds_import_unknown_ext; before site files are analyzed. Used by plugins and processes that wish to re-arrange the contents of the site folder and adapt it to the standard DesktopServer site structure whereby:
* wp-config.php or wp-config-sample.php is in the site root.
* .ds/ds_details.json is present
* .ds/database is populated with mysql2json compatible files
ds_workflow_config_hostsThe operating system hosts file is copied to .ds/data/hosts and is about to be modified. Used by processes that wish to modify the hosts file. After this action is invoked; the hosts file will be copied back to the operating system under an elevated/privileged process.
ds_workflow_config_vhostsThe Apache web server’s vhosts file is copied to .ds/data/httpd-vhosts.conf and is about to be modified. Used by processes that wish to modify the Apache vhosts file. After this action is invoked; the Apache web server will be restarted to reload the new configuration.
ds_workflow_copy_doneOccurs after a website is copied, after wp-config.php has been updated, and after the preferences.json file has been modified to list the new site.
ds_workflow_create_doneOccurs after a website is created, after wp-config.php has been updated, and after the preferences.json file has been modified to list the new site.
ds_workflow_export_includedOccurs during the export process and before compression. Passes in an array of specific subfolders to included in the exported archive overriding the exclude array in the ds_workflow_export_exclude action.
ds_workflow_export_excludeOccurs during the export process and before compression. Passes in an array of specific subfolders to excluded from export archive.
ds_workflow_export_prezipOccurs during the export process and before compression. Passes in an array containing all the items that will be compressed in the export archive.
ds_workflow_export_doneOccurs during the export process and after compression has completed.
ds_workflow_import_decompressedOccurs during the import process after decompression has been handled (in the UI by JavaScript and/or the action hook ds_import_unknown_ext) and before folders are moved into position.
ds_workflow_import_doneOccurs after a website is imported, after wp-config.php has been updated, and after the preferences.json file has been modified to list the new site.
ds_workflow_move_doneOccurs after a website is moved, after wp-config.php has been updated, and after the preferences.json file has been modified to list the new site.
ds_workflow_remove_doneOccurs after a website has been removed, information about the given site is passed in as an argument.
ds_workflow_scrub_excludesOccurs when scrubbing is gathering files to exclude from the scrubbing process. An array of filenames to exclude is passed in as an argument.
ds_workflow_scrub_filetypesOccurs when scrubbing is gathering files to process. An array of filetypes to include, with file patterns (i.e. *.json, etc.) is passed in as an argument.
ds_workflow_scrub_filesOccurs when scrubbing is finished gathering files. An array of all files to be scrubbed is passed in as an argument.
ds_workflow_scrub_searchOccurs when scrubbing is about to take place. An array of search strings to be replaced (must match the array length in the action hook ds_workflow_scrub_replace).
ds_workflow_scrub_replaceOccurs when scrubbing is about to take place. An array of replacement strings to be inserted (must match the array length in the action hook ds_workflow_scrub_search).
ds_workflow_scrub_doneOccurs after a search and replace scrubbing process has completed.
Table 4 – Workflow Action Hooks (PHP)

DS_Utils API

In addition to workflows, DesktopServer includes a DS_Utils object (inside the ds-web/src/ds_utilities.php file) with common core static functions used throughout the application (such as file copying, etc.). A DesktopServer plugin use these static functions and are documented here:

MethodDescription
DS_Utils::camel_caseCamel case the given string with an option to preserve characters. (I.e. “Hello World” becomes “helloWorld”)

@param string $str The string to conver to camel case.
@param array $noString The sequence of characters to preserve.
@return string The camel case version of the string.
DS_Utils::copy_folderCopy the source folder contents to the destination folder, omitting items listed in the filter parameter; default skips .git*, .svn, .dropbox, .DS_Store, _notes, __MACOSX, and other pesky files and folders.

@param string $src The source folder containing the content to copy.
@param string $dest The destination folder to copy the folder contents to.
@param array $filter An array of strings containing file/folder name patterns to skip (pass null for default).
@param object $climate An optional climatePHP object to provide CLI status.
@return void
DS_Utils::create_dbCreate a database in MySQL with unique credentials that are prefixed with a hint of the site’s given domain name.

@param string $name The site name to use for creating related credentials.
@return array An array containing the credentials, dbUser, dbName, dbPass, dbHost.
DS_Utils::dump_dbDump database for the given website name to it’s .ds/database folder.

@param string $name The name of the website to dump the database for.
@param object $climate An optional climatePHP object to provide CLI status.
@return void
DS_Utils::execute_sqlExecutes the given SQL statement on the server.

@param string $sql The SQL to execute on the server.
DS_Utils::find_first_fileRecursively search the given path for the first instance of the given filename.

@param string $path The path to perform searching recursively.
@param string $name The filename to find.
@return string The complete path to the file or empty string if not found.
DS_Utils::get_header_detailsSearches for all files and within subfolders for a valid WordPress style headers within the given folder path. A valid header file must match the filename or filename pattern (i.e. *.php, style.cc, etc.) and contain the first element in the details array to retrieve (i.e. ‘Plugin Name’). The function will return an array of JSON objects containing all keys and values in addition to the extra keys ‘headerFile’ containing a full native path to the found header file, and ‘slug’, a slugified version of the first key entry (i.e. a-plugin-name).

@param string $path The folder path to begin searching (i.e. wp-content/plugins)
@param string $filter The filename or pattern to search for (i.e. *.php, style.css, etc.)
@param array $keys The array of header keys to obtain (i.e. [‘Plugin Name’, ‘Description’, etc.])
@return array An array objects containing the given keys.
DS_Utils::get_php_valueReliably obtain the first instance of a casted value that appears in a given PHP source code file, ignoring any commented out lines, and accomodating single quotes or double quoated values. Casted means it must contain an equal sign. I.e. obtain ‘wp_’ in wp-config.php’s line $table_prefix = ‘wp_’; OR ‘root’ from phpMyAdmin’s config.inc.php where the line reads $cfg[‘Servers’][$i][‘user’] = ‘root’;

@param string $file The complete path and file name of the PHP file to be read.
@param string $hint A string that must appear on the a line to the left of the equal sign.
@return mixed Returns the found value or NULL if none found.
DS_Utils::get_php_defineReliably obtain the first instance of a define value that appears in a given PHP source code file, ignoring any commented out lines, and accomodating single quotes or double quoted values. I.e. obtain ‘username_here’ from define( ‘DB_USER’, ‘username_here’ );

@param string $file The complete path and file name of the PHP file to be read.
@param string $key The define key to obtain the value for.
@return mixed Returns the found value or NULL if none found.
DS_Utils::move_folderMove the source folder contents to the destination folder, omitting items listed in the filter parameter; default is no filter.

@param string $src The source folder containing the content to move.
@param string $dest The destination folder to move the folder contents to.
@param array $filter An array of strings containing file/folder name patterns to skip (pass null for default).
@param object $climate An optional climatePHP object to provide CLI status.
@return void
DS_Utils::random_charsGenerate random alpha numeric for passwords, seeds, etc.

@param int $length The length of characters to return.
@param string $chars The set of possible characters to choose from.
@return string The resulting randomly generated string.
DS_Utils::random_saltGenerate random salt, includes randomChars with expanded character set, and a default of 64 bytes in length.

@param int $length The length of characters to return.
@param string $chars The set of possible characters to choose from.
@return string The resulting randomly generated string.
DS_Utils::reload_dbReload the database for the given website name; provided it has a .ds/database folder

@param string $name Then name of the website to reload the database for.
@param object $climate An optional climatePHP object to provide CLI status.
@return void
DS_Utils::remove_folderRemove/delete the given folder and all child files and folders.

@param string The complete path to the folder to be removed.
DS_Utils::scrub_folderScrub is recursive search and replace on the given folder. The search and replace parameters must be arrays of the same length. Types and exclude are additional arrays that only apply to the included file types, and are within folders that do not match the exclude parameter.

@param string $folder The folder to perform the search and replace operation on.
@param array $search An array of strings to search for; same length as $replace parameter
@param array $replace An array of strings to replace corresponding search items with.
@param object $climate An optional climatePHP object to provide CLI status.
@param array $types An array of file types to analyze, defaults to .json,.php,.css,.htm,.html,.txt,.md,.js,.htaccess,.xml
@param array $excludes An array of path fragments to exclude from the scrubbing process; defaults to wp-admin,wp-includes,wp-content/plugins
@return void
DS_Utils::slugifyA super simple slugify function for a given title.

@param string $text The string to slugify.
@param string $divider The optional divider between words.
@return string Returns the slugified version of the given string.
DS_Utils::update_php_defineUpdate a define value in a given PHP source code file, ignoring any commented out lines, and preserving the existing single/double quoated value nomenclature.

@param string $file The complete path and file name of the PHP file to be updated.
@param string $key The key in the define definition to update.
@param string $value The value to use in the define statement.
@param string $old The optional previous value to search for to increase search accuracy.
@param Boolean Returns true if the value has been successfully updated or false if not found.
DS_Utils::update_php_valueUpdate a casted value (equals/= statment) in a given PHP source code file, ignoring any commented out lines, and preserving the existing single/double quoated value nomenclature.

@param string $file The complete file path and file name of the PHP file to be updated.
@param string $hint A string that must appear on the a line to the left of the equal sign.
@param string $value The value to use in the casted value casted statement.
@param Boolean Returns true if the Value has been successfully updated or false if not found.
DS_Utils::update_preferencesUpdate the preferences file with our new definition.
DS_Utils::update_wp_configUpdate the wp-config.php file for the give site folder. If no wp-config.php file is found, it will seek out the wp-config-sample.php file and use it as a template for a new wp-config.php file.

@param string $dest The folder containing a wp-config.php file.
@param string $dbName The value to set for DB_NAME.
@param string $dbUser The value to set for DB_USER.
@param string $dbPass The value to set for DB_PASSWORD.
@param string $dbHost The value to set for DB_HOST, defaults to “127.0.0.1” (faster than localhost; this has been benchmarked).
@param boolean $multisite An optional multisite flag, true to set the multisite option.
@return void
Table 5 – DS_Utils API (PHP)

DS_Utils Action Hooks

DesktopServer DS_Utils action hooks work in conjunction with their similar-named workflows as they are often invoked by a given workflow, i.e. ds_workflow_remove_done uses the DS_Utils::remove_folder method that in turn invokes ds_utils_remove_folder action hook. However, it is important to note that DS_Utils’ action hooks are generic in nature and may be used by other unrelated processes and services that have little or nothing to do with a particular workflows operation. Furthermore, DesktopServer action hooks are multi-process operations. A given action hook may not occur within the same process of another; thereby making global variable sharing inappropriate and not guaranteed. When two action hooks wish to reference a shared value or set of values, it is best practice to store such values in session variables or temp files.

Action HookOccurrence
ds_utils_copy_folderDS_Utlils::copy_folder invoked. I.e. during a website copy operation.
ds_utils_dump_dbDS_Utils::dump_db invoked. I.e. during a website copy, move, or export operation.
ds_utils_execute_sqlDS_Utils::execute_sql invoked. I.e. during a create new website operation to create a database.
ds_utils_find_first_fileDS_Utils::find_first_file invoked. I.e. when searching for the wp-config.php file to parse.
ds_utils_move_folderDS_Utils::move_folder invoked. I.e. when moving an existing website.
ds_utils_reload_dbDS_Utils::reload_db invoked. I.e. during a website copy or move operation.
ds_utils_remove_folderDS_Utils::remove_folder invoked. I.e. when deleting an existing website.
ds_utils_scrub_folderDS_Utils::scrub_folder invoked. I.e. when a website is copied, the domain is search & replaced.
ds_utils_update_preferencesDS_Utils::update_preference invoked. I.e. when updating the preferences.json file.
ds_utils_update_wp_configDS_Utils::update_wp_config invoked. I.e. when updating database credentials.
Table 6 – DS_Utils Action Hooks (PHP)
Extending the Navigation Bar Menus

The navigation bar area contains two menu areas that can be extended by DesktopServer plugins the User Menu (see #2, Figure 4) and the Sidebar Menu (see #1, Figure 5).

Figure 4 – Navigation Bar Areas

The User Menu (#2, Figure 4) can easily be appended to or altered using the action hook ‘ds_navbar’. This action hook is setup as a filter and passes the markup content that makes up bith the Navbar area and the Sidebar area. You may use this to primarily inject menus and/or functionality that is specific to the user menu. For example, the user menu consists of a seperation bar between the items “Help & Support” and “Log Out”. The following code could inject a new item by replacing the seperation bar markup:

global $ds_runtime;

// Hook the navbar
$ds_runtime->add_action('ds_navbar', function($content) {

  // Create markup code for our new menu item
  $from = '<b-dropdown-divider></b-dropdown-divider>';
  $to = "<b-dropdown-divider></b-dropdown-divider>\n";
  $to .= '<b-dropdown-item href="#" v-on:click="alert(' . "'Hello from the User Menu!'" . ');">Hello!</b-dropdown-item>';

  // Replace first instance of divider with our Hello! menu item.
  return preg_replace('/'.preg_quote($from, '/').'/', $to, $content, 1);
}

The code above will effectively create a menu item above the Log Out menu item that says “Hello!”. When clicked, an alert dialog box should appear with the message “Hello from the User Menu!”. Likewise, a plugin author code inject a Vue.prototype of their own. See the .ds/runtime/ds-web/htdocs/assets/js/ds_vm.js JavaScript file for an example of how the $logout method works.

Figure 5 – Sidebar Menu Area

In addition to the User Menu, there is the Sidebar (#1, Figure 5), with predefined areas such as the main DesktopServer group (#2) and submenu items (#3). You may append to these areas using the special action hook ‘ds_init_sidebar’ in conjunction with the special $ds_runtime methods that are available only during the ‘ds_init_sidebar’ action hook:

$ds_runtime->set_sidebar_group_icon
and
$ds_runtime->insert_sidebar_item

For an example of how to use the action hooks and methods to build the sidebar, see line 51 inside .ds/runtime/ds-web/htdocs/sidebar.php. An excerpt of that code is presented here to illustrate how the DesktopServer Main Menu item is displayed on the sidebar:

// Create our initial DesktopServer sidebar group and items
$ds_runtime->add_action('ds_init_sidebar', function() {
    global $ds_runtime;

    // DesktopServer group
    $ds_runtime->set_sidebar_group_icon('DesktopServer', '<i class="icon-ds5-bw"></i> ');
    $ds_runtime->insert_sidebar_item('Main Menu', "window.location = ds.ds_folder + 'runtime/ds-web/htdocs/main.php';", 'DesktopServer');
...

When the ds_init_sidebar action hook is fired, you can see that the main DesktopServer group is created with the DesktopServer icon (using an icon font). DesktopServer 5 includes a number of custom dashicon fonts specific for DesktopServer and including those from WordPress’ icons and the Bootstrap Vue project.

DesktopServer JavaScript API

While DesktopServer’s PHP API provides you with a powerful means to modify the DOM, inject scripts, and other elements; the bulk of DesktopServer’s Application UI is driven by JavaScript. More specifically, DesktopServer leverages the power of the Bootstrap Vue project and it’s own trusted native functions that can be invoked by JavaScript. For instance, DesktopServer’s import screen uses JavaScript to communicate with operating system via a hidden command line instance to carry out various operations (i.e. decompress an archive prior to import, access the operating system’s priviledged/administrator files like the hosts file, restart the webserver, etc.). These methods are accessible via the global ds object. It is important to note that the ds object is only available when the DOM has finished parsing and DesktopServer throws the ds_ready event. This event can be hooked using the following script pattern:

<script>
  window.addEventListener("ds_ready", function() {

    // The ds object is ready for use
    ds.confim("Choose an option", function(result) {

      document.write("The result is " + result.toString());

    });

  });
</script>

The proceeding code will present the user with a confim dialog box followed by displaying the boolean result based on the user selection (True for OK and False for Cancel). The ds object is made available after the ds_ready event has been fired; thereby making the method ‘confirm’ accessible. In addition to methods, the ds object contains a number of useful properties:

Property NameDescription
ds.preferencesJSON object containing the complete preferences file. This object can be updated and saved using the ds.save() method.
ds.protectedJSON object containing the decoded protected file. Used to store private and encrypted data.
ds.darkModeBoolean for the initial dark mode status.
ds.sessionJSON object containing temporary session data. This data can be read from DesktopServer’s PHP API using the $ds_runtime->read_session() method.
ds.windowIDString for the unique window handle.
ds.platformString indicating the current platform (mac/win).
ds.architectureString indicating the architecture (x64, ARM, etc.)
ds.executableFileString containing the executable filename & path.
ds.resourcesString containing the resources folder path.
ds.ds_folderString containing the “dot” DesktopServer folder path.
ds.trusted_domainString containing the trusted domain.
Table 7 – DS Object Properties (JavaScript)

The global JavaScript DesktopServer object (aka ‘ds’) includes the following list of methods for plugin authors. Their subsequent descriptions are also listed here:

Method NameDescription
ds.addEventListenerProvides extendable API with events:

ds_alert – Occurs before an alert dialog is displayed.
ds_appearance_changed – Occurs when the user switches between light and dark modes.
ds_confirm – Occurs before a confirmation dialog is displayed.
ds_dl_progress – Reports progress of download, bytes, total bytes, local filename.
ds_download – Occurs when a file download is initiated with the given URL.
ds_debug_log – Occurs whenever ds.debugLog is called within the application javascript context.
ds_exists – Occurs whenever ds.exists is called to query if a file or folder exists.
ds_notify – Occurs when a BootstrapVue ‘toast’ notification dialog appears in the DesktopServer application UI.
ds_notify_all_windows – Occurs when ds.notifyAllWindows is used, before all windows receive ds_window_notified.
ds_window_notified – When a message is received from ds.notifyAllWindows.
ds_open_window – When a openWindow has been invoked with a given URL.
ds_prompt – Occurs before a input text field dialog is displayed.
ds_ready – When the ds object is ready; use window.addEventListener to hook this.
ds_read_file – Occurs when a ds.readFile has been invoked.
ds_resized – Occurs when the application window appears and/or is resized.
ds_save – Occurs before preferences, protected, and session data are saved.
ds_saved – Occurs after preferences, protected, and session data has been saved and refreshed in all open windows.
ds_shell_command – Occurs before a shell command is executed.
ds_shell_interactive – Occurs before a shell interactive is executed.
ds_shell_change – When the built in shell is updated with new content.
ds_shell_elevated – Occurs before an elevated shell command is executed.
ds_shell_write – Occurs before a subsequent command/keystroke is sent to the interactive shell.
ds_update_repos – Occurs before repos are automatically updated and allows modifying the repos list.
ds_vm_ready – Occurs when our Vue system is mounted (invoked from ds-web).
ds_window_close – Cancellable event (event.preventDefault()) that occurs before window close
ds_write_file – Occurs when a ds.writeFile has been invoked.
ds_quit – Occurs before the application quits.

@param {string} name The name of the event to listen to (see above).
@param {function} cb The callback function to be invoked.
ds.alertSupport a native alert dialog box.

@param {string} msg The message to display in our alert box.
@param {function} cb The optional callback to invoke when the OK button is acknowledged.
ds.closeWindowClose the current window.
ds.confirmDisplays a confirmation dialog message with ok, cancel buttons.

@param {string} msg The message to display in the confirmation dialog.
@param {function} cb The callback to receive the selection result (true/false).
ds.copyContentsToCopy the contents of the given folder to the given destination. Returns a callback when finished.

@param {string} from The source folder containing the content to copy.
@param {string} dest The destination folder to copy the contents to.
@param {function} cb The callback to invoke when finished.
ds.copyFolderToCopy a folder to the given destination path. Returns a callback when finished.

@param {string} from The source folder to copy.
@param {string} dest The destination path to copy the folder to.
@param {function} cb The callback to invoke when finished.
ds.debugLogAppend a message to the System.DebugLog. On Windows, it logs to the debugger, so programs like DebugView can be used to view the string. On macOS, it logs to the Console. On Linux, it prints the message to StdErr. Messages can also be seen in the Xojo IDE workspace. Also write to our own debugLog if defined in the preferences file, i.e. “debugLog”:”file:\/\/\/C:\/error_log.txt”

@param {string} msg The message to send to the System.DebugLog
ds.deleteFolderDelete the given folder and all it’s children. Returns a callback when finished.

@param {string} fn The folder to delete.
@param {function} cb The callback to invoke when finished.
ds.downloadDownload a given file from the specified URL to the local file system.

@param {string} url The remote URL of the item to download.
@param {string} fn The local file path and filename or just path (default to orignal download filename).
@param {function} cb The callback to receive the file complete event.
ds.existsCheck if an existing file or folder exists and return true/false in the callback.

@param {string} fn The file or folder in URL or native shell format.
@param {function} cb The callback to return the results to.
ds.findFileFind the first occurance of the given filename within the given parent folder and it’s children. Returns the complete path as a file URL or empty string if not found.

@param {string} fn The parent folder path to begin searching.
@param {string} name The name of the file to find.
@param {function} cb The callback to return the results to.
ds.findFolderFind the first occurance of the given folder name within the given parent folder and it’s children. Returns the complete path as a file URL or empty string if not found.

@param {string} fn The parent folder path to begin searching.
@param {string} name The name of the folder to find.
@param {function} cb The callback to return the results to.
ds.getProcessIDGet the process ID for the given name; i.e. ‘http’, ‘mysqld’, etc. Returns the first instance of the given process ID or zero if none found.

@param {string} name The name of the process to look and obtain the PID for.
@param {function} cb The callback to invoke and return the process id.
ds.getNativeCodeUsed internally for nativeCode to retrieve messages.

@returns {string} Messages awaiting pickup in native code.
ds.moveContentsToMove the contents of the given folder to the given destination. Returns a callback when finished.

@param {string} from The source folder containing the content to move.
@param {string} dest The destination folder to move the contents to.
@param {function} cb The callback to invoke when finished.
ds.moveFolderToMove a folder to the given destination path. Returns a callback when finished.

@param {string} from The source folder to move.
@param {string} dest The destination path to move the folder to.
@param {function} cb The callback to invoke when finished.
ds.notifyProvides an implmentation of the Bootstrap Vue “toast” notifications on demand in the DesktopServer application UI that will appear in the upper right hand corner of the user interface.

@param {string} title The title to use in the toast notification dialog.
@param {string} msg The message to display in the toast notification dialog.
@param {string} variant The color schema to use. The default is ‘primary’.
@param {number} delay The amount of time in milliseconds to display the notification dialog before auto-hiding. The default is 0 ‘forever’ or until the user closes it via the x button.
@param {string} href A URL hyperlink to invoke if the user clicks on the given dialog’s message area.
ds.notifyAllWindowsSend a message to all open windows that listen via ds_window_notified.

@param {string} msg The message to send to all windows.
ds.openWindowOpen a new application window.

@param {string} url The URL to navigate to in the newly opened window.
@param {boolean} topmost Determines if the window is a global floating topmost window.
@param {boolean} width Determines initial window width.
@param {boolean} height Determines initial window height.
ds.promptDisplays a prompt for user input with single text field, ok, and cancel buttons.

@param {string} msg The message to display in the prompt.
@param {string} val The optional default value to display in the input text field.
@param {function} cb The callback to receive the input or empty string on cancel.
@param {boolean} pass Changes the text input field to be password protected type.
ds.purgeFileByNameDeletes all files by the given name starting from the given parent folder and within all child folders. Returns a callback when finished.

@param {string} fn The parent folder to begin searching for files to purge.
@param {string} name The name of the file to delete from the parent and sub folders.
@param {function} cb The callback to invoke when finished.
ds.purgeFolderByNameDeletes all folders of the given name starting from the given parent folder and within all child folders. Returns a callback when finished.

@param {string} fn The parent folder to begin searching for files to purge.
@param {string} name The name of the file to delete from the parent and sub folders.
@param {function} cb The callback to invoke when finished.
ds.quitQuit the DesktopServer application.
ds.readFileReads the given file and returns the results in the callback.

@param {string} fn The file path and name in URL or native shell format.
@param {function} cb The callback to return the results to.
ds.removeEventListenerRemoves the given event listener

@param {string} name The name of the event to listen remove.
@param {function} cb The callback function to be removed.
ds.saveSave our preferences, protected, and session data.

@param {function} cb Optional callback guarantee when save finishes.
ds.setMinimumWindowSizeSets the minimum application window size the user is able to resize the window to in pixels.

@param {number} width The minimum width in pixels for the application window.
@param {number} height The minimum height in pixels for the application window.
ds.setWindowPositionSets the window position on the desktop in pixels from the upper top left corner of the display.

@param {number} left The x coordinate/left most position for the application window.
@param {number} top The y coordinate/top most position for the application window.
ds.setWindowSizeSets the width and height in pixels for the application window.

@param {number} width The width for the window in pixels.
@param {number} height The height for the window in pixels.
ds.shellCommandExecutes a command in the native OS shell and optionally returns the results to a given callback function.

@param {string} cmd The command to execute.
@param {function} cb Optional callback to return with results.
ds.shellElevatedExecutes a command in the ‘elevated’ or privilege native OS shell (via DesktopServer_Helper).

@param {string} cmd The command to execute.
@param {function} cb Optional callback to return with results.
ds.shellInteractiveLike shellCommand but keeps the shell alive when returning the results to the callback; the callback may, in return, provide subsequent commands to the interactive shell to process (see ds.shellWrite below). Ideally, the callback should return false or void (undefined) to invoke garbage collection and proper closing of the shell.

@param {string} cmd The command to execute.
@param {function} cb Optional callback to return with results.
@return {integer} The unique id/handle associated with the shell instance.
ds.shellToURLConvert platform shell path to URL path.

@param {string} path The folder or filename path to convert to from native platform specific to shell path.
ds.shellWriteWrite a command to an existing interactive shell (see ds.shellInteractive above). Must supply a valid handle as retrieved from a prior call to ds.shellInteractive. Allows sending keypresses; therefore typical CLI entries should be terminated with an ‘enter’ keypress (newline character).

@param {string} cmd The command/text to send to the interactive shell instance.
@param {integer} id The unique id/handle associated with an existing shell instance (from ds.shellInteractive).
@return void
ds.showOpenFileShow the native open file dialog.

@param {string} folder Initial folder path in URL format or empty string for home folder.
@param {function} cb The callback to receive the user selected file path or empty string if cancelled.
ds.showSaveFileShow the native save file dialog.

@param {string} fn Initial file path to set default file name or just folder path (default home folder).
@param {function} cb The callback to receive the user selected file path or empty string if cancelled.
ds.showSelectFolderShow the native folder selector dialog.

@param {string} folder The optional initial folder path or empty string for user home folder.
@param {function} cb The callback to receive the user selected folder or empty string if cancelled.
ds.syncRepoShallow synchronize the given repo to the given directory or default to obtaining the latest runtime/ds-web. Returns a promise after completion.

@param {string} url The git repository URL to pull files from.
@param {string} dir The local directory to place files to.
@param {string} version The specific tagged version to retrieve from the repo.
ds.unzipUnzip the given item using the native unzip to an adjacent unzipped folder of the same name, overwriting any pre-existing folder or to the given destination folder. Returns the unzip item’s folder path in a callback.

@param {string} fn The filename and path of the zip archive to unzip.
@param {string} path The optional destination folder to unzip to.
@param {function} cb The callback to invoke returning the unzipped folder.
ds.updatePermissionsUpdate the given parent folder and all sub folders and files with WordPress’ default file and folder permissions respectively (0x755 and 0x644). Options to re-assign owner and group (default is to inherit parent folder’s). Returns a callback when the process is finished.

@param {string} fn The parent folder path to update permissions.
@param {number} nFile The optional file permission setting.
@param {number} nFolder The optional folder permission setting.
@param {string} owner The optional owner name to set.
@param {string} group The optional group name to set.
@param {function} cb The callback to invoke when finished.
ds.urlToShellConvert URL path to platform native shell path.

@param {string} path The folder or filename URL path to convert to the native platform specific shell path.
ds.writeFileWrite the given file with the given data; returns callback when finished.

@param {string} fn The file path and name in URL or native shell format.
@param {string} d The data to write to the given file.
@param {function} cb The callback to return the results to.
ds.zipZip the given parent folder to an adjacent zip file of the same name or to the given optional destination folder. Returns a callback when complete with the resulting zip file path.

@param {string} fn The name of the parent folder to zip up.
@param {string} dest The optional destination to zip the file to.
@param {function} cb The callback to return zipped file URL.
Table 8 – DS Object Methods (JavaScript)

In addition to the core ds object, the DesktopServer JavaScript API includes a services object that is used to control the integrated web server, database services, and invoke asyncronous PHP workflow processes, . This API is accessible through the sub-object ‘ds.services’ and it’s methods are documented here:

Method NameDescription
ds.services.buildBootstrapBuilds the boot.bat or boot.sh bootstap file that guarantees us access to the Apache, MySQL, PHP, etc. Plugins/third-parties can intercept this to inject their own paths and bootstrap changes by listening for the events ds_read_file and ds_write_file.
ds.services.isRunningDetermines if services are running; DesktopServerHelper, web (httpd), and database (mysqld).

@returns Promise resolves if processes are in memory.
ds.services.restartRestart the web and database services.

@returns Promise resolves on completion.
ds.services.restartDBRestart the database service.

@returns Promise resolves on completion.
ds.services.restartWebRestart the web service.

@returns Promise resolves on completion.
ds.services.startStarts the web and database server.

@returns Promise after services have started.
ds.services.startDBStart the database server.

@returns Promise after the service have started.
ds.services.startHelperStarts the DesktopServerHelper privileged process, a requirement for ds.shellElevated to function properly.

@returns Promise resolves when process has returned without error.
ds.services.startWebStart the web server.

@returns Promise after the service have started.
ds.services.stopStop all services, web, database, and the priviledged DesktopServerHelper process.

@returns Promise on completion.
ds.services.stopDBStop the database service.

@returns Promise on completion.
ds.services.stopHelperStops the priviledged DesktopServerHelper process.
ds.services.stopWebStop the web service.

@returns Promise on completion.
ds.services.updateConfigFilesUpdate all the configuration files, filters all writes through latent event; allowing newly activated plugins to modify configuration files too.

@returns Promise after all files have completed writing.
ds.services.workflowWorkflow allows us to pass execution to an asynchronous PHP script and monitor for results. Parameters are passed from a JSON object that is relayed to the shell process as a series of command arguments. JSON results can be monitored by the supplied callback to observe the process’ progress.

@param {string} cmd The PHP workflow script command to execute.
@param {variant} options An optional JSON object of CLI option/switches or string as one CLI argument
@param {object} status A vue status object to provide GUI feedback.
@return A promise that resolves when the workflow has completed.
Table 9 – DS Services Object Methods (JavaScript)

The DesktopServer JavaScript API also includes a number of utility functions; accessible via the sub-object ds.utils. The utilities object’s methods are documented here:

Method NameDescription
ds.utils.cygpathConvert DOS drive path to cygpath.

@param {string} The path in DOS format (i.e. C:\ProgramData\.ds\temp)
@returns A string in cygwin compatible format (i.e. /cygdrive/C/ProgramData/.ds/temp)
ds.utils.dospathConvert cygpath to DOS drive path.

@param {string} The path in cygpath format (i.e. /cygdrive/C/ProgramData/.ds/temp)
@returns A string in DOS path compatible format (i.e. C:\ProgramData\.ds\temp)
ds.utils.generateSiteNameGenerate a new logical site name that is not currently an existing site name.

@param {string} initName The initial site name to request.
ds.utils.getSubFoldersGets a list of sub folders from the given path.

@param {string} filepath a native path or URL (file:///C:/Users, etc.).
@returns Promise with an array containing a list of immediate sub directories.
ds.utils.openExternalURLOpen the given URL or file path in the system designated web browser or file system browser.

@param {string} url The file path or URL to open.
@returns void
ds.utils.randomStringGenerate a string of random characters.

@param {number} The length of the string to generate.
@param {string} The character sets to include a (lowercase alphabet), A (uppercase alphabet), # (numbers), ! (punctuation)
@returns Random characters of the specified length.
Table 10 – DS Utils Object Methods (JavaScript)

Modifying the Localhost (‘View Sites’) Pages

DesktopServer includes a localhost page to make visiting virtually hosted sites easy. This page (accessible at http://localhost), includes key areas that can be customized by plugins to include more convenience features and links. These areas include the Tools pull down menu (see #1, Figure 6), the listing of virtual hosted domains created in DesktopServer (see #2, Figure 6), and quick access, domain button groups (see #3, Figure 6). Each of these areas can be appended to or modified host specific DesktopServer action hooks.

Figure 6 – Localhost Page Areas

A good example of a DesktopServer plugin that modifies the localhost page to better suite user needs is the ds-phpmyadmin plugin. This plugin will furnish the latest phpMyAdmin utility to make managing DesktopServer’s database easy. Once activated via the DesktopServer application’s Services menu, the plugin will append a phpMyAdmin link to the Tools pull down menu (#1, Figure 6). In addition, the ds-phpmyadmin plugin will provide an additional orange button to the domain button group (#3, Figure 6) that will automatically open the phpMyAdmin utility to the database context associated with the given website. The localhost homepage can be located in the following directory:

On Macintosh operating systems at:
/Users/Shared/.ds/runtime/ds-web/localhost/index.php

On Windows operating systems at:
C:\ProgramData\.ds\runtime\ds-web\localhost\index.php

The following action hooks are exclusive to the DesktopServer 5 localhost page:

Action Hook Occurrence
ds_head_localhostThe contents between <head> tags, including title, css, scripts, etc. This action is a filter and supplies the existing header contents. It is important to pass along the contents in the return value. This action hook replaces the ‘ds_head’ (deprecated) action hook used in prior versions of DesktopServer.
ds_append_tools_menuThis action hook is not a filter. It can be used to inject additional menu items in the Tools pulldown menu. Additional items should echo markup that uses the Bootstrap Vue syntax, for example:

<b-dropdown-item href=”http://localhost/phpinfo.php” target=”_blank”>
                            PHP Information
</b-dropdown-item>
ds_list_domainThis action hook is not a filter. It can be used to inject additional markup in the domain listing section of the localhost page (see #2, Figure 6).
ds_domain_button_groupThis action hook is not a filter. It can be used to inject additional markup in the domain button group section of the localhost page (see #3, Figure 6).
ds_domain_button_group_afterThis action hook is not a filter. It can be used to inject additional markup in the domain button group section of the localhost page (see #3, Figure 6).
ds_list_subdomainThis action hook is not a filter. It can be used to inject additional markup in the sub-domain listing section of the localhost page (see #2, Figure 6).
ds_subdomain_button_groupThis action hook is not a filter. It can be used to inject additional markup in the sub-domain button group section of the localhost page (see #3, Figure 6).
ds_subdomain_button_group_afterThis action hook is not a filter. It can be used to inject additional markup in the sub-domain button group section of the localhost page (see #3, Figure 6).
ds_footer_localhostThe contents between total sites listed on the domain list and the closing </body> tag. It is important to pass along the contents in the return value. This action hook replaces the ‘ds_footer’ (deprecated) action hook used in prior versions of DesktopServer.
Table 11 – Localhost Action Hooks (PHP)

Creating Background Services

Creating background services for DesktopServer is easy. Simply use the DesktopServer PHP action hook API syntax to listen for the ‘ds_heartbeat’ action hook. This action hook is invoked by the DesktopServerHelper process. The heartbeat can be artificially invoked by visiting http://localhost/heartbeat.php.

Action HookOccurrence
ds_heartbeat The ds_heartbeat action hook occurs once every minute. Care should be taken to note that the heartbeat process is an asynchronous process but is shared amoungst all listeners that wish to utilize it. It is therefore in the best interest of the plugin author to efficiently release the process as soon as possible. Functionality that requires additional processing time could spawn sub processes using PHP’s shell_exec or utilize some other mechanism to assure control is returned to the main processing thread.
Table 12 – DS Heatbeat Action Hook (PHP)

Debug Logging

The $ds_runtime object also furnishes a central debugging log used throughout the DesktopServer application. The method is called “debugLog” and is available in both PHP ($ds_runtime->debugLog) and JavaScript (ds.debugLog). To use the method, simply specify the “debugLog” property in the preferences.json file with either a boolean true or as string indicating where you want the debug log to be filename and path written to:

{
    "version": "5.0.0",
    "webOwner": "jsmith",
    "debugLog": true,
...

With the debugLog property set within the preferences.json file, any usage of the $ds_runtime->debugLog method will result in output inside the ds_error.log file. The ds_error.log file can be found at the following locations (based on your operating system platform):

On Macintosh operating systems at:
/Users/Shared/.ds/temp/logs/ds_error.log

On Windows operating systems at:
C:\ProgramData\.ds\temp\logs\ds_error.log

For example, the code below will output the current contents of the <head> </head> tag on the main menu of our application. You can see the content written to the ds_error.log file:


<?php

   global $ds_runtime;
   $ds_runtime->add_action('ds_head_main', function($content) {
      global $ds_runtime;

      // Log the current content between the <head> and </head> tags to our ds_error.log file.
      $ds_runtime->debugLog($content);

      // Important to return the content so that it is output to the main menu.
      return $content; 
   });

In JavaScript, the ds.debugLog method is available after the ds_ready event has fired. For example, the following will write to the same ds_error.log from JavaScript:

<script>

  window.addEventListener('ds_ready', function() {

    ds.debugLog("Hello from JavaScript!");

  }); 

</script>