2014-04-11, 01:11:29
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.
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:
By saving a copy in the assets/ folder, we we can copy it during the initialization process if the file doesn't exist.
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:
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).
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).
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.
lib/yourpluginadmindisplay.class.php
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.
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
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.
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).
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->id, i18n_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($file, 0, true);
// 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($file, 0, true);
// 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);
}
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
}