This is an old revision of the document!


Feng Office Plugin Tutorial: Hello World

In this tutorial you will be able to create a basic plugin, that will provide you general understanding of how Feng Office Plugin System works and how to develop more complex extensions for this platform.

First of all, choose the plugin name - which we will call PLUGIN_NAME to make it generic -, in this case: 'helloworld' Create a folder named 'PLUGIN_NAME' under FENGOFFICE_ROOT/plugins.

All the necessary resources and code for your plugin will be placed here: javascripts, css, images, php (templates, views, controllers, models).

The first file you need to create is the plugin metadata 'info.php'. Create this file under you plugin root folder 'plugins/PLUGIN_NAME/info.php' containing this php code:

<?php return array(
    "name" => "helloworld", //name of the plugin
    "version" => "1", //version of the plugin
    "author" => "Feng Office", //author
    "website" => "http://fengoffice.com", //website of the author
    "description" => "First plugin in Feng" //brief description of the plugin	
);?>

This will provide information about the plugin version, description, order, dependencies, category, author and other metadata necessary for third party plugin management.

If you want to create a new tab, you will have to specifiy it as following, so when the plugin is installed, the tab is created:

<?php return array(
    "name" => "helloworld",
    "version" => "1",
    "author" => "Feng Office",
    "website" => "http://fengoffice.com",
    "description" => "First plugin in Feng",	
    "tabs" => array ( //tab creation
                array(
			"id" => "helloworld-panel", //plugin id
                        "ordering" => 2, //order of the tab when shown among the rest, 0 being the first
                        "title" => "helloworld tab", //lang that will be used to specify the tab name
                        "icon_cls" => "ico-world", // CSS class for tab's icon
                        "refresh_on_context_change" => true,
                        "default_controller" => "helloworld", //name of the controller 
                        "default_action" => "say_hello" , //first action it will do when loading 
                        "initial_controller" => "" ,
                        "initial_action" => "" ,
                        "type" => "plugin", //type
                        "object_type_id" => 0 //id of the content object if it is related to one, otherwise 0                        
                )
     )
);?>        

Note: Please look below at the 'Email' plugin example for further details regarding a content object association.

This tells the installer that it will have to create a new tab in the system, specifying id, title and many other configuration options, but the most important ones are default_controller and default_action.

The tab title will be looked up in a language file. In our case the lookup string will be “helloworld tab”. We need to provide a return string in the language file. Create the language folder 'plugins/PLUGIN_NAME/language/LANGUAGE', in our case 'plugins/helloworld/language/en_us'. Two files are placed into this folder: 'lang.js' and 'lang.php'. Simply copy the lang.js script from another plugin, and create 'lang.php' as follows:

<?php return array(
	'helloworld tab'=>'World',
);

This will display 'World' as the our new tab's title. For multi-lingual support you may repeat this process for other languages.

At this point we are assuming that you are familiar to MVC concepts, so if this is not your case, we strongly suggest you to read some other documentation about this design pattern before moving forward.

Create the folder 'application/controllers' under your plugin structure - so that it looks like FENG_ROOT/plugins/PLUGIN_NAME/application/controllers -, and create the following class under this folder:

Name of the class: [PLUGIN_NAME]Controller.class.php ⇒ i.e.: HelloworldController.class.php

<?php class HelloworldController extends ApplicationController {                
        var $plugin_name = "helloworld"; //name of the plugin
 
        function __construct() {
                parent::__construct();
                prepare_company_website_controller($this, 'website');              
        }

        function say_hello() {
                $txt = "Hello World ! ! ! ! ";
                tpl_assign('message',$txt);
        }
}?>

In this case the controller loads the data, and assigns it to the view in a variable called 'message'.

Notes:

  • We have not spoken about models yet, so the data is hard-coded in order to simplify the example.
  • This is not what the actual Mail plugin does, but it has been used this way to explain it better

Create the folders 'application/views/helloworld' under your plugin structure so that it looks like: FENG_ROOT/plugin/PLUGIN_NAME/application/views/OBJECT_NAME

i.e.: FENG_ROOT/plugin/helloworld/application/views/helloworld

Within the last folder, create the following file: 'say_hello.php' with the following content:

<div class="hello-world">
        <h1><?php echo $message ?></h1>
        <p>Congratulations ! ! !</p> 
        <p>This is your first hello world application. <p>
</div>

Note: When invoking a cotroller action (or method talking in OOP), the system automatically loads the view named 'ACTION.php'.

In info.php we set the array element

"icon_cls" => "ico-world"

and now we need to create a CSS class .ico-world that styles a background with the desired icon image.

Edit the relevant CSS stylesheet for the theme's tabs, in our case 'public/assets/themes/default/stylesheets/file/types.css' and insert a style for the class .ico-world (in this case we used the default theme,s 16×16 sprites, vertical offset -357 pixels)

.ico-world {
	background: transparent url(../../images/16x16/all_16_16_vertical.png) no-repeat scroll 0 -357px !important;
}

Custom CSS and JS can be done in many ways:

INLINE (not recommended):

Each view can make use of <script> and <style> tags, but this does not follow the best practices of web development

Automatically load the css JS (recommended):

While loading a page, Feng Office will include the JS and css on its head section if you create those files following this convention: plugins/PLG_NAME/public/assets/javascript/PLG_NAME.js plugins/PLG_NAME/public/assets/css/PLG_NAME.css

At Runtime

In any place of your controller method add the following line: require_javascript('WhateverYorJsIsNamed.js', $this→plugin_name); Sometimes you want to include JS libraries only on some user actions, so this way is better if that is your case.

If you don't see the 'Plugins' icon in the Administration panel, then enable it by editing 'config/config.php' and inserting the line:

define('PLUGIN_MANAGER', true);

Close and restart Feng Office and navigate to Adminstration → Plugins. You should now see an entry for 'helloworld' and an 'Install' link just below. Click the 'Install' link and, if successful, click the 'Activate' link. Now refresh the browser (Ctrl+F5) and you should see your new tab “World” appear. If not, check the tab ordering for conflicts (Administration → Tabs) and retry.

Example with the Email Plugin

In this case we will take the Email plugin as an example provided that anyone can access its source code. The plugin name is 'mail'.

Create a folder named 'PLUGIN_NAME' under FENGOFFICE_ROOT/plugins.

All the necessary resources and code for your plugin will be placed here: javascripts, css, images, php (templates, views, controllers, models).

The first file you need to create is the plugin metadata 'info.php'. Create this file under you plugin root folder 'plugins/PLUGIN_NAME/info.php' containing this php code:

<?php return array(
        "name" => "mail", //name of the plugin
	"version" => "1", //version of the plugin
	"author" => "Feng Office", //author
	"website" => "http://fengoffice.com", //website of the author
	"description" => "Email web client", //brief description of the plugin
	"dependences" => array('core_dimensions'), //if the plugin depends on another plugin to work correctly
	"order" => 1
);?>

This will provide information about the plugin version, description, order, dependences, category, author and other metadata necessary for third party plugin management.

If you want to create a new tab or associate it with a content object, you have to specify to the metadata file some extra configuration as shown below:

<?php return array(
    "name" => "mail",
	"version" => "2",
	"author" => "Feng Office",
	"website" => "http://fengoffice.com",
	"description" => "Email web client",
	"dependences" => array('core_dimensions'),// Array of plugin names (TODO check dependences)
	"order" => 1,
        "types" => array ( //association with a content object
		array(
			"id" => 22, //id of the content object
			"name" => "mail", //content object name
			"handler_class" => "MailContents", //name of the handler class
			"table_name" => "mail_contents", //name of the table containing it
			"type" => "content_object", 
			"icon" => "mail", //icon of the content object
			
		)
	),
    "tabs" => array ( //tab creation
                array(
                        "id" => "mails-panel", //plugin id
                        "ordering" => 2, //order of the tab when shown among the rest, 0 being the first
                        "title" => "email tab", //lang that will be used to specify the tab name
                        "icon_cls" => "ico-mail",  //icon that the tab will have
                        "refresh_on_context_change" => true, 
                        "default_controller" => "mail", //name of the controller 
                        "default_action" => "init" , //first action it will do when loading 
                        "initial_controller" => "" , 
                        "initial_action" => "" ,
                        "type" => "plugin", //type
                        "object_type_id" => 22 //id of the content object if it is related to one
                )
     )
);?>        

This tells the installer that it will have to create a new tab in the system, specifying id, title and many other configuration options, but the most important ones are default_controller and default_action.

Create the folder 'application/controllers' under your plugin structure - so that it looks like FENG_ROOT/plugins/PLUGIN_NAME/application/controllers -, and create the following class under this folder:

Name of the class: [PLUGIN_NAME]Controller.class.php ⇒ i.e.: MailController.class.php

<?php class MailController extends ApplicationController {                
        var $plugin_name = "mail"; //name of the plugin
 
        function __construct() {
                parent::__construct();
                prepare_company_website_controller($this, 'website');
                Env::useHelper('MailUtilities.class', $this->plugin_name); //in case it needs an extra class to handle some functions
		require_javascript("AddMail.js",  $this->plugin_name); //in case it requires a JavaScript file to load certain data
        }

        function init() {
                //do something
        }
}?>