Site icon Osclass Documentation & Knowledge Base

How to extend fields

This page will show you hot to create an attributes plugin to extend the fields of the ads in your Osclass installation. In most cases the built-in functionality custom fields of Osclass is enough to extend the fields of an ad, however, sometime is necessary to add a search functionality or have a more deep customization. In those cases, creating a plugin is the best option.

Requirements

Base of our plugin

For this tutorial we’re going to use products attributes plugin as a base. Go catch the last release of it and download to your PC.

Structure of the plugin

Files and folders you will find on the plugin:


You’re free to rename those files whatever you want, as long as you change the names later in the code

Languages

Your plugin could be translate to other locales. To make it available, you need to use the functions __(‘text’, ‘name_of_your_plugin’) and _e(‘text’, ‘name_of_your_plugin’), for every string on it. Later, you should generate .mo and .po files for different languages and place them in folders inside the language folder.

Main file (index.php)

First, we’re going to declare the name and version of our plugin, feel free to modify the next lines

/*
Plugin Name: My Own attributes
Plugin URI: http://www.myownwebsite.org/myownplugin
Description: This plugin extends a category of items to my own attributes
Version: 1.0
Author: Me
Author URI: http://www.myownwebsite.org/
Short Name: myown_plugin
*/


At the end of index.php file, you will encounter the hooks, hooks can be placed anywhere, to keep code clear, we put them at the end. These are the basic hooks needed to have a full functional attributes plugin

// This is needed in order to be able to activate the plugin
osc_register_plugin(osc_plugin_path(__FILE__), 'myown_call_after_install');
// This is a hack to show a Configure link at plugins table (you could also use some other hook to show a custom option panel)
osc_add_hook(osc_plugin_path(__FILE__)."_configure", 'myown_admin_configuration');
// This is a hack to show a Uninstall link at plugins table (you could also use some other hook to show a custom option panel)
osc_add_hook(osc_plugin_path(__FILE__)."_uninstall", 'myown_call_after_uninstall');
 
// When publishing an item we show an extra form with more attributes
osc_add_hook('item_form', 'myown_form');
// To add that new information to our custom table
osc_add_hook('item_form_post', 'myown_form_post');
 
// When searching, display an extra form with our plugin's fields
osc_add_hook('search_form', 'myown_search_form');
// When searching, add some conditions
osc_add_hook('search_conditions', 'myown_search_conditions');
 
// Show an item special attributes
osc_add_hook('item_detail', 'myown_item_detail');
 
// Edit an item special attributes
osc_add_hook('item_edit', 'myown_item_edit');
// Edit an item special attributes POST
osc_add_hook('item_edit_post', 'myown_item_edit_post');
 
//Delete item
osc_add_hook('delete_item', 'myown_delete_item');
 
// previous to insert item
osc_add_hook('pre_item_post', 'myown_pre_item_post') ;

struct.sql

We are going to create a table to hold just one extra field (s_myfield, with a length of 50 characters), the struct.sql will be something like this example, but you’re free to modify its structure and add more fields.

CREATE TABLE /*TABLE_PREFIX*/t_item_myown_attr (
    fk_i_item_id INT UNSIGNED NOT NULL,
    s_myfield VARCHAR(50),
 
        PRIMARY KEY (fk_i_item_id),
        FOREIGN KEY (fk_i_item_id) REFERENCES /*TABLE_PREFIX*/t_item (pk_i_id)
) ENGINE=InnoDB DEFAULT CHARACTER SET 'UTF8' COLLATE 'UTF8_GENERAL_CI';

Installing the plugin

We need to create a MySQL table to save the extra fields of your plugin, there’re several ways to achieve this, but if you are going to use several tables, best way is to create a .sql file with the definition of it. Later, on index.php, we call our install function, which basically will read struct.sql and execute it contents.

function myown_call_after_install() {
    // Insert here the code you want to execute after the plugin's install
    // for example you might want to create a table or modify some values
 
    // In this case we'll create a table to store the Example attributes
    $conn = getConnection() ;
    $conn->autocommit(false);
    try {
        $path = osc_plugin_resource('myown_attributes/struct.sql');
        $sql = file_get_contents($path);
        $conn->osc_dbImportSQL($sql);
        $conn->commit();
    } catch (Exception $e) {
        $conn->rollback();
        echo $e->getMessage();
    }
    $conn->autocommit(true);
}

Uninstalling the plugin

When we installed the plugin we created some tables, if the user wants to uninstall it, we should delete the tables and remove all other info we created.

function myown_call_after_uninstall() {
    // Insert here the code you want to execute after the plugin's uninstall
    // for example you might want to drop/remove a table or modify some values
 
    // In this case we'll remove the table we created to store Example attributes
    $conn = getConnection() ;
    $conn->autocommit(false);
    try {
        $conn->osc_dbExec("DELETE FROM %st_plugin_category WHERE s_plugin_name = 'myown_plugin'", DB_TABLE_PREFIX);
        $conn->osc_dbExec('DROP TABLE %st_item_myown_attr', DB_TABLE_PREFIX);
        $conn->commit();
    } catch (Exception $e) {
        $conn->rollback();
        echo $e->getMessage();
    }
    $conn->autocommit(true);
}

Make your plugin configurable

Your plugin could be installed and uninstalled correctly now, you could start testing it! The next step is to make it able to be configurable, since we’re doing a standard attributes plugin, we need to let admin to chose which categories they want the plugin to be attached to. This is done with this small piece of code

function myown_admin_configuration() {
    // Standard configuration page for plugin which extend item's attributes
    osc_plugin_configure_view(osc_plugin_path(__FILE__));
}

Publishing items

We need to create a template of a form to publish our new extra field, take a look at item_edit.php

Pro-tip: use unique name variables and fields, so they don’t will be mixed up with Osclass’ core or someone else plugin.

<h3><?php _e('MyOwn attributes', 'myown_attributes') ; ?></h3>
<table>
    <tr>
        <?php
            // This lines prevent to clear the field if the form is reloaded
            if( Session::newInstance()->_getForm('myown_myfield') != '' ) {
                $detail['myown_myfield'] = Session::newInstance()->_getForm('myown_myfield');
            }
        ?>
        <td><label for="make"><?php _e('MyField', 'myown_attributes'); ?></label></td>
    	<td><input type="text" name="myown_myfield" id="myown_myfield" value="<?php if(@$detail['s_myfield'] != ''){echo @$detail['s_myfield']; } ?>" size="20" /></td>
    </tr>
</table>


We had now our template file item_edit.php (yeah, it’s called item_edit, but it will work for both, edit and add!). We need now a way to display it on the form. That’s an easy task, take a look at this function:

function myown_form($catId = '') {
    // We received the categoryID
    if($catId!="") {
        // We check if the category is the same as our plugin
        if(osc_is_this_category('myown_plugin', $catId)) {
            include_once 'item_edit.php';
        }
    }
}

Test it, test it now. The form should appear if you select the correct categories. Time to save our field in our mighty table.

function myown_form_post($catId = null, $item_id = null) {
    // We received the categoryID and the Item ID
    if($catId!=null) {
        // We check if the category is the same as our plugin
        if(osc_is_this_category('myown_plugin', $catId)) {
                // Insert the data in our plugin's table
                $conn = getConnection() ;
                $conn->osc_dbExec("INSERT INTO %st_item_myown_attr (fk_i_item_id, s_myfield) VALUES (%d, '%s')", DB_TABLE_PREFIX, $item_id, Params::getParam('myown_myfield') );
        }
    }
}


Editing an ad is quite similar to publish it, for that, we called our template item_edit.php. Since we’re using the same file for publish and edit, we only need to write functions to display the form (before) and manage the data (after).

// Self-explanatory
function myown_item_edit($catId = null, $item_id = null) {
    if(osc_is_this_category('myown_plugin', $catId)) {
        $conn = getConnection() ;
        // Gather the information related to the ad we're editing
        $detail = $conn->osc_dbFetchResult("SELECT * FROM %st_item_myown_attr WHERE fk_i_item_id = %d", DB_TABLE_PREFIX, $item_id);
        if(isset($detail['fk_i_item_id'])) {
            include_once 'item_edit.php';
        }
    }
}
 
function myown_item_edit_post($catId = null, $item_id = null) {
	// We received the categoryID and the Item ID
	if($catId!=null) {
		// We check if the category is the same as our plugin
		if(osc_is_this_category('myown_plugin', $catId)) {
                    $conn = getConnection() ;
                    $conn->osc_dbExec("REPLACE INTO %st_item_myown_attr (fk_i_item_id, s_myfield) VALUES (%d, '%s')", DB_TABLE_PREFIX, $item_id, Params::getParam('myown_myfield') );
		}
	}
}


Pro-tip: We use REPLACE instead of an UPDATE SQL query because, if we add the plugin after some ads were published, the record of them in the table would not exists and an UPDATE query will fail, instead, a REPLACE query will work always.

Search filters

At this point, we should have a full working plugin that add an extra attribute (myfield) to our ads, but we want our users to be able to filter search results by our new field. We need three things, a template file (search_form.php) for the filter, a function to display the template and a function to add conditions to the search.

The template will be quite simple, an input text field. This template should change depends on your needs, but we’re going to do the most basic condition, any ad which contains a certain text in the new field.

<h3><?php _e('MyOwn attributes', 'myown_attributes') ; ?></h3>
<div class="row one_input">
    <table>
        <tr>
            <td>
                <label for="myown_myfield"><?php _e('MyField', 'myown_attributes'); ?></label>
                <br/>
                <input type="text" id="myown_myfield" name="myown_myfield" />
            </td>
        </tr>
    </table>
</div>


To display the new search filter

function myown_search_form($catId = null) {
    include_once 'search_form.php';
}


Ok, the filter should show up now in the search page, let’s add some conditions to our search!

// Adds some plugin-specific search conditions
function myown_search_conditions($params) {
    // we need conditions and search tables (only if we're using our custom tables)
        $has_conditions = false;
 
        foreach($params as $key => $value) {
            // We may want to  have param-specific searches
            switch($key) {
                case 'myown_myfield':
                    Search::newInstance()->addConditions(sprintf("%st_item_myown_attr.s_myfield LIKE '%%%s%%'", DB_TABLE_PREFIX, $value));
                    $has_conditions = true;
                    break;
                default:
                    break;
            }
        }
 
        // Only if we have some values at the params we add our table and link with the ID of the item.
        if($has_conditions) {
            Search::newInstance()->addConditions(sprintf("%st_item.pk_i_id = %st_item_myown_attr.fk_i_item_id ", DB_TABLE_PREFIX, DB_TABLE_PREFIX));
            Search::newInstance()->addTable(sprintf("%st_item_myown_attr", DB_TABLE_PREFIX));
        }
}

That function could be scary at first, and it could be simplified, but we prefer to leave it that way so it could be easily for you to modify it and add more fields and conditions.

Additional functions

Our plugin is almost finished, it lets you install, uninstall, add and edit ads and even perform some filtered searches! Let’s add two additional functions to make an awesome plugin.


First, we should perform some actions when an ad is deleted. Basically, delete the data in our table related to that ad, if the ad no longer exists, there’s no point to keep fields of that ad.

function myown_delete_item($item) {
    $conn = getConnection();
    $conn->osc_dbExec("DELETE FROM %st_item_myown_attr WHERE fk_i_item_id = '" . $item . "'", DB_TABLE_PREFIX);
}

What more could be add? Well, this is completely unnecessary but it’s awesome! Imagine your user is publishing an ad, but for some reason it failed, maybe the title is too short, or description too long,… so the page is reloaded and your extra field is empty!! In our example plugin is not such a problem, a simple 50 characters length text input is not much, but imagine you ask the user to write a dozen of fields, if the publish fail and your fields are empty, the user will be annoyed. To avoid that, we use this function (it’s ok if you don’t understand it, it works, just need to write the variable and its value):

function products_pre_item_post() {
    Session::newInstance()->_setForm('myown_myfield' , Params::getParam('myown_myfield'));
    // keep values on session
    Session::newInstance()->_keepForm('myown_myfield');
}