Download EE 2 Docs Download EE 1 Docs
ExpressionEngine

2.9.2 User Guide

ExpressionEngine Fieldtypes

Basic File Structure

All fieldtypes should be placed into the third_party folder in a package and be named after that package name. So in a packaged named google_maps the fieldtype file will be ft.google_maps.php. All fieldtypes must inherit from the EE_Fieldtype base class and they must provide an $info array with a name and version number.

<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');

class Google_maps_ft extends EE_Fieldtype {

    var $info = array(
        'name'      => 'Google Maps',
        'version'   => '1.0'
    );

    // --------------------------------------------------------------------

    function display_field($data)
    {
        return form_input(array(
            'name'  => $this->field_name,
            'id'    => $this->field_id,
            'value' => $data
        ));
    }
}
// END Google_maps_ft class

/* End of file ft.google_maps.php */
/* Location: ./system/expressionengine/third_party/google_maps/ft.google_maps.php */

Example - Google Maps

The snippets below were truncated for clarity. The full example fieldtype can be downloaded here.

Installation

The google maps fieldtype is going to have 3 global settings. Latitude, longitude, and zoom. These will determine what the default map looks like. By returning an array from within install we can provide a default set of global settings.

function install()
{
    // Somewhere in Oregon ...
    return array(
        'latitude'  => '44.06193297865348',
        'longitude' => '-121.27584457397461',
        'zoom'      => 13
    );
}

Uninstaller

The installation method for this fieldtype does not create any additional tables, so no cleanup work needs to be done. The default uninstall() method provided by the EE_Fieldtype parent class will suffice. Most fieldtype methods have sensible defaults to help reduce duplicate code.

Global Settings

The installer sets the default global settings, but currently there is no way to change these from the control panel. We can use the display_global_settings() method to return the contents of the settings form. Having this method also enables the global settings link on the overview page.

function display_global_settings()
{
    $val = array_merge($this->settings, $_POST);

    $form = form_label('latitude', 'latitude').NBS.form_input('latitude', $val['latitude']).NBS.NBS.NBS.' ';
    $form .= form_label('longitude', 'longitude').NBS.form_input('longitude', $val['longitude']).NBS.NBS.NBS.' ';
    $form .= form_label('zoom', 'zoom').NBS.form_dropdown('zoom', range(1, 20), $val['zoom']);

    return $form;
}

Manually entering longitudes and latitudes is inconvenient so the final method in the example download also adds some javascript to let the user choose from a map.

Saving Global Settings

In most instances saving the global settings is as easy as storing the $_POST array. Remember to include existing global settings if not everything can be changed.

function save_global_settings()
{
    return array_merge($this->settings, $_POST);
}

Individual Settings

The default map may not always be the desired choice for each map field, so on the regular settings page it will display a similar configuration screen. The individual settings are in a table, so they need to use add_row().

function display_settings()
{
    $latitude = isset($data['latitude']) ? $data['latitude'] : $this->settings['latitude'];
    $longitude        = isset($data['longitude']) ? $data['longitude'] : $this->settings['longitude'];
    $zoom             = isset($data['zoom']) ? $data['zoom'] : $this->settings['zoom'];

    ee()->table->add_row(
        lang('latitude', 'latitude'),
        form_input('latitude', $latitude)
    );

    ee()->table->add_row(
        lang('longitude', 'longitude'),
        form_input('longitude', $longitude)
    );

    ee()->table->add_row(
        lang('zoom', 'zoom'),
        form_dropdown('zoom', range(1, 20), $zoom)
    );

    // Map preview
    $this->_cp_js();
    ee()->javascript->output(
        // Map container needs to be visible when you create
        // the map, so we'll wait for activate to fire once
        '$("#ft_google_maps").one("activate", gmaps);'
    );

    ee()->table->add_row(
        lang('preview'),
        '<div style="height: 300px;"><div id="map_canvas" style="width: 100%; height: 100%"></div></div>'
    );
      }

Saving Individual Settings

Saving individual field settings works largely the same as saving global settings. Keep be aware that they are later merged with global settings, so they can override a global setting.

function save_settings($data)
{
    return array(
        'latitude'  => ee()->input->post('latitude'),
        'longitude' => ee()->input->post('longitude'),
        'zoom'      => ee()->input->post('zoom')
    );
}

Displaying the Field (Publish Page)

With all the settings set up, it can now be displayed on the publish screen. A key factor when you get to this stage is to decide in what format the data should be stored. Since all three available values in this case are numbers, this field will store them separated by pipes (lang|lat|zoom).

function display_field($data)
{
    $data_points = array('latitude', 'longitude', 'zoom');

    if ($data)
    {
        list($latitude, $longitude, $zoom) = explode('|', $data);
    }
    else
    {
        foreach($data_points as $key)
        {
            $$key = $this->settings[$key];
        }
    }

    $zoom = (int) $zoom;
    $options = compact($data_points);

    // some javascript

    $value = implode('|', array_values($options));
    $hidden_input = form_input($this->field_name, $value, 'id="'.$this->field_name.'" style="display: none;"');

    return $hidden_input.'<div style="height: 500px;"><div id="map_canvas" style="width: 100%; height: 100%"></div></div>';
}

Rendering the Tag

Finally, the field needs a frontend display. For google maps this will almost exclusively be javascript.

function replace_tag($data, $params = array(), $tagdata = FALSE)
{
    static $script_on_page = FALSE;
    $ret = '';

    list($latitude, $longitude, $zoom) = explode('|', $data);

    // google maps javascript ...

    return $ret.'<div style="height: 500px;"><div id="map_canvas_'.$this->field_id.'" style="width: 100%; height: 100%"></div></div>';
}

Creating Multiple Rendering Options

Along with parameters a field can also provide tag modifiers to change its output. In the template these are called by adding a colon to the fieldname, followed by the modifier name. For example: {myfield:latitude}. The advantage that field modifiers have over parameters is that they can be used in conditionals.

Parsing the modifiers is identical to using the regular replace_tag() function. The method name must start with replace_ followed by the modifier name.

function replace_latitude($data, $params = array(), $tagdata = FALSE)
{
    list($latitude, $longitude, $zoom) = explode('|', $data);
    return $latitude;
}

There is also a function to catch ALL modifiers, whose declaration includes the modifier name and looks like this:

function replace_tag_catchall($file_info, $params = array(), $tagdata = FALSE, $modifier)

You can also use variable pairs to capture tag data for processing in your modifier function. The syntax for using modifiers on variable pairs in your templates is:

{myfield:option}
    Tag data here
{/myfield}

Development Reference

class EE_Fieldtype

Class Variables

The base class provides a handful of base variables:

property EE_Fieldtype::$EE

A reference to the controller instance.

Deprecated since version 2.7.0.

property EE_Fieldtype::$id

The field identifier (unique for the current content type).

property EE_Fieldtype::$name

The field name, used for the tag names.

property EE_Fieldtype::$content_id

The unique id of the parent content that contains this field. Not available in install, settings, or other non-content environments.

property EE_Fieldtype::$content_type
property EE_Fieldtype::$settings

The field settings array

property EE_Fieldtype::$field_id

Alias for id

property EE_Fieldtype::$field_name

Alias for name

Note

Allowing fields to be used as tag pairs requires some extra processing to reduce the parsing overhead. So if you want to create such a field, you need to explicitly tell the parser to pre-parse these pairs:

property EE_Fieldtype::$has_array_data

TRUE if the field can be used as a tag pair

Function Reference

EE_Fieldtype::id()

Getter for id.

Return type:Integer/String
EE_Fieldtype::name()

Getter for name.

Return type:String
EE_Fieldtype::content_id()

Getter for content_id.

Return type:Integer/String
EE_Fieldtype::content_type()

Getter for content_type.

Return type:String
EE_Fieldtype::row($key[, $default = NULL])

Accessor for the current content type parent row. In the case of channel entries, this would be current entry row. If the key is not found, the value given in default is returned. Not all content types have all row keys.

Param:string $key: The name of the row value to retrieve
Param:mixed $default: The value to return if $key is not set
Returns:The value of the row element, or $default.
Return type:Mixed
EE_Fieldtype::install()

Installs the fieldtype and sets initial global settings. Can return an array of global variables.

Return type:Void
EE_Fieldtype::uninstall()

Handle any cleanup needed to uninstall the fieldtype. Channel data is dropped automatically.

Return type:Void
EE_Fieldtype::display_field($data)

Used to render the publish field.

Parameters:
  • $data (array) – Current field data, blank for new entries
Returns:

The field to display on the publish page

Return type:

String

EE_Fieldtype::validate($data)

Validates the field input

Parameters:
  • $data (array) – Current field data, blank for new entries
Returns:

TRUE if the field validates, an error message otherwise

Return type:

Boolean/String

EE_Fieldtype::save($data)

Preps the data for saving

Parameters:
  • $data (array) – Current field data, blank for new entries
Returns:

Data to save to the database

Return type:

String

EE_Fieldtype::post_save($data)

Handles any custom logic after an entry is saved.

Called after an entry is added or updated. Available data is identical to save, but the settings array includes an entry_id.

Parameters:
  • $data (array) – Current field data, blank for new entries
Return type:

Void

EE_Fieldtype::delete($ids)

Handles any custom logic after an entry is deleted.

Called after one or more entries are deleted.

Parameters:
  • $ids (array) – IDs of deleted entries. Please note that channel data is removed automatically so most fieldtypes will not need this method.
Return type:

Void

EE_Fieldtype::pre_loop($data)

Before the tag is rendered on the frontend, this function is called to pass field data for the entire channel entries loop to the fieldtype for preprocessing or caching. This function is useful when your fieldtype needs to query the database to render its tag. Instead of querying with each loop of the channel entries tag, all data needed can be gathered up front, therefore reducing queries and loadtime needed.

Parameters:
  • data (array) – contains all field data for the current channel entries loop, limited only to the fieldtype’s own data
Return type:

Void

EE_Fieldtype::replace_tag($data[, $params = array()[, $tagdata = FALSE]])

Replace the field tag on the frontend.

Parameters:
  • $data (array) – contains the field data (or prepped data, if using pre_process)
  • $params (array) – contains field parameters (if any)
  • $tagdata (array) – contains data between tag (for tag pairs)
Returns:

String to replace the tag

Return type:

String

EE_Fieldtype::display_settings($data)

Display the settings page. The default ExpressionEngine rows can be created using built in methods. All of these take the current $data and the fieldtype name as parameters:

$this->field_formatting_row($data, 'google_maps');
  • $this->text_direction_row() - text direction toggle
  • $this->field_formatting_row() - field formatting options (xhtml, br, none)
  • $this->field_show_smileys_row() - yes/no toggle to show smileys
  • $this->field_show_glossary_row() - yes/no toggle to show the glossary
  • $this->field_show_spellcheck_row() - yes/no toggle to show spellcheck
  • $this->field_show_file_selector_row() - yes/no toggle to show the file selector button
  • $this->field_show_writemode_row() - yes/no toggle to show the writemode button
Parameters:
  • $data (array) – Field settings
Returns:

Either nothing, or a string for your settings fields

Return type:

Void/String

EE_Fieldtype::validate_settings($data)

Validate fieldtype settings. In this method, you can set rules via the Form Validation library to ensure values entered in your settings form are valid. Here is an example from our File field:

function validate_settings($data)
{
    ee()->form_validation->set_rules(
        'file_allowed_directories',
        'lang:allowed_dirs_file',
        'required|callback__check_directories'
    );
}

Callbacks may be specified as well, as you see above we are calling a method called _check_directories to ensure upload destinations exist before creating a new file field.

Parameters:
  • $data (array) – Submitted settings for this field
Return type:

Void

EE_Fieldtype::save_settings($data)

Save the fieldtype settings.

Parameters:
  • $data (array) – Submitted settings for this field
Returns:

Settings for the field

Return type:

Array

EE_Fieldtype::settings_modify_column($data)

Allows the specification of an array of fields to be added, modified or dropped when fields are created, edited or deleted.

Parameters:
  • $data (array) – settings for this field as well an indicator of the action being performed ($data['ee_action'] with a value of delete, add or get_info).
Returns:

Fields to be created, modified or dropped when fields are created

Return type:

Array

By default, when a new field is created, 2 fields are added to the exp_channel_data table. The content field (field_id_x) is a text field and the format field (field_ft_x) is a tinytext NULL default. You may override or add to those defaults by including an array of fields and field formatting options in this method. For example, the date file type requires an additional field_dt_x field and different content field type:

function settings_modify_column($data)
{
    $fields['field_id_'.$data['field_id']] = array(
        'type'      => 'INT',
        'constraint'    => 10,
        'default'   => 0
        );

    $fields['field_dt_'.$data['field_id']] = array(
        'type'      => 'VARCHAR',
        'constraint'    => 8
        );

    return $fields;
}
EE_Fieldtype::post_save_settings($data)

Do additional processing after the field is created/modified.

$this->settings is fully available at this stage.

Parameters:
  • $data (array) – submitted settings for this field
Return type:

Void

EE_Fieldtype::display_global_settings()

Display a global settings page. The current available global settings are in $this->settings.

Returns:Global settings form
Return type:String
EE_Fieldtype::save_global_settings()

Save the global settings. Return an array of global settings.

Returns:Global settings
Return type:Array
EE_Fieldtype::pre_process($data)

Preprocess the data on the frontend. Multiple tag pairs in the same weblog tag will cause replace_tag to be called multiple times. To reduce the processing required to extract the original data structure from the string (i.e. unserializing), the pre_process function is called first.

Parameters:
  • $data (array) – Field data
Returns:

Prepped $data

Return type:

Array

Content Type Independence

Fieldtypes can be used to describe fields in many different types of content. For most fieldtypes adding support simply means overriding the accepts_content_type method to always return TRUE.

EE_Fieldtype::accepts_content_type($name)

Returns TRUE or FALSE based on whether or not the content type is supported. By default all fieldtypes support the channel content type.:

public function accepts_content_type($name)
{
  return ($name == 'channel');
}
Parameters:
  • $name (string) – The name of the content type
Returns:

Supports the given content type?

Return type:

Boolean

However, if your fieldtype stores its own data, then you must make sure to clearly separate the data by content type. You can do this by accessing the current content type with the content_type getter method, and using it as an additional parameter everywhere you store or retrieve data.

You must also handle the complete out removal of a content type.

EE_Fieldtype::unregister_content_type($name)

Remove a content type from the current fieldtype.

Parameters:
  • $name (string) – Name of the content type to remove.
Return type:

void

If your fieldtype creates columns or tables dynamically, you may also want to implement the opposite case of when a fieldtype is added.

EE_Fieldtype::register_content_type($name)

Add a content type from the current fieldtype.

Parameters:
  • $name (string) – Name of the content type to add.
Return type:

void

Grid Fieldtype Development

In order to make your fieldtypes compatible with Grid, a few more methods as well as Javascript callbacks are available.

To make your fieldtype recognized by Grid as a Grid-compatible fieldtype, you need to modify your implementation of accepts_content_type to accept the grid content type. For example:

public function accepts_content_type($name)
{
    return ($name == 'channel' || $name == 'grid');
}

Once that’s done, your fieldtype will show up in the list of fieldtypes available for use when setting up a new Grid column.

Grid Column Settings

EE_Fieldtype::grid_display_settings($data)

Displays settings for your Grid fieldtype:

public function grid_display_settings($data)
{
    return array(
        $this->grid_field_formatting_row($data),
        $this->grid_text_direction_row($data),
        $this->grid_max_length_row($data)
    );
}

Each array item should be a string.

Parameters:
  • $data (array) – Column settings
Returns:

Array of settings for the column

Return type:

Array

Much like in display_settings, we provide several helpers to insert the settings rows you may need:

EE_Fieldtype::grid_settings_row($label, $content[, $wide = FALSE])

Adds a generic settings row to a Grid column.

Parameters:
  • $label (string) – Label for the setting
  • $content (string) – HTML for the form element(s) for the setting
  • $wide (boolean) – If TRUE, gives more room to the content portion of the setting
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_dropdown_row($label, $name, $data[, $selected = NULL[, $multiple = FALSE[, $wide = FALSE[, $attributes]]]])

Adds a dropdown settings row to a Grid column.

Parameters:
  • $label (string) – Label for the setting
  • $name (string) – Value for the name attribute of the dropdown
  • $data (array) – Array of options to show in the dropdown
  • $selected (string) – Selected value of the setting
  • $multiple (boolean) – Whether or not this is a multiselect
  • $wide (boolean) – If TRUE, gives more visual room to the dropdown portion of the setting
  • $attributes (string) – Any extra HTML attributes to put on the dropdown
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_checkbox_row($label, $name, $value, $checked)

Adds a settings row with a single Checkbox to a Grid column.

Parameters:
  • $label (string) – Label for the setting
  • $name (string) – Value for the name attribute of the checkbox
  • $value (string) – Value for the value attribute of the checkbox
  • $checked (boolean) – Whether or not the box is checked on display
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_yes_no_row($label, $name, $data)

Adds a settings row with a Yes radio button and a No radio button to a Grid column.

Parameters:
  • $label (string) – Label for the setting
  • $name (string) – Value for the name attribute of the radio buttons
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_text_direction_row($$data)

Adds a settings row with a dropdown of text direction options.

Parameters:
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_field_formatting_row($$data)

Adds a settings row with a dropdown of text formatting options.

Parameters:
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_max_length_row($$data)

Adds a settings row with a small textbox to enter the maximum number of characters your fieldtype accepts.

Parameters:
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_multi_item_row($$data)

Adds a settings row with a textarea for entering options to be used in a fieldtype where the content is limited to multiple options to select from, such as radio buttons.

Parameters:
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

EE_Fieldtype::grid_textarea_max_rows_row($$data)

Adds a settings row with a small textbox to enter the maximum number of rows a textarea may show.

Parameters:
  • $data (array) – Data array passed to grid_display_settings()
Returns:

String of HTML ready to use as a Grid settings row

Return type:

String

Check the implementations of grid_display_settings in our native fieldtypes to see examples of the above helper methods being used as well as other ways to display custom settings.

Validating Grid Settings

EE_Fieldtype::grid_validate_settings($data)

Validating your Grid column’s settings is similar to validating field contents. Unlike validate_settings, you cannot use the Form Validation library, rather you simply check the array of settings passed to your fieldtype, and then return TRUE or an error message if the settings do not validate.

For example, here is the validation method for a File field’s settings when used as a Grid column:

function grid_validate_settings($data)
{
    if ( ! $this->_check_directories())
    {
        ee()->lang->loadfile('filemanager');
        return lang('please_add_upload');
    }

    return TRUE;
}

If the _check_directories() check fails, we return an error message. Otherwise if it passes, we return TRUE.

Parameters:
  • $data (array) – Submitted settings for this field
Return type:

Void

Grid Fieldtype Events

All of the regular fieldtype methods (display_field(), replace_tag(), etc.) are available prefixed with “grid_” for special handling when being used in the context of the Grid field, with a few exceptions noted below. For example:

// Only called when being used as a normal fieldtype:
public function display_field($data)
{
    // Display code
}

// Only called when being rendered in a Grid field cell:
public function grid_display_field($data)
{
    // Display code for Grid cell
}

However, if a fieldtype does NOT implement grid_display_field(), Grid will call display_field() to display the field’s form in the cell. This applies to all fieldtype methods except for the following:

Method Exception
install() No unique Grid method required
uninstall() No unique Grid method required
display_global_settings() No unique Grid method required
save_global_settings() No unique Grid method required
settings_modify_column() Must use Grid Column Settings methods
display_settings() Must use grid_display_settings
validate_settings() Must use grid_validate_settings

The idea is that most fieldtypes should be able to use the same code to handle their field operations for both Grid and the normal publish form, but if not, you can easily override the behavior and run special operations when in the context of Grid.

If you use grid_* methods, you may want to look for ways to refactor your fieldtype where there is overlapping logic to run. For example, some of our native fieldtypes require slightly different code to render the HTML needed to display fields in display_field() and grid_display_field(), so we try to centralize the the common logic between them for better code maintenance.

Grid Fieldtype Settings Class Property

When your fieldtype is in the context of Grid, it will have a few more items available to you in your fieldtype’s $settings class property.

Settings Key Name Description
col_id The ID of the column your fieldtype is in publish form
col_name The short name of the column your fieldtype is in
col_required Whether or not the column is required (y/n), field_required will also be set to this
grid_field_id Field ID of the column’s parent Grid field
grid_row_name In certain instances, such as saving data, will be set to a unique row name when a row ID might not be available for new rows
grid_row_id When available, ID of the current row being processed

These are accessed as array keys of your $settings class property like so:

$this->settings['col_id'];

Grid Javascript Events

Several Javascript events are fired on certain actions to let your fieldtypes know when those actions have taken place. Here is an overview.

Event Name Description
display Called when a row is displayed on the publish form
remove Called when a row is deleted from the publish form
beforeSort Called before a row starts sorting on the publish form
afterSort Called after a row finishes sorting on the publish form
displaySettings Called when a fieldtype’s settings form is displayed on the Grid field settings page

To bind an event, use the below Javascript as an example:

Grid.bind("date", "display", function(cell)
{
    // Act on event
});

Here are the usage details for this function:

Grid.bind(fieldtype, event, callback)
Arguments:
  • fieldtype (string) – Your short fieldtype name
  • string – Event name
  • callback – Callback function to use for the event
Return type:

Void

A jQuery object of the cell being affected by the current event (or settings form in the case of displaySettings) is passed to the callback function. There are a few data attributes available on the cell object such as fieldtype, column-id and row-id (row-id will be undefined for new rows). Plus since it’s a jQuery object, you have all DOM traversal methods available to act upon.

User Contributed Notes

Posted by: iain on 30 May 2013 9:31pm
iain's avatar

If you want to access information like the current entry’s entry_id, url_title or any other data associated with the entry from the fieldtype’s replace_tag method, you can access it via

$this->row 

So to access the entry_id you’d need

$this->row['entry_id'
Posted by: Michael C. (ProImage) on 13 January 2013 4:21pm
Michael C. (ProImage)'s avatar

If your fieldtype references an external .php file (for separating bulk data, for example), be careful when using the “_once” variants of require() or include(). A situation can occur where your fieldtype can be called multiple times per EE pageload, but the variables would be reset between each call, leaving every call but the first without the include()‘d / require()‘d variables at hand.

Posted by: Jamie Rumbelow on 4 November 2011 12:41pm
Jamie Rumbelow's avatar

It’s really, really, REALLY important that you return an array from the fieldtype’s install() method, even if you’re not using any global settings. Failing to do so causes irrevocable amounts of pain.

Posted by: Kenny M. on 3 September 2010 11:00pm
Kenny M.'s avatar

Just a note that on display_field the data has htmlspeciachars on it if you’re trying to deserialize or decode_json so make sure you do this:

htmlspecialchars_decode($data

Before you try and decode it.

Posted by: Leevi Graham on 31 March 2010 6:34pm
Leevi Graham's avatar

If you want your fieldtype to act as a tag pair as well as a single tag you must add the following as a class variable:

$has_array_data TRUE 

You must have an EllisLab product license and have at least 50 posts to the community forums to contribute notes to the User Guide