On this page

How to build a Standard App

SiteGUI's Standard App is a standard PHP class with a namespace, the class should contain some configuration settings for the app and several methods for handling app records. Methods should always return an array containing a key name "result" with the value "success" to indicate successful execution. 

Standard App must be submitted to SiteGUI Appstore for reviewing before it can be deployed. Once your app has been developed, simply use the  button next to your app name to submit it to the Appstore.

App Settings and Per Site Settings

App Settings (visibility, category) can be defined in a static method named config(), these values will determine whether the app is included in the app menu or not and whether the app records are accessible by different user groups. App can also create Per Site Settings by adding custom fields to allow Site Managers to input their own configuration values for the app. To create a custom field, just define field id (name), type, display name (label) and description for it. You can also set field visibility (visibility), a default value (value), whether the field is required or optional (is => required/optional/multiple) or accepting multiple values (select and lookup field only), and specify options if field supports them. The following field types are supported:

  • text/textarea: text input field
  • lookup: a lookup field that returns the IDs of matching object name (e.g: a Page name, a Product name, a User name). Supported objects are: creator (user), admin (staff), group (role), page, collection, menu_id, product, variant, sku, app name (e.g: feature_request).
  • select/radio: a field that consists several options to choose. Options can be pre-defined or can be looked up by specifying From::lookup as the first option, object (creator, page, permission) as the second option and optionally the value to lookup as the third option.  
  • file/image: a file/image field that allows uploading of file/image or selecting a file/image from File Manager
  • checkbox: a checkbox field
  • radio hover: a radio field that shows the selected or default option and upon mouse hovering, shows other available options to choose (e.g: an emoji selection)
  • rating: a clickable/slidable field that consists 5 stars to allow choosing a rate out of 5. Half-star or a rate of 4.5 is also supported.
  • password: a password field that can be used to store sensitive credentials, the value will be encrypted
  • url/email/tel/color: standard input fields
  • country: a dropdown field for selecting a country 

Below is an example of the static method config()

  public static function config($property = null) {
  $app['visibility'] = 'client_readonly';
  $app['category'] = 'CMS';

  /* a text field type allows for single line text input */
  $app['fields'] = [
     'name' => [
        'label' => 'Blog Name',
        'type' => 'text',
        'size' => '6',
        'value' => '',
        'description' => 'Enter your Blog Name here',
     ],
  ];
  if ($property AND isset($app[ $property ]) ) {
     $response[ $property ] = $app[ $property ];
  } else {
     $response['config'] = $app;
  } 

  $response['result'] = 'success';
  return $response;
}            

Initialize the App

When the app is initialized, it should receive the configuration values for the running site and for the app itself (per site settings), these values are stored in $this->config (sample below). The View object is also available for the app to use at $this->view.

  [site] => Array
(
  [id] => 1000
  [name] => SiteGUI
  [url] => sitegui.com
  [template] => supersite
  [status] => Active
  [owner] => 123456
  [language] => en
  [timezone] => America/New_York
  [editor] => wysiwyg
  [logo] => https://cdn.sitegui.com/public/templates/admin/bootstrap5/assets/img/logo.png
  [locales] => Array
  (
	[en] => english
  )
)
[app] => Array
(
  [api_token] => xxxxxxx
  [mode] => advance
  [row_count] => 25
}  

SiteGUI ViewBlock

SiteGUI renders content using a Layout and ViewBlocks. Layouts are important for creating visually appealing and functional user interfaces. They allow developers to organize the components of an application in a logical and intuitive way. A layout is an arrangement of BlockHolders that can be displayed at a relative position of a view, such as main, top, bottom, left or right. SiteGUI supports the following BlockHolders by default:

  • block_head: should be attached to <head> tag, should contain non-visible content such as scripts or CSS (inline or URLs)
  • block_header: should be displayed at the header of a page (where logo and menu are displayed)
  • block_spotlight: should be displayed where attracts most attention from viewers
  • block_left: should be displayed to the left of the page
  • block_right: should be displayed to the right of the page
  • block_top: should be displayed at the top of the page
  • block_bottom: should be displayed at the bottom of the page
  • block_main: should be displayed as the main content. Page content is shown here
  • block_footnote: should be displayed near the end of a page but before the footer area
  • block_footer: should be displayed at the end of a page 
  • content_header: should be displayed at the header of the main content
  • content_spotlight: should be displayed where attracts most attention from viewers
  • content_left: should be displayed to the left of the main content
  • content_right: should be displayed to the right of the main content
  • content_top: should be displayed at the top of the main content
  • content_bottom: should be displayed at the bottom of the main content
  • content_footnote: should be displayed near the end of the main content but before the footer area
  • content_footer: should be displayed at the end of the main content

A layout may add more custom BlockHolders (should start with block_) but should support as many default BlockHolders as it could to make the layout usable with different applications which may attach ViewBlocks to those default BlockHolders. 

A ViewBlock is actually an array containing the following keys:

  • order (integer, optional): use for sorting if there are multiple ViewBlocks at one position
  • system (array): keys in this array will be converted to Smarty variables {$key}:
  • api (array): keys in this array will be appended to the Smarty variable {$api} and will be available via API access
  • html (array): keys in this array will be appended to the Smarty variable {$html} and will only be available via API access upon requested (html=1)
  • menu (array): an array of menu items which will be merged into a Smarty variable {$position_menu}  (position is the position to which the ViewBlock is attached e.g: {$top_menu})
  • output (HTML string): an HTML string which will be assigned to a Smarty variable {$block_name} (block_name is the name of the block i.e: block_main, block_top, block_1, block_2)
  • template (array): specify a Smarty template (to be rendered to HTML when "output" key is not defined) using the following keys 
    • string (base64 encoded string): a template string
    • file (file name without extension): a template file (e.g: page_edit)
    • directory (relative file path, optional): specify a directory relative to the base directory to load the template file specified above
    • layout (file name without extension, optional): specify a layout to use instead of the default layout, this is applicable to a ViewBlock attached to position "main" only.

    One or more ViewBlocks can be attached to a BlockHolder. When attaching to one of the default BlockHolders, just remove the prefix block_ and use the position directly (i.e: top, left or main instead of block_top, block_left or block_main). For custom BlockHolders, please use the full block name. Any Smarty variable assigned/appended in each ViewBlock are available for all other ViewBlocks to use (and may be overwritten by other ViewBlocks)Any ViewBlock attached to a BlockHolder will have their rendered HTML output appended to a Smarty variable {$block_name} (block_name is the name of the block i.e: block_main, block_top, block_1, block_2, content_top) and displayed at the specified position in the layout.

    Create a new or edit an existing record

    The method edit() is called when the record editor is opened to create a new or edit an existing record. The method should return an array of SiteGUI ViewBlocks attached to supported BlockHolders to alter the look and feel of the editor. The main block may specify a template name to be rendered or use the default one (app_edit.tpl). If the default template is used, the main block should indicate which default inputs should be shown and may add custom fields to the editor.

    Save a record

    The method update() is called whenever the app receives a submission. The method processes the submitted data and then return them back to be stored into the database.

    Display a record on the website

    The method render() is called when a record is displayed. It receives the record data and returns an array of SiteGUI ViewBlocks that contain all variables and settings (layout, template name) to help the View object to render the record properly.

    Display a record category on the website

    The method renderCollection() is called when a record category is displayed. It receives the category data and returns an array of SiteGUI ViewBlocks that contain all variables and settings (layout, template name) to help the View object to render the category properly.

    Sample App

      <?php
    namespace SiteGUI\App;
    
    class Blog {
       protected $config, $view; 
       /* Class construction */
       public function __construct($site_config, $view){
          $this->config = $site_config;
          $this->view = $view;
       }
    
       /* App Config */
       public static function config($property = null) {
          $app['visibility'] = 'client_readonly';
          $app['category'] = 'CMS';
    
          /* a text field type allows for single line text input */
          $app['fields'] = [
             'name' => [
                'label' => 'Blog Name',
                'type' => 'text',
                'size' => '6',
                'value' => '',
                'description' => 'Enter your Blog Name here',
             ],
          ];
          if ($property AND isset($app[ $property ]) ) {
             $response[ $property ] = $app[ $property ];
          } else {
             $response['config'] = $app;
          } 
    
          $response['result'] = 'success';
          return $response;
       }        
    
       /* Render Editor */
       function edit($page) {
          if ( !empty($page) ){
             $app['hide'] = [
                'description' => 1, 
                /* 'content' => 1, */
             ];
             $app['fields'] = [
                /* a text field type allows for single line text input */
                'username' => [
                   'label' => 'Author',
                   'type' => 'text',
                   'size' => '6',
                   'value' => '',
                   'description' => 'Enter your name here',
                ],
             ];
    
             /* $response['blocks']['main']['template']['layout'] = "blank"; */	
             /* $response['blocks']['main']['template']['file'] = "blog_edit"; */	
             $response['blocks']['main']['api']['page'] = $page;
             $response['blocks']['main']['api']['app'] = $app;
             /* $response['blocks']['footer']['output'] = 'Extra footer content'; */					
          }
    
          $response['result'] = 'success';
          return $response;
       }
    
       /* Process data to be saved */
       function update($page){
          if ( !empty($page) ){
             $response['result'] = 'success';
             $response['page']   = $page;	
          } else {
             $response['result']  = 'error';
             $response['message'] = 'Invalid submitted data '. print_r($page, true);
          }
    
          return $response;
       }
    
       /* Render record via website */
       function render($page){
          if ( !empty($page) ){ 
             $page['title'] .= ' - '. $this->config['app']['name'] .' - '. $this->config['site']['name']; 
             $response['result'] = 'success';
             $block['template']['string'] = base64_encode('<h2>{$api.page.title}</h2>
                {if $api.page.image}
                   <div class=""><img src="{$api.page.image}"></div>
                {/if}
                {$api.page.content}
                Collection: 
                {foreach $api.collections as $collection}
                   <a href="{$collection.slug}" rel="tag">{$collection.name}</a>
                {/foreach}
             ');
             $block['api']['page'] = $page;
             $response['blocks']['main'] = $block;
             $response['blocks']['top']['order'] = 0;
             $response['blocks']['top']['api']['order'] = 1;
             $response['blocks']['top']['menu'] =  [ 
                0 => [
                   'name' => 'Blog Add',
                   'slug' => '/category/blog_add',
                   'children' => [
                      19 => [
                         'type' => 'Page',
                         'name' => 'New Post',
                         'slug' => '/new-custom-post'
                      ],
                      31 => [
                         'type' => 'Page::Collection',
                         'name' => 'News',
                         'slug' => '/category/news-category'
                      ]
                   ] 
                ]    
             ];
    
             $response['blocks']['footer']['output'] = 'Extra footer content';
          } else {
             $response['result']  = 'error';
             $response['message'] = 'Invalid submitted data '. print_r($page, true);
          }
    
          return $response;
       }
    
       /* Render a category via website */
       function renderCollection($page){
          if ( !empty($page) ){ 
             $response['result'] = 'success';
             $block['api']['page'] = $page;
             $block['template']['string'] = base64_encode('{foreach $api.collections as $item}
                <h2>{$item.title}</h2>
                {if $item.image}
                   <div class=""><img src="{$item.image}" class=""></div>
                {/if}
             {/foreach}
             ');
             $response['blocks']['main'] = $block;
          } else {
             $response['result']  = 'error';
             $response['message'] = 'Invalid submitted data '. print_r($block, true);
          }
    
          return $response;
       }	
    }