How to create Osclass Plugins - Madhouse

How to develop Osclass plugins – Part 2

Osclass, Plugins, Tutorials

It’s been quite some time since we wrote and released to the world our tutorial on how to develop Osclass plugins. Here’s a follow up to keep up to date with latest Osclass improvements and best practices.

In this second part of the tutorial, we’ll update our Madhouse Helloworld plugin with more advanced features that will boost a nice and working plugin for Osclass into a pro-quality plugin, ready to hit the world.

Introduction

This tutorial is a three part tutorial:

For the sake of this example, we will be building a basic plugin called Madhouse HelloWorld whose code is available on Github. Download Madhouse HelloWorld on Github.

  1. Administration
  2. Pagination
  3. Semver, upgrade and licensing
  4. Conclusion

1- Administration

Settings are the most vital parts of plugins if you want to build flexible plugins. In order to offer settings to website administrators, the plugin needs to add a custom administration page to the administration panel of Osclass.

With Osclass routing system, making a custom administration page for your plugin is very similar to what we’ve been doing in the previous part:

  • Create a route
  • Add some helper functions for new routes
  • Add an entry in the main administration menu
  • Create the corresponding view file (settings form)
  • create a controller matching this route and handling all the processing

1.1- Create the route

We will add two new routes to the index.php file: one to display the settings page (form) and one to save the settings to the database (post).

osc_add_route(
    "madhouse_helloworld_admin_settings",
    "madhouse_helloworld/admin_settings/?",
    "madhouse_helloworld/admin_settings/",
    "madhouse_helloworld/views/admin/settings.php"
);

osc_add_route(
    "madhouse_helloworld_admin_settings_post",
    "madhouse_helloworld/admin_settings_post/?",
    "madhouse_helloworld/admin_settings_post/",
    "madhouse_helloworld/views/admin/settings.php"
);

Note the way those routes are named which has the benefit of not crash with Osclass default routes and clearly state that they are meant to be used in admin only.

1.2- Add some helpers for the admin

We will create right away some helpers to easily use those two new routes and keep things the way Osclass do it.

In the helpers/hHelloWorld.php, add those two new helpers:

/**
 * Get the admin settings route URL.
 *
 * @return string
 *
 * @since  1.3.0
 */
function mdh_helloworld_admin_settings_url()
{
    return osc_route_admin_url("madhouse_helloworld_admin_settings");
}

/**
 * Get the admin settings form action route URL.
 *
 * @return string
 *
 * @since 1.3.0
 */
function mdh_helloworld_admin_settings_post_url()
{
    return osc_route_admin_url("madhouse_helloworld_admin_settings_post");
}

1.3- Add a menu item

We will once again add some hook calls to our beloved index.php to add a nice link to our (soon to be created) settings form for Madhouse HelloWorld to the plugins section in the administration menu on the side:

/*
 * ==========================================================================
 *  ROUTES
 * ==========================================================================
 */

osc_add_hook('admin_menu_init', function () {
    osc_add_admin_submenu_divider(
        "plugins",
        __("Madhouse HelloWorld", "madhouse_helloworld"),
        "madhouse_helloworld",
        "administrator"
    );

    osc_add_admin_submenu_page(
        "plugins",
        __('Settings', "madhouse_helloworld"),
        mdh_helloworld_admin_settings_url(),
        "madhouse_helloworld_admin_settings",
        "administrator"
    );
});

Take note that we used our helpers, created in the previous section to define our menu item. We won’t see in details what are the arguments of those Osclass menu helpers, you’ll have to take my word that it works fine!

At this point, you should get something similar than the screenshot below:

Tutorial Osclass Plugins 2 - Admin menu example (Madhouse HelloWorld)

1.4- Create the view file!

Our menu item is there, but if you click on it, Osclass will most likely complain because the view file – define in the route definition – does not exist yet. Let’s correct that!

Create a new file and directories, if necessary, views/admin/settings.php:


<?php echo "Welcome to Madhouse HelloWorld settings!"; ?>

Now, if you click on settings in the side menu, you should see your welcoming message. That’s a good start but what we want is being able to set some settings in database and use them in our custom plugin page.

Let’s update our view file with meaningful content.


<?php echo "Welcome to Madhouse HelloWorld settings!"; ?>
<form class="form-horizontal" method="POST" action="<?php echo mdh_helloworld_admin_settings_post_url(); ?>
">
<div class="form-row">
<div class="form-label">
            <?php _e("Messages per page", "madhouse_helloworld"); ?></div>
<div class="form-controls">
            <input type="text" class="" name="i_display_length" value="<?php echo osc_get_preference("i_display_length", "plugin_madhouse_helloworld"); ?>"></div>
</div>
<button class="btn btn-submit" type="submit">
        <?php _e("Save settings", "madhouse_helloworld");?>
    </button>
</form>

Saving this form won’t do much yet, since we didn’t created our controller to handle this form. Let’s fix that.

1.5- Create the admin controller!

First, create a new PHP class Admin.php located inside classes/Madhouse/HelloWorld/Controllers/Admin.php:

<?php class Madhouse_HelloWorld_Controllers_Admin extends AdminSecBaseModel {     /**      * Load the settings view.      */     private function doSettingsAction()     {     }     /**      * Updates settings.      *      * @return      */     private function doSettingsPostAction()     {         // Redirect and display a nice message!         osc_add_flash_ok_message(__("Successfully updated settings!", "madhouse_helloworld"), "admin");         $this->redirectTo(mdh_helloworld_admin_settings_url());
    }

    /**
     * Do model, catch all cases of madhouse user resoures for admin
     */
    public function doModel()
    {
        parent::doModel();

        switch (Params::getParam("route")) {
            case "madhouse_helloworld_admin_settings_post":
                $this->doSettingsPostAction();
                break;
            case "madhouse_helloworld_admin_settings":
            default:
                $this->doSettingsAction();
                break;
        }
    }
}

Some important things to look at:

  • Our admin controller MUST extends AdminSecBaseModel;
  • We are matching routes created previously in the doModel() method;
  • Don’t forget to add that new class in the unfamous oc-load.php:
    require_once __DIR__ . "/classes/Madhouse/HelloWorld/Controllers/Admin.php";

On the front-end, creating our custom page, we had used a hook that Osclass makes available to plugins and allowed us to plug a custom controller matching our custom route.

We will use a similar hook for the administration pages called renderplugin_controller to which we will plug a custom admin controller to handle the settings form and save its parameters into database.

Inside your index.php file, to plug everything together:

function mdh_helloworld_admin_controller()
{
    if (mdh_is_helloworld()) {
        $filter = function ($string) {
            return __("Madhouse HelloWorld", "madhouse_helloworld");
        };

        // Page title (in <head />)
        osc_add_filter("admin_title", $filter, 10);

        // Page title (in
<h1 />)
        osc_add_filter("custom_plugin_title", $filter);

        $do = new Madhouse_HelloWorld_Controllers_Admin();
        $do->doModel();
    }
}
osc_add_hook("renderplugin_controller", "mdh_helloworld_admin_controller");

This snippet will match routes and run the admin controller that we just created if the route belongs to Madhouse HelloWorld. It also add some filter to display the name of the plugin in right spots.

1.6- Save the settings in database!

With the current admin controller implementation, it will display a success message and redirect to the settings form. Let’s do some more and save the settings in the Osclass database!

Osclass gives us an easy way to store settings without creating our own SQL table called Preference.

Update the doSettingsPostAction() in your controller:

/**
 * Updates settings.
 *
 * @return
 */
private function doSettingsPostAction()
{
    // Get parameter.
    $numberOfMessagesPerPage = Params::getParam("i_display_length");

    // Save settings @ database.
    osc_set_preference("i_display_length", $numberOfMessagesPerPage, "plugin_madhouse_helloworld", "INTEGER");

    // Redirect and display a nice message!
    osc_add_flash_ok_message(__("Successfully updated settings!", "madhouse_helloworld"), "admin");
    $this->redirectTo(mdh_helloworld_admin_settings_url());
}

That’s it, you can enter a value which is persisted in the Preference system of Osclass and usable everywhere in your plugin.

Tutorial Osclass Plugins 2 - Admin settings example (Madhouse HelloWorld)

2- Pagination

Pagination in Osclass is a bit tricky and we’ve been asked many times how to show how to build a pagination on custom plugin page. We will be using the settings created in the previous section as an example of using settings in custom plugin page.

Here’s a few steps we’ll go through:

  • Implement pagination in our SQL query;
  • Update controller to take page and length as parameters;
  • Use the Pagination Osclass class to format our pagination;

2.1- Prepare some stuff

We will update the Web.php controller to export all the messages:

case "madhouse_helloworld_show":
    // Get our first message from our model layer.
    $message = Madhouse_HelloWorld_Models_Message::newInstance()->findByPrimaryKey(1);

    // Exports it to make it available to the view.
    View::newInstance()->_exportVariableToView(
        "mdh_helloworld_message",
        $message["s_content"]
    );

    // Get all messages
    $messages = Madhouse_HelloWorld_Models_Message::newInstance()->listAll();

    // Exports it to make it available to the view.
    View::newInstance()->_exportVariableToView(
        "mdh_helloworld_messages",
        $messages
    );
    break;

We will also add a helper to hHelloWorld.php to get those exported messages:

/**
 * Gets the all messages to display.
 *
 * @return String the message.
 *
 * @since 1.3.0
 */
function mdh_helloworld_get_messages()
{
    return View::newInstance()->_get("mdh_helloworld_messages");
}

Last but not least, display all the messages on our show.php view:

<h3><?php _e("All messages", "madhouse_helloworld"); ?>:</h3>
<?php $allMessages = mdh_helloworld_get_messages(); ?>
<ul>
<?php foreach ($allMessages as $currentMessage) : ?>
    <li><?php echo $currentMessage['s_content']; ?></li>
<?php endforeach; ?>

Here’s a preview of what it looks like:

Tutorial Osclass Plugins 2 - Pagination example 1 (Madhouse HelloWorld)

2.2- Update the model object

The default DAO does not support pagination out of the box, we need to create a method handling this.

Add this method to the classes/Madhouse/HelloWorld/Models/Message.php:

/**
 * {@inheritDoc}
 */
public function listAll($page = null, $length = null)
{
    $this->dao->select($this->getFields());
    $this->dao->from($this->getTableName());

    if (!is_null($page) && !is_null($length)) {
        $this->dao->limit($page - 1, $length);
    }

    $result = $this->dao->get();
    if($result == false) {
        return array();
    }

    return $result->result();
}

This method override the default listAll() method from the parent DAO class to add parameters for pagination purpose, using limit in the sense of SQL limit.

2.3- Update the controller

Update the call to the listAll() method with new parameters in your controller. Another addition will be to export the total number of messages to be able to create our pagination. It looks like this:

// Page number.
$page = Params::getParam("iDisplayPage");
if(!isset($page) || empty($page)) {
  $page = 1;
  Params::setParam("iDisplayPage", $page);
}

// Number of thread displayed per page.
$length = Params::getParam("iDisplayLength");
if(!isset($length) || empty($length)) {
  $length = 10;
  Params::setParam("iDisplayLength", $length);
}

// Get all messages.
$messages = Madhouse_HelloWorld_Models_Message::newInstance()->listAll($page, $length);
$totalMessages = count(Madhouse_HelloWorld_Models_Message::newInstance()->listAll());

// Exports it to make it available to the view.
View::newInstance()->_exportVariableToView(
    "mdh_helloworld_messages",
    $messages
);
View::newInstance()->_exportVariableToView(
    "mdh_helloworld_messages_count",
    $totalMessages
);

You can see that we added new request parameters, named iDisplayPage and iDisplayLength to keep the naming convention of Osclass and a total count of messages exported in view too.

Now, if you type this URL into your browser, you should see only one message displayed:

/index.php?page=custom&route=madhouse_helloworld_show&iDisplayLength=1

2.4- Display the pagination

Let’s update our helper to take some arguments:

function mdh_helloworld_show_url($page = "", $length = "")
{
    if (osc_version() >= 330) {
        $params = array();
        if (!empty($page)) {
            $params["iDisplayPage"] = $page;
        }
        if (!empty($length)) {
            $params["iDisplayLength"] = $length;
        }

        return osc_route_url("madhouse_helloworld_show", $params);
    }
    return osc_ajax_plugin_url("madhouse_helloworld/main.php") . "&do=show";
}

And, create a new one to get the total of messages to compute the pagination:

/**
 * Total number of messages in database.
 *
 * @return int
 *
 * @since 1.3.0
 */
function mdh_helloworld_count_messages()
{
    return (int) View::newInstance()->_get("mdh_helloworld_messages_count");
}

Then comes the most important part and where Osclass provides the most tools to handle paginations, format it and display it. Let’s create a new helper (again) in helpers/hHelloWorld.php to display our pagination component:

/**
 * Gets the pagination links of messages pagination
 *
 * @return string pagination links
 *
 * @since  1.3.0
 */
function mdh_helloworld_pagination() {
    if (mdh_helloworld_count_messages() === 0) {
        return '';
    } else {
        $params = array(
            'total'    => ceil(mdh_helloworld_count_messages() / Params::getParam("iDisplayLength")),
            'selected' => Params::getParam("iDisplayPage") - 1, // page 1 is actually 0.
            'url'      => mdh_helloworld_show_url('{PAGE}', Params::getParam("iDisplayLength")),
            'class_prev'         => 'prev',
            'class_next'         => 'next',
            'class_selected'     => 'active',
        );

        $pagination = new Pagination($params);
        return $pagination->doPagination();
    }
}

It uses everything we created previously to make use of the Pagination Osclass core class that will do most of the work for us. The only thing left to do is to display the result of this helper in our show.php view.

<div class="paginate">
    <?php echo mdh_helloworld_pagination(); ?></div>

Tada!

Tutorial Osclass Plugins 2 - Pagination example 2 (Madhouse HelloWorld)

3- Semver, upgrade and licensing

Final step of this part of the tutorial:

  • Version and updates management best practices;
  • Licensing for your Osclass plugins (and themes);

3.1- Version and upgrade

Managing versions is hard and upgrades could easily be the subject of an entire part of this tutorial, and it very well might be in the future.

The best way to prepare the field for later – more advanced – upgrade process by defining a preference when installing the plugin with the initial version of the plugin:

/**
 * (hook: install) Make installation operations
 *      It creates the database schema and sets some preferences.
 * @returns void.
 */
function mdh_helloworld_install()
{
    mdh_helloworld_import_sql(__DIR__ . "/assets/model/install.sql");

    osc_set_preference("version", "1.0.0", "plugin_madhouse_helloworld");
    osc_reset_preferences();
}
osc_register_plugin(osc_plugin_path(__FILE__), 'mdh_helloworld_install');

At the time we wrote those lines, we’re upgrading the plugin from 1.2.0 to 1.3.0. Therefore, we’ll update the version preference in the index.php and set a default preference for our new plugin settings:

if (version_compare(osc_get_preference("version", "plugin_madhouse_helloworld"), "1.3.0") < 0) {
    // Set a default value for new settings.
    osc_set_preference("i_display_length", 1, "plugin_madhouse_helloworld");

    // Upgrade the version @ database
    osc_set_preference("version", "1.3.0", "plugin_madhouse_helloworld");
    osc_reset_preferences();
}

Every new upgrade of the plugin would add a similar block for new settings or new SQL tables and upgrade the version.

3.2- Licensing

You must include a license to your plugin if you plan to release it to the world, no matter if it’s a commercial / premium or free plugin for Osclass. It defines what end users can an can’t do with your plugin and may influence greatly if your end users will buy or use your product in the end.

If you don’t what license to choose for your plugin or theme, you better check our quick overview of license on Osclass.

Conclusion

You now have a plugin that provides administation settings and pagination and little improvements that will simplify your life in end.

That’s a pretty good overview of plugin development for Osclass and should get you started working with Osclass but it’s still missing a lot of things like: looping helpers, real upgrade process, dependency management, etc.

One thought on “How to develop Osclass plugins – Part 2

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s