GuppY Help Center, help online, documentation and tutorials


You are here :   Welcome » Plugins tutorial
    Print this page...

Plugins tutorial

  • Introduction
  • Types and Structure
  • Admin part
  • Public part
  • Going further
  • Resources


In computing, the term plugin (or plug-in) is used to describe a program that interacts with a main software, called a host program to provide it with new features.
To match Guppy, a plugin must:
  • to be bilingual
  • to support the skins
  • to be valid HTML 5
  • preferably using a database "flat file"
This tutorial is intended as a manual for initiating plugin creation for GuppY 5.0.

In this document, we will give you the basics to know to create a plugin. For that we will start with some very important safety reminders.
Then we will see the different types of plugins possible.
Then, we will study the case of a simple plugin Hello_World ("hello everyone").
We will finish with some tips and tricks to go further.

Before you start, you need to know PHP programming and HTML 5 and CSS 3 languages.

The security of your plugin should be your priority.

  • Never believe that a variable from a form or url parameter contains what you think you have set.
  • Check the values from the url (GET) or form (POST) before use.
  • Especially those used in the functions include, require ... Initialize variables before use $toto = ''; Or $toto = array (); For a table, do not rely on the default value that PHP should have given them.
  • Use constants for constant values (path of config ...).
  • Put an index.php file pointing to the top directory in all the plugin directories to avoid indexing the plugin files.
(This document contains the basics and the example of the document written for version 4.6 and translated by Hspam).

Plugin Types

Three types of plugins are possible:
  • Those of boxes: they display data in one or more boxes of GuppY, they can define header boxes, side boxes, secondary boxes and footers.
  • Those of main displays: they display data in the main zone of GuppY.
  • Those reserved for the administration: they are only for the administrator and are not accessible to the public. A plugin can be in 1, 2 or 3 of the cases at once.

The directories

With the GuppY system, there are 4 slots where you need to put files for a plugin. One for administrative tasks, one for the public part of the plugin, one for storing the data and the last one often omitted but nevertheless useful.
  • admin/plugins/my-plugin/ 
  • plugins/my-plugin/
  • data/plugins/my-plugin/
  • documentation/plugins/my-plugin/

The files

First a preview of all the files we will create for our hello_world plugin.

The administration part

  • admin/plugins/hello_world/index.php
  • admin/plugins/hello_world/
  • admin/plugins/hello_world/
  • admin/plugins/hello_world/hello_world.png

The public part

  • plugins/hello_world/index.php
  • plugins/hello_world/
  • plugins/hello_world/hello_world.png
  • plugins/hello_world/
  • plugins/hello_world/lang/
  • plugins/hello_world/lang/

The documentation part

Too often overlooked, it must be integrated into your plugin.
The first documents to be placed there: the classics readme.txt and readme.txt. Do not put them in GuppY's main directory, they would be fatally overwritten by other plugins files.

Then, of course one or more documents to explain the installation (chmods) and the operation of your plugin. These documents, preferably in .html format, can be displayed from the plugin administration.

  • documentation/plugins/mon-plugin/
  • documentation/plugins/mon-plugin/fr/
  • documentation/plugins/mon-plugin/en/
Documentation in both languages (or more) will always be appreciated.

The administration part

Create a hello_world subdirectory in the admin/plugins/ directory.

In this directory admin/plugins/hello_world/ we will put some files.

1/ Let's start with the index.php file. Its content is:

<?php header('location:../index.php'); ?>

2/ The second file is The contents of this file consist of the initialization of several variables. Its content is:

// Sécurité
if (stristr($_SERVER['SCRIPT_NAME'], '')) {

// inclusion of the language file
if (is_file(CHEMIN.'plugins/hello_world/lang/'.$lng.'')) {
    include CHEMIN.'plugins/hello_world/lang/'.$lng.'';
} else {
    include CHEMIN.'plugins/hello_world/lang/';
// Plugin name
$plugin_admin_name = 'Hello_World';
// Administration part of the plugin
$plugin_admin_url = 'hello_world/hello_world_admin';
// Plugin icon in the administration area
$plugin_admin_icon = 'hello_world/hello_world.png';

// Structure for a clean uninstallation of the plugin
$plugin_datas_uninstall = array(
    'dirs' => array( 'plugins/hello_world',
    'admin/plugins/hello_world' ),
    'files' => array(),
    'include' => 'admin/plugins/hello_world/',
    'function' => 'hw_uninstall' );

// Added side box (a function that will add the box to the list)
AddPluginBox($world[1], 'plugins/hello_world/hello_world_user', 'fbox_hello_word', BOX_LEFT.BOX_RIGHT); // lateral box of the plugin

Let's see the detail of this file:

– The security block blocks the direct call of the script, it must be present at the beginning of all files '.inc'

– The link to the language file uses the CHEMIN constant, allowing you to use a relative path to the site root for inclusion. It also uses the $lng variable that contains the current language. Note that the plugin must be bilingual, it is necessary to test the presence of the file and if necessary it is the file of English language that will be loaded.

$plugin_admin_name contains the name of the plugin that will be displayed in the administration console.

$plugin_admin_url contains the relative path to the plugin administration from the /admin/plugins/ directory without the '.inc' extension.

$plugin_admin_icon contains the relative path from the /admin/plugins/ directory to the plugin icon that will be displayed in the administrative console.

$plugin_datas_uninstall is a structure for uninstalling the plugin. The uninstaller is at the designer's expense who is the most qualified person to perform a clean uninstall. This structure is not mandatory but strongly advised. It contains the following items:
    dirs : an array of directories to remove
    files : an array of files to delete that would not be located in directories to uninstall
    include : the name of the file that contains the uninstaller function
    function : the name of the function that will perform the uninstall

AddPluginBox() allows you to add the side box via the fbox_hello_world () function, declared in the script. The variable $world [ 1 ] represents the title of the side box.

In the variables, GuppY automatically assumes that both URLs refer to an .inc file, so you need to refrain from wanting to add the file extension.

3/ With the third file, you can configure the plugin via the admin area of GuppY.

In the Hello_world plugin, included with this article, we show you how you can add an icon, in the navigation bar, that can be used by visitors to activate the plugin. This example is not the simplest part of the hello_world plugin code but can be very useful if you want to use an icon in the navigation bar for your plugin. It's just a problem to copy/paste and change a little bit of code.

In the second file, you saw that the URL for the administration part points to hello_world/hello_world_admin. As we wrote above, GuppY automatically considers that the extension of this file is .inc. So the name of the third file is

For the full contents of this file, refer to the attached Hello_World plugin.

The minimum content of a file to configure the plugin by the admin zone is:

// Security
if (stristr($_SERVER['SCRIPT_NAME'], '')) {
// inclusion of the language file
if (is_file(CHEMIN.'plugins/hello_world/lang/'.$lng.'')) {
    include CHEMIN.'plugins/hello_world/lang/'.$lng.'';
} else {
    include CHEMIN.'plugins/hello_world/lang/';
// always start with the following 5 lines
$topmess = '<a href="admin.php?lng='.$lng.'
&amp;sid='.$sid.' ">Admin</a> > '.str_replace('Admin - ', '', $world[0]);
include CHEMIN.'admin/';
// haut de page
htable($world[0], '100%'); // entête de boite centrale avec le nom du plugin
// inclusion of the admin page header file according to its rights
if ($wri == 'admin') include CHEMIN.'admin/administrateur.php';
if ($wri == $userprefs[1]) include CHEMIN.'admin/adminredac.php';

//  Your PHP and/or HTML code .. //

// always finish this file with the following lines
// no need to refer to the admin page, in the new structure, tabs
// of the linear drop-down menu are always at your disposal

btable(); // end of admin box
include CHEMIN.'admin/'; // right column and footer

Note the $world variables that come from the language file.

More information about the language file at the end of this article!

4/ Finally, there is a fourth file that you can also find in This is the icon used in the administration area for this plugin. Called in this case hello_world.png. The icons make 42*42 pixels.

The public part

This part of the Hello_World plugin treats the part that visitors to your website will be able to see.

Create a hello_world subdirectory in the directory /plugins/.

1/ We start again with the index.php file. Its content is:

<?php header('location:../index.php'); ?>

2/ The second file is The contents of this file consist of several variables. Its content is:

// sécurité
if (stristr($_SERVER['SCRIPT_NAME'], '')) {

define('CHEMIN', '../../');
// inclusion of the language file
if (is_file(CHEMIN.'plugins/hello_world/lang/'.$lng.'')) {
    include CHEMIN.'plugins/hello_world/lang/'.$lng.'';
} else {
    include CHEMIN.'plugins/hello_world/lang/';

// Plugin Name
$plugin_bar_name = $world[1];
// The following two lines refer to files in the plugin /hello_world/
// The URL to activate when clicking on the icon
$plugin_bar_url = 'hello_world.php';
// The icon
$plugin_bar_icon = 'img/hello_world.png';

You do not need this file if you do not use an icon in the navigation bar!

Let's see the detail of this file:

define("CHEMIN", "../../") defines the relative path to return to the root of the site.

$plugin_bar_name contains the name that will be displayed in the menu bar.

$plugin_bar_url contains the url relative to the directory of the plugin of the php file containing the public page of the plugin, the one that will be called when clicking on the menu bar.

$plugin_bar_icon contains the url relative to the directory of the plugin of the icon that will be displayed in the menu bar.

3/ The third file is called and already mentioned in admin/plugins/

This file contains a function that creates the side box.

For the full contents of this file, refer to the attached Hello_World plugin.

The minimum content for a side box is:

// Sécurité
if (stristr($_SERVER['SCRIPT_NAME'], '')) {

function fbox_hello_world($pos, $args) {

    // Declaration of necessary system variables
    global $lng, $lang, $site, $serviz, $userprefs, $drtuser, $page, $tconfig, $reptheme, $web;
    // Inclusion of the language file
    include CHEMIN.'plugins/hello_world/lang/'.$lng.'';
    // Inclusion of the plugin configuration file
    include CHEMIN.DATAREP.'plugins/hello_world/';

    // The $out variable contains the HTML of your box
    $out = '
      <div style="text-align: center;padding: 12px;">
        <a href="'.CHEMIN.'plugins/hello_world/hello_world.php?lng='.$lng.'" title="hello_world" />Hello !</a>

    // Set the Quick Administration icon
    if (($serviz[32] == 'on' && !empty($serviz[31]) && ($serviz[31] == $userprefs[1]) || $serviz[32] == 'on' && $drtuser['hello_world'] == 'on')) {
        $out .= '
          <div class="f-right">'.displayQuickConfig($pos).'
            <a href="'.CHEMIN.'admin/admin.php?lng='.$lng.'&amp;pg=plugin&amp;plug=hello_world/hello_world_config
&amp;sid='.$sid.' " title="">
              <img alt="'.$web[308].'" src="'.$reptheme.'/edit.png" style="border:0;" title="'.$web[308].'" />
          </div><div class="c-right"></div>';
    // Finish the function for a side box by this line
    return boxthin($pos, $world[1], $out, ' H_W'.$tconfig, $hwdynabox);
} // end of the function

The side box must be enabled in Admin > Configurations > Config boxes!

Let's see the detail of this file:

function fbox_hello_world($pos, $args), execution of this function will display the hello_world side box, function parameters, $pos gives the position of the box in the structure of the page, $args contains the arguments passed to the function, they are transmitted by the execution function of the GuppY engine.

global : within a function the global variables are not visible, so they should be declared. For example, $lng that contains the language used must be visible to load the plugin's language file.

$out is the variable that contains the HTML 5 displayed in the box. It will be passed to the boxthin() function, which will display the entire box, title, and content.

if (($serviz[32] == .... , this code has the role of displaying at the bottom right of the box the small icons of fast administration

return boxthin() we return the whole formatted box thanks to the parameters provided, $pos is the box position, $world[1] is the box title, $out is the box content, 'H_W' is the name of a pseudo class that can be used to customize the box, $tconfig is a global variable that defines the number of the display page and finally $hwdynabox a configuration parameter defining the status of the box (open, closed, static). This last parameter will be defined in admin in the configuration of the plugin.

4/ The fourth file is hello_world.php which will be activated by the plugin icon in the navigation bar (if present). This file will also be activated by a link in the side box.

The goal is that the output of this file is displayed in the central part of a page.

The content looks like this:

/* Security
* This time no security code (4 lines)
* that you have seen in all other .php and .inc files
* because this .php file is called by a direct link.
// Start with the following lines to display the output in a central box


header('Pragma: no-cache');
define('CHEMIN', '../../');
include CHEMIN.'inc/';

include CHEMIN.'inc/';
$false = false;
foreach ($medias as $media) if (strstr(strtoupper($_SERVER["HTTP_USER_AGENT"]), $media)) $false = true;
if (!$false) @session_set_cookie_params(0, '/', $_SERVER['HTTP_HOST'], false, (is_ssl() ? true : false));

include CHEMIN.'inc/';
// Inclusion of the language file
include CHEMIN.'plugins/hello_world/lang/'.$lng.'';
// Header box
htable($world[1], '100%');

// Your PHP and / or HTML code
echo '<h3>Hello World</h3>';

// Always finish with the following lines
include $CHEMIN.'inc/';

The sample code is just a line of XHTML. What you will often see here is the use of PHP, XHTML and CSS code.

Let's see the detail of this file:

header('Pragma: no-cache') not to cache the page, case of a dynamic page.

include CHEMIN.'inc/' loading the GuppY engine.

– The other elements have already been seen before.

5/ One of the nice functions of GuppY is to be able to use it in bilingual. This means it is important to make your plugins easily translatable and easy to use in bilingual. To make it bilingual, we have added the following line in the code we spoke of earlier:

// Inclusion of the language file
include CHEMIN.'plugins/hello_world/lang/'.$lng.'';

The $lng variable contains the language code. For example: if your site is in french the file name is The language file contains variables. These variables are used in the plugin code. To make the plugin usable in other languages, we only need to rename the language file and translate the contents of the variables.

For example: to translate the plugin into spanish, we duplicate and rename the file to and
let us translate the contents of the variables.

The Hello_World plugin language file contains:

// sécurité
if (stristr($_SERVER['SCRIPT_NAME'], '')) {
// Language variables used by the Hello_World plugin
$world[0] = 'Admin - Plugin Hello World';
$world[1] = 'Hello World';
$world[2] = 'Put the 'Hello World' icon in the navigation bar';
$world[3] = 'Put here code for administration tasks (if
$world[4] = 'Put here the code for the visitors part (if necessary)';
$world[5] = 'Click here';
$world[6] = 'Uninstall the plugin';

It is advisable to make a subdirectory lang/ to separate these files from others and facilitate their location by the translators.

On large plugins, you can separate the language file in 2, a postfixed 'admin' and another postfixed 'web' for the administrative and public parts of the plugin.

6/ Finally, there is a sixth file that you also find in This is the icon used in the navigation bar and called hello_world.png. The icons are 42*36 pixels. This can be the same icon used in the admin area. You do not need this file if you do not use an icon for this plugin in the navigation bar or in the central box!

7/ Points to consider.

  • For each .inc and .php file in your plugin, start directly after the first <php with comment lines indicating the plugin name, license distribution, author, your website ...:

    Plugin :Plugin name
    Licence : CeCILL
    Name : your name or pseudo
    Website : your website (to support)
    Do not add your email to avoid spam!
    Comments on file changes

  • Add clear documentation about the plugin's purpose, how to install it (CHMOD), and how to configure it.

  • Once completed, submit your plugin to beta testers. Nothing beats the opinion of the users.

  • Once verified and verified, advertise it on FreeGuppY and submit it to GuppYLand.

Go further

Navigate to a multi-page plugin

To access a admin page of a plugin, one always passes by admin.php (which manages the access rights) passing 2 parameters to him:

pg which contains the value 'plugin', to say that one accesses a plugin,

plugin which contains the relative path to the plugin administration page from the /admin/plugins/ directory without the '.inc' extension.

If we take the example of the plugin "hello_world", the address of the administration page of the plugin is the following in html:

echo CHEMIN.'admin/admin.php?lng='.$lng.'&pg=plugin&plug=hello_world/hello_world_admin';

Define several side and center boxes

To do this, it will be necessary to modify the file admin / plugins / mon-plugin /

Create an .inc file in plugins/my-plugin/ by box, for example,, etc.

Each .inc file will contain the corresponding function, fbox_my_first_box($pos, $args) for the first file, fbox_my_second_box($pos, $args), and so on.

These boxes will be supported in admin/plugins/my_plugin/ with the following declarations:

AddPluginBox($box_name[1], 'plugins/mon_plugin/my_first_box', 'fbox_my_first_box', BOX_LEFT.BOX_RIGHT);
AddPluginBox($box_name[2], 'plugins/mon_plugin/my_second_box', 'fbox_my_second_box', BOX_LEFT.BOX_RIGHT);

Note that BOX_LEFT.BOX_RIGHT indicates that the use of the box will only be possible in the right and left columns. It is possible to write it like this: 'LR'.

To make the box available in all the locations of a page, you should specify 'LRAEUTB', or using the predefined constants.

Add the plugin in the menu bar

Example of the hello_world plugin

// integration of necessary functions
include 'plugins/';
// This part saves the status of the plugin in the menu bar
// The 3 occurrences of "hello_world" correspond to the name of the plugin directory

$regit = import('regit');

if ($regit == 1) {

    $hello_world = import('hello_world');
    $iconexec = import('iconexec');
    $icondisp = import('icondisp');
    if ($hello_world == 'on') {
        if (!PluginRegistered('hello_world')) RegisterPlugin('hello_world', $iconexec, $icondisp);
    else UnregisterPlugin('hello_world');

// Form to (un)register the plugin
echo '
<form name="hello_world" action="admin.php?lng='.$lng.'&amp;pg=plugin&amp;plug=hello_world/hello_world_admin
&amp;sid='.$sid.' " method="post">
  <input type="hidden" name="regit" value="1" />
  <select style="max-width:180px; margin-top:4px;" name="iconexec">
    <option value="ALL"'.Selected($iconexec == 'ALL').'>'.$admin[1363].'</option>';
foreach ($templates as $key=>$val) {
  echo '<option value="'.$key.'"'.Selected($iconexec != 'ALL' && $iconexec == $key).'>'.$key.' - '.$val.'</option>';
echo '
  <select style="max-width:180px; margin-top:4px;" name="icondisp">
    <option value="ALL"'.Selected($icondisp == 'ALL').'>'.$admin[1363].'</option>';
foreach ($templates as $key=>$val) {
  echo '<option value="'.$key.'"'.Selected($icondisp != 'ALL' && $icondisp == $key).'>'.$key.' - '.$val.'</option>';
echo '
  <p>'.$world[2].'&nbsp;&nbsp;<input type="checkbox" name="hello_world"'.Checked(PluginRegistered('hello_world')).' /></p>  <p style="text-align:center;">'.SubmitButton($admin[66]).'</p>

Let's see the detail of this code:

include 'plugins/' allows access to the functions PluginRegistered(), RegisterPlugin() et UnregisterPlugin()

– if the form is valid ($regit == 1) the content of $hello_world

– if checked ($hello_world == 'on') then if the plugin is not already registered (!PluginRegistered('hello_world'))
we register it RegisterPlugin('hello_world');

– otherwise it is unsubscribed UnregisterPlugin('hello_world');

– Note in the form the use of the Checked() function which will display if necessary checked="checked", similarly the SubmitButton() function that displays the form button.

Insert text editor

We will see how to integrate in the administration of a plugin the advanced editor of GuppY.

Viewing the editor in a form

1/ To start, you have to insert the necessary functions and store the reusable flags in front of the form fields.

require CHEMIN.'admin/editors/editors_functions.php';
$flag1 = '<img src="'.CHEMIN.INCREP.'lang/'.$lang[0].'.gif" style="vertical-align:middle;border:0;" alt="'.$lang[0].'" />';
$flag2 = '<img src="'.CHEMIN.INCREP.'lang/'.$lang[1].'.gif" style="vertical-align:middle;border:0;" alt="'.$lang[1].'" />';
$wysiwyg = $serviz[49] == 'on' ? true : false;

2/ Then we will display the form with the editor in 1 or 2 languages depending on the configuration of GuppY.

echo '
<form name="adminsend" action="admin.php?lng='.$lng.'" method="post">
  <input type="hidden" name="pg" value="plugin" />
  <input type="hidden" name="plug" value="mon-plugin/monplugin" />
  <input type="hidden" name="regit" value="1" />';
// Main language
echo '
  <div style="text-align: center; margin: auto; width: 560px;">
    <label for="contenu1">'.$flag1.' Text in main language</label><br />
    '.display_admin_editor('contenu1', '540px', '400px', $contenu1, $wysiwyg).'
    <p style="text-align: center;">'.SubmitButton($admin[66]).'</p>
if ($lang[1] != '') {
// Secondary language

   echo '
  <div style="text-align: center; margin: auto; width: 560px;">
    <label for="contenu1">'.$flag2.' Text in secondary language</label><br />
    '.display_admin_editor('contenu2', '540px', '400px', $contenu2, $wysiwyg).'
    <p style="text-align: center;">'.SubmitButton($admin[66]).'</p>

echo '

Let's see the detail of this code:

require the library is loaded which contains all the necessary functions of the editor

$flag1, $flag2, these two variables contain the site's language images

$wysiwyg retrieves the choice of the editor ("on" by default)

– the form is classic in admin, it displays the language flag associated with a label, followed by the call to function

display_admin_editor() is the display function of the editor, whether WYSIWYG or not
    'contenu1' is the name of the variable given back
    follow the width and height of the editor in pixels
    $contenu1 contains the text to be edited
    et enfin $wysiwyg which will determine which editor to use, CKEditor or a textarea

if ($lang[1] != '') we test if a secondary language is present, then we display a second time the editor with the corresponding values

Processing form data

With CKeditor we transform relative paths into absolute. But before the data is stored, it is necessary to do the opposite operation.

if ($regit == 1) {
    $text1 = import('contenu1');
    $text2 = import('contenu2');
    $text1 = PathAbsoluteRelative($text1);
    $text2 = PathAbsoluteRelative($text2);
    $txt   = "<?php
$contenu1 = stripslashes("$text1");
$contenu2 = stripslashes("$text2");
    WriteFullDB(CHEMIN.DATAREP.'plugins/mon_plugin/', $txt);

Let's see the detail of this code:

– if ($regit == 1) $regit went through the form

$text1, $text2, recovering and formatting the values

PathAbsoluteRelative transforms absolute paths into relative.

Show texts

The texts are saved with relative paths relative to the root of the site. So the images and links do not work when the page where the text is displayed is plugins/my-plugin/monplugin.php.

No worries, GuppY has a function to correctly restore relative paths. Just do :

echo PathToImage($contenu1);

Uninstall the plugin

For the hello_world plugin we will perform the uninstall in the script admin/plugins/hello_world/

Let's add a small form to launch the uninstallation:

if (isset($plugin_datas_uninstall)) {
    echo '
<hr />
<div style="width:480px;text-align:center;margin:auto;">
  <form name="uninstall" action="admin.php?lng='.$lng.'&amp;pg=plugin&amp;plug=hello_world/hello_world_admin
&amp;sid='.$sid.' " method="post">
  <input type="hidden" name="regit" value="unplug" />
  <p style="text-align:center;">'.SubmitButton($world[6]).'</p>

Let's see the detail of this code:

if (isset($plugin_datas_uninstall)) we test the existence of the deinstallation structure declared in admin/plugins/hello_world/

– the form is displayed which only contains the submission button

Then the application must be processed:

if ($regit == 'unplug') {
    $dirs  = $plugin_datas_uninstall['dirs'];
    $files = $plugin_datas_uninstall['files'];
    foreach ($dirs as $dir) RecursiveRemoteDir(CHEMIN.$dir);
    foreach ($files as $file) @unlink(CHEMIN.$file);
    echo BeginJavascript().'


You have come to the end of this tutorial on a very simple example. You have the main elements that will allow you to create your own plugin for GuppY version 5.0.

When your plugin is ready, it's time to create a .zip archive with the Manifest file that will allow users of GuppY version 5.0.x to install it directly with the function > General management > Install.

The mkZip utility, created by JeanMi, to create your .zip archive is at your disposal at the end of this article. Install it on your hard drive. Simply run the mkzip.php script and fill in the required fields.

Where to find plugins?

GuppYLand, the site to visit absolutely:

CeCILL License

The entire manual is subject to the CeCILL License, which means:

  • that everyone has the right to freely use the manual.
  • that everyone is authorized to distribute the manual.

The GuppY software is subject to the CeCILL license. You will find more details about it here:

Link for plugin Hello World download:    hello_world.png

Link for downloading the mkZip utility: zip.gif

Creation date : 02/03/2015 @ 16:39
Last update : 10/09/2019 @ 15:14
Category : - Plugins tutorial
Page read 3627 times