GetSimple Support Forum
Plugin Tutorial: Designing an Administration Panel - Printable Version

+- GetSimple Support Forum (http://get-simple.info/forums)
+-- Forum: GetSimple (http://get-simple.info/forums/forumdisplay.php?fid=3)
+--- Forum: Developer Discussions (http://get-simple.info/forums/forumdisplay.php?fid=8)
+--- Thread: Plugin Tutorial: Designing an Administration Panel (/showthread.php?tid=6090)



Plugin Tutorial: Designing an Administration Panel - Angryboy - 2014-04-11

Scenario

You've designed a plugin that has a few variables/parameters that the admin should be able to easily manipulate (i.e. they should be able to change them from the admin panel and not by editing any of the plugin files that they downloaded). Let's assume that (for this example) the parameters are simply imitations of some of the ones in the Settings page - Website Title, Website URL and Email. How do you integrate such a back-end?

How to do it


lib/plugin.class.php

In your plugin class, you will already have three methods - register, init and whichever method points to the admin panel (in this case, let us call it displayAdminPanel). The register method will say (in the register_plugin function) that displayAdminPanel is the desired method to call for the admin panel.

PHP Code:
public function register() {
    
// register the plugin
    // note that some properties are used in conjunction with i18n_r for language-flexibility
    
register_plugin(
      
$this->id,
      
i18n_r($this->id '/PLGN_TITLE'), 
      
'0.1',
      
'You',
      
'http://yoursite/',
      
i18n_r($this->id '/PLGN_SIDEBAR'),
      
'plugins'// This example will show the plugin on the Plugins tab
      
array($this'displayAdminPanel')
    );
  } 

init will ensure that a default settings file already exists for the admin to edit (if it doesn't already). A model of the settings file might be this:

PHP Code:
<?xml version="1.0"?>
<settings>
  <websitetitle></websitetitle>
  <websiteurl></websiteurl>
  <websiteemail></websiteemail>
</settings> 

By saving a copy in the assets/ folder, we we can copy it during the initialization process if the file doesn't exist.

PHP Code:
public function init() {
    
// sidebar link
    
add_action('pages-sidebar','createSideMenu', array($this->idi18n_r($this->id '/PLGN_SIDEBAR')));
    
    
// copy settings file
    
if (!file_exists($settings GSDATAOTHERPATH $this->id '_settings.xml')) {
      
copy(GSPLUGINPATH $this->id '/assets/xml/settings.xml'$settings);
    }
    
    
// any other init queries...
  


To modulate the code, we will handle the admin panel with two further classes - one for designing the admin functions and one for displaying the admin panel. For it to work, our displayAdminPanel panel will only require the following code:

PHP Code:
public function displayAdminPanel() {
    
$admin = new YourPluginAdminDisplay($this->id);  // load admin panel object
    
$admin->getPage();                               // get the correct admin panel page
  


lib/yourpluginsettings.class.php

It is good practice to design classes for handling different types of data. As our settings constitute as a type of data, it will be helpful to have a class for handling it.

This class will load the settings xml file, cast its properties as strings (instead of objects) into a private array, and provide a method for accessing the array elements (so we will not have 'Unidentified index' errors if we happen to call an entry that doesn't exist).

PHP Code:
<?php

class YourPluginSettings {
  private 
$settings = array();
  
  public function 
__construct($file) {
    
// load xml file
    
$xml = new SimpleXMLExtended($file0true);
    
    
// set each xml field as a string in the settings array
    
foreach ($xml as $field => $value) {
      
$this->settings[$field] = (string) $value;
    }
  }
  
  public function 
getSetting($setting) {
    if (isset(
$this->settings[$setting])) {
      return 
$this->settings[$setting];
    }
    else return 
null;
  }
}

?>

lib/yourpluginadmin.class.php

The admin panel will be separated into its functions (YourPluginAdmin) and its display (YourPluginAdminDisplay). The latter class will extend the former so that its methods are immediately available, but the division of the classes will make them easier to maintain (especially as your admin panel increases in complexity).

PHP Code:
<?php

class YourPluginAdmin {
  private 
$id// useful to have the plugin id
  
private $url// useful to have the admin plugin link
  
  
public function __construct($id) {
    
$this->id $id;
    
$this->url 'load.php?id=' $id;
  }
  
  public function 
saveSettings($file$data) {
    
// ...
  
}
}

?>

The main method to implement is the one for saving the settings. This involves editing the input XML file (which will be done with the SimpleXMLExtended class) with respect to some $_POST query. To escape the data safely, the information will be put in CDATA blocks.

PHP Code:
protected function saveSettings($file, array $data) {
    
// load xml file
    
$xml = new SimpleXMLExtended($file0true);
    
    
// loop through data array and set the properties
    
foreach ($data as $field => $value) {
      
$xml->{$field} = null;
      
$xml->{$field}->addCData($value);
    }
    
    
// save the xml file and return the success boolean
    
return $xml->saveXML($file);
  } 

lib/yourpluginadmindisplay.class.php

PHP Code:
<?php

class YourPluginAdminDisplay extends YourPluginAdmin {
  public function 
getPage() {
    
// ...
  
}
}

?>

The main method to implement now is for getting the correct admin panel page. In this case, there is only one, but we can easily extend this to show other pages (based on the $_GET array). When a post query is sent, we save the settings.

PHP Code:
public function getPage() {
    
// save the settings
    
$file GSDATAOTHERPATH $this->id '_settings.xml';
    if (
$_SERVER['REQUEST_METHOD'] == 'POST') {
      
$this->saveSettings($file$_POST);
    }
    
// load settings object and display the settings
    
$settings = new YourPluginSettings($file);
    
$this->displaySettings($settings);
  } 
Our private displaySettings method will have the HTML markup of the page, parameterized by the existing settings. It will take a settings object as a parameter and use it for displaying the settings properties

PHP Code:
private function displaySettings(YourPluginSettings $settings) {
    
?>
    <h3><?php i18n('SETTINGS'); ?></h3>
    <form method="post">
      <p>
        <input type="text" class="text" name="websitetitle" value="<?php echo $settings->getSetting('websitetitle'); ?>"/>
      </p>
      <p>
        <input type="text" class="text" name="websiteurl" value="<?php echo $settings->getSetting('websiteurl'); ?>"/>
      </p>
      <p>
        <input type="text" class="text" name="websiteemail" value="<?php echo $settings->getSetting('websiteemail'); ?>"/>
      </p>
      <p id="submit_line">
        <span><input class="submit" value="<?php i18n('BTN_SAVECHANGES'); ?>" type="submit"></span>
      </p>
    </form>
    <?php
  


That's all that's required to have a working admin panel.

Adding more pages

Design the extra functions you'll need in the YourPluginAdmin class. Then design the extra pages for the admin panel that you will need in the YourPluginAdminDisplay class. Finally, in the getPage method, use a switch or if/else statement to output the correct page.

PHP Code:
public function getPage() {
    if (
condition) {
      
// e.g. condition could be $_GET['edit'] = 'something'
    
}
    elseif () {
      
// ...
    
}
    
// ...
    
else {
      
// save the settings
      
$file GSDATAOTHERPATH $this->id '_settings.xml';
      if (
$_SERVER['REQUEST_METHOD'] == 'POST') {
        
$this->saveSettings($file$_POST);
      }
      
// load settings object and display the settings
      
$settings = new YourPluginSettings($file);
      
$this->displaySettings($settings);
    }
  } 

Error messages


The functions in YourPluginAdmin were purposefully designed to return booleans in correspondance with the success of their operations. We can use this to our advantage and display error messages consistent with the ones you're used to seeing in the GetSimple back-end. Using this code snippet from the GetSimple wiki, you can show messages dependent on the boolean value of the function(s).

PHP Code:
public function getPage() {
    if (
condition) {
      
// e.g. condition could be $_GET['edit'] = 'something'
    
}
    elseif () {
      
// ...
    
}
    
// ...
    
else {
      
// save the settings
      
$file GSDATAOTHERPATH $this->id '_settings.xml';
      if (
$_SERVER['REQUEST_METHOD'] == 'POST') {
        
// set the boolean into a variable
        
$save $this->saveSettings($file$_POST);
        
        
// set the correct error message
        
if ($save) {
          
$msg i18n_r($this->id'/SETTINGS_SUCC');
          
$isSuccess true;
          
$canUndo true// if you have an undo function
        
}
        else {
          
$msg i18n_r($this->id'/SETTINGS_FAIL');
          
$isSuccess false;
          
$canUndo false;
        }
      }
      
// load settings object and display the settings
      
$settings = new YourPluginSettings($file);
      
$this->displaySettings($settings);
    }
    
    if (isset(
$msg)) {
      if (
$canUndo$msg .= ' <a href="' $this->url '&undo">' i18n_r('UNDO') . '</a>'
    
?>
    <script type="text/javascript">
      $(function() {
        $('div.bodycontent').before('<div class="<?php echo $isSuccess 'updated' 'error'?>" style="display:block;">'+
          <?php echo json_encode($msg); ?> + '</div>');
        $(".updated, .error").fadeOut(500).fadeIn(500);
      });
    </script>
    <?php 
    




RE: Plugin Tutorial: Designing an Administration Panel - almirb - 2014-12-09

Hello!

This tutorial starts with a scenario. How can I get the starting package or the complete source code of this plugin?

That's exactly I was looking for. Smile

Thanks!
Almir