Sunday, May 18, 2014

title: using wordpress WP_List_Table in the frontend WP_List_Table is a cool class to display list of items in the admin panel. You dont directly use this class rather create a child/derived class of it and override some methods defined in the base class (WP_List_Table in this case). you are done! you'll have the same wordpress look and feel, same functionality doing very little coding. But unfortunately this great piece of code is not available to use in the frontend. But tiny trick and modification can make it easy to use in the frontend part of your plugin. Here I'll tell you how i did this: firstly,create a new file which will contain a class definition that is extended from WP_List_Table.At the beginning of this file, include WP_List_Table from wp-admin/include.Probably you'll want to copy that WP_List_Table definition file into your plugin directory and include it (usually i do this).
include_once('class-wp-list-table.php'); // assuming you copied the file into your plugin directory.
class User_List extends WP_List_Table {

secondly, WP_List_Table depends on few (for the most part two) function which are not available in the frontend. copy them from wp-admin/includes/template.php and paste on the top of the file you just created. you may want to avoid copying this by modifying WP_List_Table. But I prefer to keep it intact. Required functions are:
if(!is_admin()){
	function get_submit_button( $text = NULL, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = NULL ) {
		switch ( $type ) :
			case 'primary' :
			case 'secondary' :
				$class = 'button-' . $type;
				break;
			case 'delete' :
				$class = 'button-secondary delete';
				break;
			default :
				$class = $type; // Custom cases can just pass in the classes they want to be used
		endswitch;
		$text = ( NULL == $text ) ? __( 'Save Changes' ) : $text;
	
		// Default the id attribute to $name unless an id was specifically provided in $other_attributes
		$id = $name;
		if ( is_array( $other_attributes ) && isset( $other_attributes['id'] ) ) {
			$id = $other_attributes['id'];
			unset( $other_attributes['id'] );
		}
	
		$attributes = '';
		if ( is_array( $other_attributes ) ) {
			foreach ( $other_attributes as $attribute => $value ) {
				$attributes .= $attribute . '="' . esc_attr( $value ) . '" '; // Trailing space is important
			}
		} else if ( !empty( $other_attributes ) ) { // Attributes provided as a string
			$attributes = $other_attributes;
		}
	
		$button = '';
	
		if ( $wrap ) {
			$button = '
' . $button . '
'; } /* TODO - colum_XX replace XX with your table's key/id column field value. The actions (edit, delete etc.) will be added to this column in the list */ function column_member_id($item){ //Build row actions (we are only alowing "Delete" option for this list) $actions = array(); //Use the folloiwng instead of the above if you want to add both edit and delete options for each row of the list // $actions = array( // 'edit' => sprintf('Edit',$item['id']), // 'delete' => sprintf('Delete',$_REQUEST['page'],'1',$item['id']), // ); //Return the refid column contents return $item['member_id'] . $this->row_actions($actions); } return $button; } function submit_button( $text = NULL, $type = 'primary', $name = 'submit', $wrap = true, $other_attributes = NULL ) { echo get_submit_button( $text, $type, $name, $wrap, $other_attributes ); } }
you'll notice that i wrapped the definitions with is_admin function. you can use is_front_page or function_exists. Thirdly, You need to override some methods in the child class. this is mandatory. Methods are : 1. __construct() this is typical constructor method but few things to note:
    function __construct(){
        global $status, $page;        
        //Set parent defaults
        parent::__construct( array(
            /**
            * you'll have to define a css class and you'll have to use  uncamelcased and 
            * white-space removed version ( userlist in this case)  of list name as the css class name.
            */
            'singular'  => 'User List', //singular name of the listed records
            'plural'    => 'User List', //plural name of the listed records
            'ajax'      => false //does this table support ajax?
        ) );           
   
2. column_cb() this method defines how the checkbox on the left of the table should behave. usually it represents the value of primary key of the db table. typical implementation may look like the following:
    function column_cb($item){
        return sprintf(
            '',
            /*$1%s*/ $this->_args['singular'], //Let's reuse singular label (User List)
            /*$2%s*/ $item['id'] //The value of the checkbox should be the record's key/id
        );
    }   
   
3. get_columns() you'll define which columns you want to display in the list in this method. it returns a key/value. key should be exactly the database field name and value will be the label you want to show in the table column header. 4.get_sortable_columns() you'll define which columns you want to be sortable in the function.
   function prepare_items(){
        // Lets decide how many records per page to show         
        $per_page = 30;                
        $columns = $this->get_columns();
        $hidden = array();
        $sortable = $this->get_sortable_columns();                
        $this->_column_headers = array($columns, $hidden, $sortable);                
        $this->process_bulk_action();                                      
        // This checks for sorting input and sets the sort order parameters accordingly.
        $orderby_column = isset($_GET['orderby'])?$_GET['orderby']:'';
        $sort_order = isset($_GET['order'])?$_GET['order']:'';
        if(empty($orderby_column)){//set the default orderby column if it is empty
        	$orderby_column = "member_id";
        	$sort_order = "ASC";
        }
        //Query the database table and prepare our data that will be used to list the items
    	global $wpdb;
        $query = "SELECT * FROM xyz ORDER BY $orderby_column $sort_order";        
        $data = $wpdb->get_results($query, ARRAY_A);
		//pagination requirement
        $current_page = $this->get_pagenum();        
        //pagination requirement
        $total_items = count($data);                
        //pagination requirement
        $data = array_slice($data,(($current_page-1)*$per_page),$per_page);                        
        // Now we add our *sorted* data to the items property, where it can be used by the rest of the class.
        $this->items = $data;                
        //pagination requirement
        $this->set_pagination_args( array(
            'total_items' => $total_items,                  //WE have to calculate the total number of items
            'per_page'    => $per_page,                     //WE have to determine how many items to show on a page
            'total_pages' => ceil($total_items/$per_page)   //WE have to calculate the total number of pages
        ) );   
    }
   
Lastly, Some css stuff to make the list pretty.
    .userlist{
        border: 1px solid #DFDFDF;
    }
    .userlist td, .userlist th {
        font-family: Georgia,"Times New Roman";
        font-size: 14px;
        color: #333333;
        text-align: left;
        border-style: solid;
        border-width: 1px 0;
        overflow: hidden;
        border-bottom-color: #DFDFDF;
        border-top-color: #FFFFFF;
        padding:5px;
    }
    .userlist th {
        text-shadow: 0 1px 0 rgba(255, 255, 255, 0.8);
        font-family: Georgia,"Times New Roman";
        color: #333333;
        text-align: left;    
    }
    .top{
        margin-bottom: 5px;    
    }
    .bottom{
        margin-top: 5px;
    }
    .tablenav{
        background-color: #F3F3F3;
        border: 1px solid #DDDDDD;
        height: 30px;
        padding: 4px;  
        text-align: right;  
    }
    .tablenav .tablenav-pages{  
        display:block;
        margin-top:4px 0;
        width:100%; 
    }
    .tablenav .tablenav-pages {
        cursor: default;
        font-size: 12px;
        line-height: 30px;
        color: #555555;    
    }
    .tablenav .displaying-num {
        margin-right: 10px; 
        font-size: 12px;
        font-style: italic;
        width:100%;
    }
    .tablenav .tablenav-pages a {
        border:1px solid #D1E5EE;
        background: #EEE;
    }
    .tablenav .tablenav-pages a, .tablenav-pages span.current {
        text-decoration: none;
        padding: 3px 6px;
    }
    .alternate, .alt {
        background-color: #FCFBF6;
    }
    .tablenav .actions {
        padding: 4px 8px 1px 1px;
    }
    .alignleft {
        float: left;
    }
    .actions input[type="submit"],.actions select {
        border-color: #BBBBBB;
        color: #464646;
        border-style: solid;
        background-color: #FFFFFF;
        border-width:1px;
    }
    .widefat tbody th.check-column {
        padding: 5px 0 5px;
    }
    .widefat .check-column {
        padding: 5px 0 0;
        vertical-align: top;
        width: 2.2em;    
    }
    .row-actions {
        padding: 2px 0 0;
        visibility: hidden;
    }   
   

Sunday, February 5, 2012

HTML5 series part 2: IndexedDB


In the previous article, we explored localstorage(DOM Storage) API. One of the coolest features of local storage is that it is damn simple to use. basically you are dealing with bunch of getter and setter methods to get the benefit of localstorage. Its actually scaled up version of cookies. But the limitations are quite obvious when we need to operate on relatively large amount data. 
firstly,  values are unstructured in localstorage. searching and filtering will be on the order of O(n).
secondly, everything is string here. you cannot store objects unless you are using JSON.stringify and JSON.parse. both SQL and recently popular NoSQL based solutions were proposed. the solutions came in the form of web SQL database and IndexedDB respectively. 

web SQL database:

SQL based web SQL database didn't get wide acceptance among the browser developers. Though browsers like Chrome, Safari and Opera supported web SQL database but popular browser Firefox was more interested in NoSQL based IndexedDB. as a result Firefox doesn't even have minimal support for web SQL database. Finally, W3C wrote the death certificate of web SQL database API by keeping it off active maintenance. they cited lack of independent implementations as being the reason because most of the browser relied on SQLite as the underlying database. web SQL database brought real relational database implementation on browsers.  data could be stored in a very structured way. it supported JOIN operation to give quick access.

IndexedDB:

It looks like IndexedDB is going to be the standard for large scale storage in client. Structurally IndexedDB sits somewhere between true SQL and unstructured localStorage systm. basic features include:
    1. values are stored in javascript objects
    2. quick search and filtering is supported by separate indexing system.
    3. both synchronous and asynchronous APIs are available in the specification (Though no browser   
        yet implemented synchronous API). But for the time being, its mostly anynchronous
   4.  Joining is also possible. 
   5.  object-oriented.
   6.  based on transactional database model. every operation is executed in a particular context of 
        transaction (Three types of transactions: read/write transactions, read only and snapshot). this     
        comes handy when you open two instances of same web application in two different browser tabs. 
   7. data stored as key-value pairs.
   8. uses DOM based event system to notify when result is ready for an operation (typical for    
        asynchronous paradigm)
   9. Like AJAX, IndexedDB obeys same origin policy to enforce data security. each origin ( or 
       website) has its own set of databases that are not allowed to accessing data of database sets loaded 
      a different domain or website. origin is differentiated using the combination of protocol, domain      
      name   and port number.  http://www.example.com and http://www.example.com/en/  both have same origin but  https://www.example.com and  http://www.example.com spawned from two different origin. (differs in protocol)

Synchronous API:

HTML5 supports Concurrency through worker API. Synchronous API of IndexedDB is intended to be used with Worker API. 

Asynchronous API:
       
everything is asynchronous here. you need to make sure to wrap the codes that depends on the query result, in a callback function. every operation must have callback functions that will be executed in response to the event fired as a result of the operation. 

Object Stores:

Every database is named and contains one or more named Object Stores. Object stores can be grossly compared to tables in relational database parlance. every stored object must contain(explicitly or implicitly) any properties  defined by Object Stores . values stored in Object Store are structured and doesn't have rigidly defined schema. Object Store can contain one or more Indexes for easy filtering .

Cross-browser API instances:

Because of the difference in the implementation across vendors, obtaining instance is a bit different vendor-wise.
if("webkitIndexedDB" in window){
       window.indexedDB = window.webkitIndexedDB;
       window.IDBTransaction = window.webkitIDBTransaction;
       window.IDBKeyRange = window.webkitIDBKeyRange;
}else if("moz_indexedDB" in window){
       window.indexedDB = window.moz_indexedDB;
}
if(!window.indexedDB){
     alert("browser doesn't support indexedDB.");
}

why not simple namespacing:

var exampledb = {};
exampledb.indexedDB = {};


Database creation is asynchronous:

exampledb.indexedDB.open = function(){
     var result = window.indexedDB.open(
         "mydb",   // database name/ID
         "my sample db" // tiny description
     );
     result.onsuccess = functnion(e) {
         // the result attribute of the event, e holds the reference to database
          exampledb.indexedDB.db = e.target.result;
         ..... // do as needed.
     };
     result.onerror = function(e){ 
          .... 
      };
}


Database can be versioned and its asynchronous too:
      
result.onsuccess = functnion(e) {
   // the result attribute of the event, e holds the reference to database
    exampledb.indexedDB.db = e.target.result;
    var db = exampledb.indexedDB.db;
    if("" == db.version){
           // user is visiting the page for the first time. lets setup database 
           // by creating 
           // necessary Object Stores and populating default data.
           var setVrequest = db.setVersion("1.0");
            // setting a version creates an implicit transaction which ensures 
            // everything in the callback
            // succeeds or everything fails.
            setVrequest.onfailure  = function(e) {     ......      };    
            setVrequest.onsuccess = function(e) {     
               ......    // we are good to setup database.  
             };
      }
   ..... // do as needed.
};


 Creating Object Stores and Indexes:

setVrequest.onsuccess = function(e) {     
   // Object Store creation is atomic and can only take place inside version 
   // changing transaction
   var store = db.createObjectStore(
         "name":"mysamplestore", // The store's name
         "key":"id",             // The property used as key.
           "autoIncrement":true  // yes it should be auto incrementing 
       );
       store.createIndex(
            "sampleIndex", //  name of the index
            "id",          //  the property to be indexed.
             true          // its unique constraint
       );
};


Write operation is asynchronous:
             
exampledb.indexedDB.writeToDB = function(dataToWrite){
   var db = exampledb.indexedDB.db;
   // create a transaction
   var writeTrans = db.transaction(
        ["mysamplestore"],         // Object Store to lock
        IDBTransaction.READ_WRITE  // Lock type   
   );
   //open the  store for writing
   var store = writeTrans.objectStore("mysamplestore");
   var writeRequest = store.put({
        "name": "binnash", // can be object 
        "url": "http://www.binnash.blogspot.com" // can be object too                         
   });
   writeRequest.onerror = function(e){
        writeTrans.abort(); // undo and roll back
   };
   writeRequest.onsuccess = function(e){ console.log(e);  };        
};   

          
Reading data is also asynchronous:
            
exampledb.indexedDB.readRecord =  function (){
   var db = exampledb.indexedDB.db;
    // create a transaction
    var readTrans = db.transaction(
          ["mysamplestore"],       // Object Store to lock
         IDBTransaction.READ_only  // Lock type   
    );
     //open the  store for writing
     var store = readTrans.objectStore("mysamplestore");
     var readCursor = store.openCursor();
     readCursor.onerror = function(e){
            // 
     };
     readCursor.onsuccess = function(e){ 
         if(e.result){
               console.log(e.target.result.value.url);
               e.target.result.continue();
         }else{
              // you've reached the end of the cursor's list.
          }
      };                           
}


Querying in the Object Store:

as usual Querying is also asynchronous.

exampledb.indexedDB.queryStore =  function (){
    var db = exampledb.indexedDB.db;
    // create a transaction
    var readTrans = db.transaction(
          ["mysamplestore"],       // Object Store to lock
         IDBTransaction.READ_only  // Lock type   
    );
    //open the  store for writing
    var store = readTrans.objectStore("mysamplestore");
    var bounds =new IDBKeyRange.bound(
           "a",            // Lower Bound
           "z",            // Upper Bound
            true,          // include lower bound?
            true           // include upper bound?
    ); 
    var readCursor = store.openCursor(bounds);
    readCursor.onerror = function(e){
          // 
    };
    readCursor.onsuccess = function(e){ 
         if(e.result){
             console.log(e.target.result.value.url);
             e.target.result.continue();
         }else{
             // you've reached the end of the cursor's list.
         }
    };
};


Deleting record:
 
exampledb.indexedDB.deleteItem =  function (id){
   var db = exampledb.indexedDB.db;
   // create a transaction
   var readTrans = db.transaction(
      ["mysamplestore"],           // Object Store to lock
      IDBTransaction.READ_WRITE  // Lock type   
   );
   //open the  store for writing
   var store = readTrans.objectStore("mysamplestore");
   var request = store.delete(id);
   readCursor.onerror = function(e){
      console.log(e);
   };
   readCursor.onsuccess = function(e){ 
     // update screen.
   };                           
};   


Wednesday, January 18, 2012

HTML5 series part 1: localStorage

HTML5 introduces client-side storage API which aims to cover the limitations of cookie and provide  much more.  in this article, i am going to explore about browser cookies, their limitations and how HTML5 overcomes these with client-side storage.

Legacy of HTTP cookie:
An HTTP cookie is a set of key/value pairs that an web server requests web browsers to store on local disk. when browser makes further requests to the server, it wraps all the cookie information in HTTP request header as long as the following conditions are met: ( ref: rfc2109)
1.The cookie is not expired.
2. The requested domain is same or subdomain of cookie storing domain .
3. The requested path is same of subpath of cookie storing domain.

browser  deletes cookie data when cookie expires.

Limitations of cookie:
 1. most current browsers limit cookie size to 4KB.
 2. Number of cookies in a domain is limited to 300
 3. when a site uses cookie, then every request must include all cookie data in HTTP header which is a performance issue.
4. cookie data is stored as plain text in client disk which can cause cookie/session hijacking.
5. cookie cannot differentiate between two different instances of same web application running in two different tabs or windows.

Age of client-side storage:
According to the web storage specification, web storage is intended to solve two cases that are not handled well by cookies:
1. The first is designed for scenarios where the user is carrying out a single transaction, but could be carrying out multiple transactions in different windows at the same time.
2. The second storage mechanism is designed for storage that spans multiple windows, and lasts beyond the current session. In particular, web applications may wish to store megabytes of user data, such as entire user-authered documents or a user's mailbox, on the client side for performance reasons.

Unlike cookie, web storage data is stored in the client by the browsers based on retention policies. Benefits are obvious:
1. data doesn't pass through HTTP request/response. bandwidth is saved.
2. as data isn't passed through network, this is relatively secure.this notion of security has some other advantages. This means that due to the inherent security feature, HTTPs connection can use plain HTTP. Because it wont need  to encrypt data since data is stored in client-side. Since HTTPs has only 10% of performance comparing with HTTP.
3. no download time means better user experience
4. with the help of web storage, surfing same web sites using more than one account simultaneously wont be a tough task.  You can experience this right now on google sites.
5. There is no 4KB limitation, web site will enjoy much more flexibility in storing large data in client.

localStorage API:
localStorage is a handy API included in HTML5 spec that gives web developers any easy to use 5MB store on the client's local machine. It's a simply key/value dictionary that allows developers to store primitive data types like integer, string etc. storing objects requires serialization into json format. localStorage doesn't provide transaction facilities. So wise usage can save you from race conditions.
data storing and retrieval is simple:

//save a value to localStorage
localStorage.setItem('key', 'value');
localStorage.key = value;
myObject = {a:1, b:2, c:3};
localStorage.setItem('key', JSON.stringfy(myObject));

//retrieve a value 
var value = localStorage.key;
var value = locaStorage.getItem('key');
var myStorageObject = JSON.parse(localStorage.getItem("key"));
//reset storage
localStorage.clear();

//to remove an item
localStorage.removeItem('key');

Important features of localStorage:
1. localStorage values on Secure (SSL) pages are isolated:
browsers isolates localStorage values based on HTML5 origin (scheme +hostname+unique port). so http://xyz.com is separated from https://xyz.com. firefox provides  globalStorage doesn't follow this distinction. 
2. sessionStorage values can survive browser restarts if browser impements session restore feature.
3. localStorage values created in "incognito" or private browsing mode are isolated. they will be gone as soon as the session ends.
4. localStorage quota for a site is 5 MB. it cannot be expanded. alternative means are available in the form of indexeddb and web SQL database.
//check if quota limited exceeded.
try{
     localStorage.setItem('key', value);
}catch(e){
      if(e== QUOTA_EXCEEDED_ERR) alert(file is too large);
}
5. for older IE browsers, localStorage feature can be implemented using IE-only feature userData.
//checking if localStorage support is available.
var supported = false;
 try{
    if(window['localStorage']!=null) supported = true;
}catch (e){
     supported = false;
}

for browser support issue, visit http://www.quirksmode.org/dom/html5.html

Monday, January 16, 2012

Facebook PHP SDK: Acquiring anytime access permission for your application

Facebook has exposed a lot of its core functionality through Graph API.  Third party application developers now can quite easily develop application that live on Facebook's gigantic database of user profile information.But except for the public information , applications are required to authenticate by the user to get access. facebook uses OAuth 2.0 protocol for authentication and authorization and supports a number of different OAuth flows that can be used to authorize and authenticate third party mobile/desktop applications and websites. but regardless of type of the flows, Facebook's OAuth implementation involves 3 steps: user authenticationapp authorization and app authentication (more about this can be found in facebook developer site). once these steps are complete, third party application is issued an "user access token" which enables the application to gain access to user infobase on users' behalf. By default,  user access token expires after 2 hours which is not good for site owners who want to show their facebook albums etc. on their sites. in that case, site owner has to be careful enough to authenticate once after every 2 hours which is annoying.  Guys at Facebook solved this  in a way they call "offline_access" permission. user access token with offline access permission doesn't expire. lets take a look at how offline access can be obtained and utilized in your application.

the easiest way to play around with Facebook Graph API is to use SDK. I'll use PHP SDK. First grab the SDK and include into your php file and instantiate SDK's Facebook class.

            require_once("facebook.php");
            $config = array();
            $config[‘appId’] = 'YOUR_APP_ID';
            $config[‘secret’] = 'YOUR_APP_SECRET';            
            $config['fileUpload'] = false;
            $config['cookie'] = true; // don't forget to enable cookie.
            $facebook = new Facebook($config);        
             
Once you have Facebook object, you can begin authentication process. Luckily SDK handles all the 3 steps of authentication on your behalf. all you need to do is to initiate the process and SDK will do the rest. As starter, we check if anyone is already logged in or not.
          $userId = $facebook->getUser();
if no one is logged in then above statement will return 0 otherwise it will return current user's  id.
          if($userId) {
              try{
                     // if user is logged in, we try to get his/her profile information
                     $user = $this->facebook->api('/me', 'GET');
                     // url you want facebook to redirect after logout
                     $logouturl = 'YOUR_SITE_URL';                
                     $logoutUrl = $this->facebook->getLogoutUrl(array('next'=>$logouturl));
                }
                catch(FacebookApiException $e){
                     //url you want facebook to redirect after login.
                     // a note of coution though, for security reason you need to inform facebook about this
                     // URL in your developer profile page.
                     $loginurl = 'YOUR_SITE_URL';

                     $params = array(
                              //This is where you request offline access token
                              scope => 'user_photos, friends_photos,offline_access',
                             redirect_uri => $loginurl
                    );          

                    $loginUrl = $this->facebook->getLoginUrl($params);
                }
         }      
once the authentication process is complete, you can get the access token in the following way:
                    $accessToken = $facebook->getAccessToken();
You should store the token for use across sessions. You can do the subsequent API calls as :
                    $facebook->setAccessToken($accessToken);
                    $facebook->api(/*polymorphic*/);






Saturday, January 14, 2012

End User License


End User License Agreement
Copyright, binnash
All rights reserved.

By using the software, you agree to be bound by the terms of this license. If you have any questions
about the terms below, please contact n.uddin.w@gmail.com for clarification.


1.) You must have paid the developer to use the software.

2.) The copyright holder retains all intellectual property rights to the software.

3.) You are granted the right to install the software on as many websites as you want, limited only to websites you own.

4.) You are granted the right to freely modify the software for your own personal use.

5.) You may not use code snippets from the software elsewhere.

6.) You may not re-distribute (either freely, or for any kind of compensation) the software, in whole or in part, to any 3rd party.

7.) You expressly acknowledge and agree that use of the software is at your sole risk. No warrantly is provided, either express or implied.

Friday, December 30, 2011

If your HTC EVO 3D phone is not recognised by Eclipse running in Ubuntu

I was trying to develop an app for android phone. my working environment was eclipse running on unbuntu. I was planning to use an HTC EVO 3D phone for debugging. But surprisingly I wasn't able to debug and run my app directly in my phone from eclipse. the phone wasn't being recognised. Eventually I could sort out the fix and it was quite easy. ya things are easy when you know the solution :P

do the following to get your phone work:

1. run lsusb command on the prompt. You'll see something like the following:

Bus 002 Device 013: ID 0bb4:0cba High Tech Computer Corp. 


Observe 0bb4:0cba.  0bb4 is the vendor ID and 0cba is the product ID.

2. create/edit /etc/udev/rules.d/51-android.rules  as super user. Add the following line:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="0bb4", ATTRS{idProduct}=="0cba", MODE="0666"

update product ID according to your system.

3. unplug and plug your phone again. you are all set.

Wednesday, November 23, 2011

Joomla: access plugin configuration params from different plugin

Sometimes it may be necessary that you need to access xml configuration parameters of plugin from within another plugin. in joomla you can achieve this quite easily. Suppose you a content plugin called "linkmanager" and you want to be able to access and use the xml configuration parameters of "linkmanager" in another plugin called "searchmanager". in "searchmanager" plugin's class constructor, you do the following to get the configuraton parameters of linkmanager.


  •   $plugin = &JPluginHelper::getPlugin('content', 'linkmanager');                 
  •   $this->params->loadObject(json_decode($plugin->params));