Advanced Extension Development Topics

Extenstion might require sometime more advanced approcahes, depending on the requirements. More advanced extension development solutions are discussed in this manual.

Database extension

You can utilize 3 approaches to store extension data to the database.
1. New tables can be created to support the data storage
2. Existing tables can be altered to add new fields and indexes.
3. Dataset tools are offered by AbanteCart to save data without creating or altering database.

As first two are straight forward, we will cover #3 in more details.
Dataset aproach offers quick and worry free method to handle data without dealing with SQL and creating specific database tables. Data can be handled via easy dataset class methods.
Good example for dataset usage will be ocasionaly edited information for products, categories, customers and orders data extension, polls, questioners, etc.

Note

It is not recommended to use dataset for large sets and transactional type of data, since performance might be affected. Eventhough, we tested performance with 500000 rows, and no slowdown noticed, it is still not desired to use this storage for high traffic read and write.

What is Dataset?
Say you need to develop a poll extension and need to store records of poll questions and answers. Normally, you would create and add 2 or more tables to the databases to handle data for the poll. With the dataset, we created an abstraction layer to the database, that allows you to skip database creation and go directly to handling data.
Dataset class will handle all the data storing and management for you with interface of methods provided. It is very easy. You name new dataset (traditionally table) or use existing dataset . Dataset can be created during extension installation from XML file provided in the extension package. It can be also removed with extension uninstall. No direct access to SQL or database is needed. If restriction access required to the dataset, it needs to be handled pragmatically based on AbanteCart permissions. If you decide to use traditional database tables in extension, you will need to create SQL scripts with install, uninstall and disable extension management process.

How does Dataset work?
First you have to recognize namings in dataset class. There are “object”, “datarow”, “fieldset” and their “definitions”.

caption

“Object” is any abstract part of your extension or core. It may be anything that we call “owner”. Object is owner of data sets. Menu, charts, polls, etc. may contain some data, therefore, they are owners of data sets, objects. “Object” entity have two attributes: name and key. Name is common text unique identifier of the object (menu, poll, etc). “Key” is identifier from another section or table of AbanteCart, for example, extension’s key(id). Pair “name-key” must be unique. Key can be also understood as a sort of foreign key to any other table in the system. Key is not required and if not provided name part of the object needs to stay unique. Foreign key connection to any table can be also build pragmatically with use any field in the dataset fieldset.
Key can also be a subset name in case of multiple tables used within one feature or set.


caption

In our poll example you have poll_questions and poll_answers tables. You will create 2 datasets as following:

copy

$poll_qs = new ADataset();
$poll_qs -> createDataset('poll','poll_questions');
$poll_asw = new ADataset();	
$poll_asw -> createDataset('poll','poll_answers');

 	

To work with dataset object you just create a new instance of dataset class or use one that you have created before:

copy

//Create new instance:
$my_data_obj = new ADataset ( $object_name, $object_key );
After you create a new dataset you can set properties to the dataset. These properties are global to given dataset and can be always be accessible. Properties can be some generic values that give a state to the dataset:
$my_data_obj->setDatasetProperties(  array( name => value, ….  )  );

 	

or

copy

$poll_qs->setDatasetProperties(	 array(  	'start_date'=>'2011-07-01 12:00',
   					 	'stop_date'=>'2011-08-01 12:00')	);
 	

Setting properties method:

copy

$my_data -> setDatasetProperties(	
 array( 	 "some_property_name"=>”some_value”, 			
"some_property_name"=>"some_value”) );
 	

Note

property’s name and value have limit size at 255 characters. Method setDatasetProperties completely changes values of properties, without updating.

Properties can be accessed with getDatasetProperties() method. This method returns an array with all the properties:

copy

$my_data_obj->getDatasetProperties();	
 	

Next step for new dataset, is to set columns and properties for them. This is similar in concept of creating fields for the database. Each dataset is a representation of one table and it has columns and rows.

copy

// define columns for questions
$poll_qs->defineColumns (
   		 array ( "name"=>"language_code",
   			 "type"=>"varchar"),
   		 array ( "name"=>"question",
   			 "type"=>"text"),
      		 };
      		 
 	

Dataset’s columns definition contain list of value’s descriptions (fields). Every dataset consist of columns or fieldset. Now dataset concept supports following column types:
integer
float
varchar
text
boolean
timestamp

Note

if you need to identify rows in your dataset by id, you need to create a column and make sure in your code to provide this value unique. If you later call getRows with your unique field and value, you will always get one unique row.

copy

//set properties for the dataset
$poll_qs->setColumnProperties ( 
array ( "column_name" => "language_code",
   				 "property_name" => "length",
   				 "property_value" => "2" ),		
array ( "column_name" => "question",
   				 "property_name" => "translation_key",
   				 "property_value" => "question_txt" ),		 
   			 );
 	

Column properties are used to keep global information for the columns for the given dataset . This properties can be used to identify data type and constrains for the column. Validation code can use these properties before saving data.

In some cases, column properties can be used to store data and act as 1 row table. If you have only 1 row of data and it is not changing you can just use columns properties to store data and avoid extra step to use rows.
Columns properties are not required, but helpful.
Actual data for the datasets is stored in rows that are similar to rows in traditional database or spreadsheet. Every row have columns (fields) that are set in the defineColumns method described above.

Let first see how we can add a row to example dataset:

copy

$poll_qs->addRows (  array(
	array(   language_code => “en”, question => “What color do you like?” ),
	array(   language_code => “en”, question => “What shape do you like?” )  
) );
 	

If all rows are inserted successful the return will be total number of rows added that shouldbe same as imputed array count.

Now we can select all the rows from the dataset

copy

$rows = poll_qs->getRows (); </pre>

 	

Or for big datasets we can search for specific row based on needed column:

copy

<pre class="brush:php;">$rows = poll_qs->searchRows ( array(   name=> “language_code”,  operator => “=”,  value => “en”   )  );  
 	

or

copy

$rows = poll_qs->searchRows ( array(   name=> “question”,  operator => “LIKE”,  value => “color”   )  ); 
 	

where “condition” may be one of list:
“=”
”>”
”<”
LIKE

To delete the row from the dataset you can simply call method deleteRows

copy

$my_data->deleteRows( array( "column_name"=>string, "operator"=>string, "value"=>string )  );
 	

If success, method will return total number of rows deleted.

To drop dataset you can use simple command:

copy

$my_data->dropDataset();
 	

Note

This method will completely delete data and settings in the dataset. Make sure you know what you do.

To make things simple to batch load there is a method to load data set via XML. You can create and populate data set with one function loadXML and simple XML node structure

XML Load Example:

copy

<?xml version="1.0" encoding="UTF-8"?>
<datasets>
	<dataset>
		<action>update</action>
		<dataset_name>abo</dataset_name>
		<dataset_key>menu</dataset_key>		
		<dataset_definition>
			<column_definition>
				<column_name>menu_id</column_name>
				<column_type>integer</column_type>
				<column_sort_order>1</column_sort_order>				
	 		</column_definition>
	 		<column_definition>
				<column_name>menu_name</column_name>
				<column_type>varchar</column_type>
				<column_sort_order>2</column_sort_order>				
	 		</column_definition>
	 		<column_definition>
				<column_name>menu_text</column_name>
				<column_type>varchar</column_type>
				<column_sort_order>3</column_sort_order>				
	 		</column_definition>
	 		<column_definition>
				<column_name>sort_order</column_name>
				<column_type>integer</column_type>
				<column_sort_order>4</column_sort_order>				
	 		</column_definition>	
	 	</dataset_definition>	 	

	 	<dataset_properties>
	 		<dataset_property>	 			
	 			<dataset_property_name>some_prop</dataset_property_name>
	 			<dataset_property_value>25100</dataset_property_value>
	 		</dataset_property>	 		 		
	 	</dataset_properties>

	 	
	 	<column_properties>
	 		<column_property>
	 			<column_name>menu_id</column_name>
	 			<column_property_name>max_id</column_property_name>
	 			<column_property_value>100</column_property_value>
	 		</column_property>
	 		<column_property>
	 			<column_name>menu_id</column_name>
	 			<column_property_name>min_id</column_property_name>
	 			<column_property_value>10</column_property_value>
	 		</column_property>	 		
	 	</column_properties>
	 	
	 	<dataset_rows>
	 		<dataset_row>
	 			<cell>
	 				<column_name>menu_id</column_name>
	 				<value>11</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_name</column_name>
	 				<value>some name1</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_text</column_name>
	 				<value>some text1</value>
	 			</cell>
	 			<cell>	
	 				<column_name>sort_order</column_name>
	 				<value>1</value>
	 			</cell>
	 		</dataset_row>
	 		<dataset_row>
	 			<cell>
	 				<column_name>menu_id</column_name>
	 				<value>12</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_name</column_name>
	 				<value>some name2</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_text</column_name>
	 				<value>some text2</value>
	 			</cell>
	 			<cell>	
	 				<column_name>sort_order</column_name>
	 				<value>2</value>
	 			</cell>
	 		</dataset_row>
	 		<dataset_row>
	 			<cell>
	 				<column_name>menu_id</column_name>
	 				<value>13</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_name</column_name>
	 				<value>some name3</value>
	 			</cell>
	 			<cell>	
	 				<column_name>menu_text</column_name>
	 				<value>some text3</value>
	 			</cell>
	 			<cell>	
	 				<column_name>sort_order</column_name>
	 				<value>3</value>
	 			</cell>
	 		</dataset_row>
	 	 </dataset_rows>	 	
	</dataset>
</datasets>

 	

Other methods
Extending Menus
We offer handy way to add menus when you install extension. This can be done with simple function that will do all the work of adding the menu for you to the proper place.

There is a library ‘menu_control.php’ with class AMenu. This class offers methods to control the menu for both storefront and control panel. You can add, delete menu items to access your extension. This can be done with simple call to aMenu class in install.php and in uninstall.php To install:

copy

// add new menu item
$menu = new AMenu ( "admin_menu" );
$menu->insertMenuItem ( array (        "item_id"=>»your-menu»,
				"item_text"=>»your_item_text_entry»,
			 "item_url"=>»your-item-url-or-route-to-controller»,
		 		"parent_id"=>»item_id-of-parent-item»,
				 "sort_order"=>»number»,
		 		"item_type" =>»optional-parameter-for-recognizing-items»));
		 		
 	

To uninstall:

copy

//delete menu item
$menu = new AMenu ( "admin_menu" );
$menu->deleteMenuItem ("sale_your-menu");
 	

Final menu id after it is created is represented based on menu levels. It will have following structure [parent]_[parent]_....[your_menu] and as in our example it is sale_your-menu To avoid conflicts with other extensions, try to create unique menu name. Do not create generic names like products or orders.

Working with Forms

There are 2 types of forms in AbanteCart, FlexyForms and standards forms. Both forms are using the same classes to draw the form and HTML elements. Main difference between the two is that FlexyForms are loaded from the data base automatically with LoadFormDB() function.

Standard form is build in the code and FlexyForms are mainly used in storefront to provide flexibility to cart admin to edit fields, add new forms, and also ability to extend forms/fields with extensions. In AbanteCart control panel we use standard forms, but blended with FlexyForms. Since control panel mainly consists of forms, it will be heavy load to provide database driven forms. FlexyForms approach in the control panel gives ability to add (extend) fields to the forms with added extensions.
There are 3 types of field sets that are used in AbanteCart. These types are based on the way fields respond to changes. Standard type - On fields changes, no changes are highlighted. This is a standard most known fields that are used in allwebsite. In AbanteCart these fields are used in storefront, and for search and non-update related fields in control panel. Highlight on change - These fields will change color once you change the value in the fields. They will change back the color if you change the value back to original. This is very helpful in UI to show users that data was changed and requires attention or saving.

Highlight and save - These fields will not only change color, but will also show the option to save or reset the value. Changed field can be saved individually right after edit, or if change in accident. it can be reset. This is very handy in the areas with big forms and improve user experience and user error.

Extending and Creating FlexyForms

FlexyForm set up consists of 3 important components: Database entry, Processing Controller and Template. Below is a diagram that can give more idea how FlexyForms are structured: caption

Lets look into Controller and PHP code Create an instance of the class AForm:

copy

	$this->form = new AForm('testForm'); 
 	
 	

Note

testForm -> Form Name and ID that needs to be unique Now we need to load this from data to the form instance from the database. We assume we already have it in there. We explain later how to add form to the database.

copy

$this->form->loadFromDb('testForm');
 	

Since we have all the form data, fields and settings for the form loaded from the database, we are ready to generate FlexyForm code and pass to the template to be displayed.
To display form you just pass output of getFormHtml() function:

copy

$this->view->assign('form_output', $this->form->getFormHtml() );

 	

Note

'form_output' is the name of variable in the template to display the form’s HTML

Run the form template or any other template to display the form:

copy

$this->processTemplate('pages/index/form.tpl' );
 	

Validation:
At some point you need to add validation code to check submited values of the form.
You can see example below how this can be done:

copy

if ( $this->request->server['REQUEST_METHOD'] == 'POST' ) {
        	if ( $this->validateForm() ) {
            	//this message should be loaded from language file
            	$this->session->data['success'] = 'Success';
            	$f = $this->form->getForm();
		//success_page can be set for the for in the database. 
            		$this->redirect($this->html->getSecureURL($f['success_page']));
        	} else {
            		$this->form->setErrors($this->errors);
            		$this->form->batchAssign($this->request->post);
        	}
    	}
 	

Validation function is pretty simple In sample case we just check if all required fields filled. You can easily extend this function to meet your needs.

copy

private function validateForm() {

    $this->errors = array();
    $fields = $this->form->getFields();
    foreach( $fields as $name => $data) {
   	 if ( $data['required'] == 'Y' && empty($this->request->post[$name]) ) {
   		 $this->errors[$name] = 'This field is required';
   	 }
    }

    if ( !empty($this->errors) ) {
   	 return false;
    } else {
   	 return true;
    }
}
 	
 	

To assign values to form fields you can call 2 methods assign() and batchAssign().
Here is an example how it is done:

copy

$this->form->assign( 'field_name',  'field_value' )
$this->form->batchAssign( array(
'field_name' => 'field_value',
'field_name' => 'field_value',
'field_name' => 'field_value',
 ) )
 
 	

If you have multiselect field or checkbox group field, you need to pass an array.

copy

$this->form->assign( 'field_name',  array(‘value1’, ‘value2’..., ‘valueN’) )

 	

Now let’s look in the template that actually contains the code to displays the form. In the template you need to include the form output in the place you need form to show:

copy

<div class="from_wrapper">
    <?php echo $form_out; ?>
  </div>
 	

Form CSS style will be based on the standard style set in the AbanteCart. You can modify the style by including your own CSS. To modify: Locate original CSS for the form in appropriate stylesheet location for admin or storefront.

TIP: In some browsers (Firefox with Firebug or Safari) you can use feature to inspect HTML elements. This is very handy to understand how CSS and HTML structured on the pages.


To add your own styles you can include CSS:

copy

$this->document->addStyle("path/to/css");
 	

Note

It is very recommended that you add this only to your extension or create extension. If you change CSS file in original location it might be replaced at your next upgrade or in some cases upgrade might fail.

You are now done with building the form code and display of the form

Now you need to set fields to the database. You can use different methods to set and save form settings and fields to the database. There is a traditional SQL inserts or updates that can be used. We have following tables that needs to be used to manage forms data:

caption

In addition to traditional SQL method we offer a convenience of build in functions in the library to simplify adding, deleting or editing FlexyForms database. These can be used for extension install and uninstall process and in the control panel to manage FlexyForm settings.

Example of xml file for form loading:

copy

<?xml version="1.0" encoding="UTF-8"?>    
    <forms>
   	 <form>
   		 <action></action>
   		 <form_name>some form</form_name>
   		 <controller>testcase/testcase</controller>
   		 <success_page>/pages/testcase/success</success_page>
   		 <status>active</status>
   		 <form_descriptions>
   			 <form_description>
   				 <language>english</language>
   				 <description>some form for loading by XML-load</description>
   			 </form_description>
   		 </form_descriptions>
   		 <fields>
   			 <field>
   				 <action></action>
   				 <field_name>fld_name</field_name>
   				 <element_type>I</element_type>
   				 <sort_order>1</sort_order>
   				 <attributes>onclick="alert('some alert text!!!')"</attributes>
   				 <required>Y</required>
   				 <status>1</status>
   				 <field_descriptions>
   					 <field_description>
   						 <language>english</language>
   						 <name>some input</name>
   						 <description>some description</description>
   					 </field_description>   				 
   				 </field_descriptions>   				 
   			 </field>
   			 <field_groups>
   				 <field_group>
   					 <action>insert</action>
   					 <name>Some field group name</name>
   					 <sort_order>2</sort_order>
   					 <status>1</status>
   					 <field_group_descriptions>
   						 <field_group_description>
   							 <language>english</language>
   							 <name>some field group</name>
   							 <description>some description</description>   
   						 </field_group_description>
   					 </field_group_descriptions>			 
   					 <fields>
   			   		     <field>
   						      <action></action>
   						      <field_name>input in group</field_name>
   						      <element_type>I</element_type>
   						      <sort_order>1</sort_order>
   						      <attribues></attribues>
   						      <required>Y</required>
   						      <status>1</status>
   					     <field_descriptions>
   					 	 <field_description>
   						    <language>english</language>
   						    <name>some input in group</name>
   						    <description>somedescription</description>
   								 </field_description>   				 
   					      </field_descriptions>    
   					   </field>   					 
   					   <field>
   							 <action>insert</action>
   							 <field_name>some select</field_name>
   							 <element_type>S</element_type>
   							 <sort_order>2</sort_order>
   							 <attribues></attribues>
   							 <required>Y</required>
   							 <status>1</status>
   							 <field_values>
   								 <field_value>
   									 <language>english</language>
   									 <opt_value>1</opt_value>
   									 <value>select me 1</value>
   									 <default>0</default>
   									 <sort_order>1</sort_order>
   								 </field_value>
   								 <field_value>
   									 <language>english</language>
   									 <opt_value>2</opt_value>
   									 <value>select me 2</value>
   									 <default>1</default>
   									 <sort_order>2</sort_order>
   								 </field_value>
   								 <field_value>
   									 <language>english</language>
   									 <opt_value>3</opt_value>
   									 <value>select me 3</value>
   									 <default>0</default>
   									 <sort_order>3</sort_order>
   								 </field_value>
   							 </field_values>    
   						 </field>  
   					 </fields>   	
   				 </field_group>
   			 </field_groups>
   		 </fields>   		 
   	 </form>    
    </forms>
    
 	

Create or Extend Standard Form with AForm Class
AbanteCart offers unified methods to create forms and load HTML form elements such as form data and fields. There are 2 main classes AForm and AHtml that are inter-connected to give better control and flexibility of the form.
To create a form you need to create an instance of class AForm and continue with using methods.
See Example:

copy

$form = new AForm();
	//Set the form
        	$form->setForm( array(
                	'form_name' => 'example_form_name',
        	));
	//Set form name and id
    	$form_data['example_form']['id'] = 'example_form_name';
	//Create a form open tag
    	$form_data['example_form']['form_open'] = $form->getFieldHtml(array(
                	'type' => 'form',
                	'name' => 'example_form_name',
                	'action' => '',
        	));
    	$form_data['example_form']['submit'] = $form->getFieldHtml(array(
                	'type' => 'button',
                	'name' => 'submit',
                	'text' => $this->language->get('button_go'),
                	'style' => 'button5',
        	));

$this->view->batchAssign( $form_data );
            	$this->processTemplate('pages/example.tpl' );
 	

To set selected value for the selectbox, checkboxgroup and multiselect elements, for example, you need to pass options array with available options to select and you can pass “value” parameter (as selected value(s) ) that can be singe value or array;

copy

$this->form->getFieldHtml(array(
 		'type' => 'selectbox',
 		'name' => 'multiple',
 	'options' => array( 1=>'1', 2=>'2', 3=>'3'),
 	'value' => 1,
	)); 
 	

copy

$this->form->getFieldHtml(array(
 		'type' => 'multipleselectbox',
 		'name' => 'multiple',
 		'options' => array( 1=>'1', 2=>'2', 3=>'3'),
 		'value' => array(1=>1, 2=>2),
	));
	
 	

Available field types as part of AForm class: input, textarea, selectbox, multiselectbox, radio, checkbox, checkboxgroup, file, and hidden
Available methods as part of AHtml class:

copy

getURL($rt, $params = '') 
    	getSecureURL($rt, $params = '') 
    	getSEOURL($rt, $params = '') 
    	getCatalogURL($rt, $params = '') 
    	getImagePath() 
	buildElement($data) 
	buildHidden($data) 
	buildInput($data) 
	buildPassword($data) 
buildPasswordset($data)
	buildSelectbox($data) 
buildMultiselectbox($data)
	buildTextarea($data) 
    	buildCheckbox($data) 
    	buildCheckboxGroup($data) 
	buildFile($data) 
	buildButton($data) 
	buildForm($data) 
buildCaptcha($data) 
 	

You can build HTML element via Form object Reference or via html object methods: Example:

build Input Element via form object

copy

string  $form->getFieldHtml( array(
   	 	'type' => 'input',
   	 	'name' => 'field_name',
   	 	'value' => 'field_value',
    	));
 	

build Input Element via html object

copy

     	string  $this->html->buildInput( array(
   	 	'name' => 'field_name',
   	 	'value' => 'field_value',
    	));
 	

build Input Element via html object

copy

     	string  $this->html->buildElement( array(
   	 	'type' => 'input',
   	 	'name' => 'field_name',
   	 	'value' => 'field_value',
    	));
 	

build Button Element

copy

$form->getFieldHtml(array(
    'type' => 'button',
    'name' => 'submit',
    'text' => ‘button_save’,
    'style' => 'button1',
));
 	

build Selectbox Element

copy

$form->getFieldHtml(array(
    'type' => 'selectbox',
    'name' => 'manufacturer_id',
    'value' => 'manufacturer_id',
    'options' => array(
option_value => option_text,
option_value => option_text,
option_value => option_text,
    ),
))
 	

Extend Standard Forms

To extend or add fields to standard form you need to create FlexyForm entry with the same form name. You need to add to FlexyForm all new (additional) fields that you need to be added to the form. These additional fields will be loaded at the end of the form with method loadExtendedFields(). Each standard form code should have this call to allow extensions to add fields to the form:

copy

$this->form->loadExtendedFields('testFrm');
 	

Example how to add extended fields from FlexyForm to standard form:

copy

$this->form = new AForm();
// Standard form code 
...
$this->form->loadFromDb('testFrm');
$extended_fields = $this->form->loadExtendedFields();
$this->view->assign('extended_fields', $extended_fields);

 	

In the template you need to add code below within the form scope:

copy

<?php echo $extended_fields ?>
</form> 
 	
 	

Setting Up Data Listing Pages with Grid

To list data in Control Panel pages, AbanteCart utilise jqGrid (by Tony Tomov, www.trirand.com/blog). This approach is unified and applied on all pages that use data listing. There is a standard interface to jqGrid that is set up as child controller. Any new page building data listing needs to include jqGrid controller and child and build data and settings. Settings are pass to controller directly and data loaded by jqGrid controller via remote ajax call to response controller.

Main idea for this concept is to prepare the format and settings for the fata and load actual data based on set format and settings. Main page controller is responsible for building data format and settings and remote AJAX controller will prepare and provide the data to be listed in the grid. Grid controller that is a common “blackbox” element shared by everybody, will display the data in a format requested.

Bellow is the description of the settings and data provided to grid controller: There are 2 parts to grid: main page controller and ajax (response) controller

Main Page controller
This controller includes grid as a child and prepare all the settings for the grid to give it a desired state. Settings include, list of fields, actions, search values, and edit/view restrictions.

All settings are set into one array that will be passed to child listing_grid controller.

Here is the process based on the example how to include grid to the main controller:

First you need to provide main settings for grid to operate. These include table name (table_id), URL, edit action URL, Default sort column, actions allowed for each row.

copy

$grid_settings = array(
   		 'table_id' => 'lang_definition_grid',
   		 'url' => $this->html->getSecureURL('listing_grid/language_definitions'),
   		 'editurl' => $this->html->getSecureURL('listing_grid/language_definitions/update'),
        	'update_field' => $this->html->getSecureURL('listing_grid/language_definitions/update_field'),
   		 'sortname' => 'module',
        		'actions' => array(
            		'edit' => array(
                		'text' => $this->language->get('text_edit'),
   			 'href' => $this->html->getSecureURL('localisation/language_definitions/update', '&language_definition_id=%ID%')
            		),
            		'delete' => array(
                		'text' => $this->language->get('button_delete'),
            		),
            		'save' => array(
                		'text' => $this->language->get('button_save'),
            		),
        	),
   	 );
 	

You need to specify column names and settings per each column.
You can set name, index, width, sorttype, align, and more. By default, if you do not set any width, it will be automatic (recommended). If you set the width, you need to set width for every column.
For more settings options for jqGrid, you can refer to www.trirand.com/blog

copy

//Set column names and order
$grid_settings['colNames'] = array(
            			$this->language->get('column_module'),
			$this->language->get('column_key'),
			$this->language->get('column_translation'),
		);
//Set column definition 
		$grid_settings['colModel'] = array(
			array(
				'name' => 'module',
				'index' => 'module',
                			'align' => 'center',
				'sorttype' => 'string',
			),
           			 array(
				'name' => 'language_key',
				'index' => 'language_key',
				'align' => 'center',
				'sorttype' => 'string',
			),
			array(
				'name' => 'language_value',
				'index' => 'language_value',
                			'align' => 'center',
				'sorttype' => 'string',
               				 'sortable' => false,
			),
);
		//Load grid child controller and get result 
      	  	$grid = $this->dispatch('common/listing_grid', array( $grid_settings ) );
		$this->view->assign('listing_grid', $grid->dispatchGetOutput());
 	

Additional parameters and settings:
You can specify the master search form that will show above the grid and can perform specific searches and update the list result

copy

$form = new AForm();
    	$form->setForm(array(
   	 	'form_name' => 'lang_definition_grid_search',
    	));

    	$listing_data['search_form']['id'] = 'lang_definition_grid_search';
    	$listing_data['search_form']['form_open'] = $form->getFieldHtml(array(
   	 	'type' => 'form',
   	 	'name' => 'lang_definition_grid_search',
   	 	'action' => '',
    	));
    	$listing_data['search_form']['submit'] = $form->getFieldHtml(array(
   	 	'type' => 'button',
   	 	'name' => 'submit',
   	 	'text' => $this->language->get('button_go'),
   	 	'style' => 'button',
    	));

    	$listing_data['search_form']['fields']['language_key'] = $this->language->get('entry_language_key') . $form->getFieldHtml(array(
   	 	'type' => 'input',
   	 	'name' => 'language_key',
    	));
    	$listing_data['search_form']['fields']['section'] = $this->language->get('entry_section') . $form->getFieldHtml(array(
   	 	'type' => 'selectbox',
   	 	'name' => 'section',
        	'options' => array(
            		'' => $this->language->get('text_select'),
            		1 => $this->language->get('text_admin'),
            		0 => $this->language->get('text_storefront'),
        		),
    	));
 	

Ajax (response) controller
This controller builds data set for the grid to display. Grid does the remote (separate) HTTP(S) call to load the data.

Here is the process based on the example how to build data set and provide it to the gird: …..


Main grid controller: admin\controller\common\listing_grid.php

For more details to data format check jqGrid manuals: http://www.trirand.com/jqgridwiki/doku.php?id=wiki:retrieving_data


We suggest to try extension developer tools to create your extension. This will help you avoid tedious work of creating necessary files. Dev Tools Extension on Github