Recent Content List Extending core functionality

Admin UI Title on 13 Jun 2020

 Plugin title for Admin UI

It is done from 2 parts:


and menu caption  


Example how to build your own title that looks similar like core one if you want it a different way for edit mode (if edit mode is not in the menu):

public function __construct($request, $response, $params = array()) {

$action = $_GET['action'];
$this->pluginTitle = _WEBLINKSADMIN;
if($action == 'edit') 
$this->pluginTitle .= ' <span class="fa fa-angle-double-right e-breadcrumb"></span> '._LINKVALIDATION;
parent::__construct($request, $response, $params = array());

ID field on 18 May 2020

Display ID field:

I don't remember that I had to set displaying this field, but it is not displayed by default now (generated by Plugin builder). You need to add "force" parameter to display it.

'uid' => array ( 'title' => LAN_ID, 'data' => 'int', 'forced'=> TRUE, 'readonly'=>TRUE),

Display comment for some table on 01 May 2020

example for pnews table

Actually moving plugin comments (in a separate table) to the core comment system.

$text .= e107::getComment()->compose_comment('pnews', 'comment', $newsid, null, $title, false, 'html');;


'pnews' - is key for comments used for this table/plugin, mainly related table name

$newsid is unique ID for this table

$title is subject for comment

* @param string $table - the source table for the associated item 
* @param string $action - usually 'comment' or 'reply' 
* @param integer $id - ID of item associated with comments (e.g. news ID) 
* @param int $width - appears to not be used 
* @param string $subject 
* @param boolean $rate 
* @param boolean|string $return true, false or 'html' 
* @param boolean $tablerender 
* @return array|null|string|void

You can use render() method too, with shorter numbers of parameters.

SEF URL field on 07 Dec 2019

 SEF-URL field

Basic settings:

'sef' => array ( 'title' => LAN_SEFURL, 'type' => 'text', 'data' => 'str', 'writeParms' => 'size=xxlarge&sef=title' ),

Batch option: 

'news_sef' => array('title' => LAN_SEFURL, 'batch'=>1,  (....)  'writeParms'=>array('size'=>'xxlarge', 'show'=>1, 'sef'=>'news_title'))

Date field on 07 Dec 2019

Date field (with calender)

minimal settings:

'date_added' => array ( 'title' => 'Added', 'type' => 'datestamp', 'data' => 'int' ),
'date_modified' => array ( 'title' => 'Modified', 'type' => 'datestamp', 'data' => 'int' ),


'date_added' => array ( 'title' => 'Added', 'type' => 'datestamp', 'data' => 'int', 'readonly' => true ),
'date_modified' => array ( 'title' => 'Modified', 'type' => 'datestamp', 'data' => 'int', 'readonly' => true ),<span></span>

Readonly has 2 modes:
1 = read-only, but only when there is a value,
2 = read-only regardless.

Correct values:

public function beforeCreate($new_data,$old_data)
$new_data['date_added'] = time();
$new_data['date_modified'] = time(); 
return $new_data;

public function beforeUpdate($new_data, $old_data, $id)
$new_data['date_modified'] = time(); 
return $new_data;

Multicheckbox field on 07 Dec 2019

How to set multicheck field

Multicheck field in admin UI

Inspiration (or core check): admin/newspost.php and field: news_render_type


=> array( 
	'title' => "Checkbox check", 
	'type' => 'dropdown', 
	'writeParms'=>array('multiple'=>'1', 'optArray' => array('0'=>'first option', '1' => 'second option')),<br />
	'width' => 'auto', 
	'thclass' => 'left', 
	'class' => 'left', 
	'nosort' => false, 
),<br />

- 'data' - Data Type: string (it saves values separated by comma)
- 'type' - news uses dropdown, type checkbox is only for one value ( (0 or 1 is returned)

Inline editing:


type checkboxes allows multiselect


'multiple' - you can select more than one option

'optArray' - list of options. It's just example, you can fill it in init() method from database values. If you don't use keys, they will be 0,1,2..., but if you use keys, those ones will be used.

Example how to get data from related table:

$parents = e107::getDb()->retrieve("property_location", "*", "WHERE parent_id = 0", true);
            $parent_item[0] = "None selected";
            foreach($parents as $parent) {
              $parent_item[$parent['id']] = $parent['title'];
	        $this->fields['parent_id']['writeParms']['optArray'] =  $parent_item;

Options field on 18 Oct 2019

How to customize options field

By default, there are only edit and delete buttons.

Available options (only tested ones):

'noselector' => true, removes option to select displayed fields in read mode
'readParms'=>'sort=1' adds sort option. It doesn't work if you add buttons manually 

Add/change your own buttons:

Change type key to be able customize those buttons:

'options' => array(
'type' => 'method',
'width' => '10%',
'forced' => true,
'thclass' => 'center last',
'class' => 'center',
'sort' => false,

and  add

* Override the default Options field.
* @param $parms
* @param $value
* @param $id
* @param $attributes
* @return string
function options($parms, $value, $id, $attributes)
$text = '';if($attributes['mode'] == 'read')

return $text;

Result:  no buttons

Add edit button back:  ( f.e. if you want your own icons)

parse_str(str_replace('&amp;', '&', e_QUERY), $query); //FIXME - FIX THIS
$query['action'] = 'edit';
$query['id'] = $id;
$query = http_build_query($query,null, '&amp;');

$text = "<a href='".e_SELF."?{$query}' class='btn btn-default' title='".LAN_EDIT."' data-toggle='tooltip' data-placement='left'>

Result: only Edit button

Add delete button back: ( f.e. if you want your own icons)

$text .= $this->submit_image('menu_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', array('class' => 'action delete btn btn-default'));

Result: Edit and Delete buttons

NEW 18.12.2019

Add delete button for record deleting (tested): 

$text .= $this->submit_image('etrigger_delete['.$id.']', $id, 'delete', LAN_DELETE.' [ ID: '.$id.' ]', 
array('class' => 'action delete btn btn-danger',
'icon'=> '<i class="fa fa-trash-o"></i>'));

The different way how to do the same thing:  (the same result as default options)

$att['readParms'] = 'sort=1';

if($attributes['mode'] == 'read')
$text = "<div class='btn-group'>";
//add your button here
$text .= $this->renderValue('options',$value,$att,$id);
//or here
$text .= "</div>"; 
return $text;

Boolean field on 20 Aug 2019

Boolean type

radio buttons with enable/disable

Default generated value by plugin builder:

'redirection_status' => array ( 'title' => 'Statust', 'type' => 'boolean',
'data' => 'int', 'width' => 'auto', 'help' => '', 'readParms' => array (),
'writeParms' => array (), 'class' => 'left', 'thclass' => 'left',),

The result is ON/OFF switcher

Available parameters (from official documentation)

inverse 0 or 1 Invert the values of 0 and 1. ie. "Disabled" = 1 and "Enabled" = 0.
enabled (string) Alternate text to replace "Enabled"
disabled (string) Alternate text to replace "Disabled"

The parameter to change the text to YES/NO

'redirection_status' => array ( 'title' => 'Status', 'type' => 'boolean',
'data' => 'int', 'width' => 'auto', 'help' => '', 'readParms' => array (), 'writeParms' => 'label=yesno',
'class' => 'left', 'thclass' => 'left',),

Supported addons directly by core on 13 Aug 2018

the list of supported addons from plugin handler -[...]

the list of supported addons from plugin handler Official info:

'e_meta', /* is not deprecated anymore */
'e_latest', /* @deprecated - see e_dashboard */
'e_status', /* @deprecated - see e_dashboard */
'e_dashboard', // Admin Front-Page addon.
// 'e_userprofile', @deprecated @see e_user
'e_header', // loaded in header prior to javascript manager.
'e_footer', // Loaded in footer prior to javascript manager.
// 'e_userinfo', @deprecated @see e_user
'e_url', // simple mod-rewrite.
'e_sitelink', // sitelinks generator.
'e_tohtml', /* @deprecated - use e_parse */
'e_library', // For third-party libraries are defined by plugins/themes.
'e_output', //hook into all pages at the end (after closing

Plugin manager on 01 Aug 2018

How to install/upgrade plugin from other plugin an[...]

How to install/upgrade plugin from other plugin and not Plugin manager. URLs for running Plugin man[...] URL for remote install plugin (example - plugin name=gsitemap:)

$url = e_ADMIN."plugin.php?mode=installed&action=install&id=gsitemap";

URL for remote upgrade plugin (example - plugin name=gsitemap:)

$url = e_ADMIN."plugin.php?mode=installed&action=upgrade&id=gsitemap";

Shortcut to generate plugin.xml via builder [folder must exists]

$url = e_ADMIN_ABS.plugin.php?build=&action=build&mode=create&newplugin=testplugin&createFiles=1&step=3

for only display [folder doesn't need to exist]:

$url = e_ADMIN_ABS.plugin.php?build=&action=build&mode=create&newplugin=testplugin&step=3

e_url.php [part n.3] on 30 Jul 2018

How to create SEF-URL with setting in e_url.php fo[...]

Answer: easy Original url looked like this:
<a href="">
Setting in e_url.php looks like this (we create e_url.php settings with minimalize rewrittiing on mind)
$config['content'] = array(
    'alias'    => '{alias}',
		'regex'    => '^{alias}/(.*)/(.*)',
		'sef'      => '{alias}/{content_sef}/{content_query}',
		'redirect' => 'e107_plugins/content/content.php$2'
We already added sef-url value to shorcodes by the way. Everything what is needed:
$row['content_sef'] = eHelper::title2sef($row['content_heading'],'dashl');
$row['content_query'] = "?cat.".$row['content_id'];
$url = e107::url("content", "content", $row, "full");
This will be used for any old url, with parameter ?author, ?content etc. So manual work starts. But there is no hurry because thanks using legacy ulrs as canonical, there is not double content. This solution is already prepared for using custom SEF-URL without needind add new fields to database. And to have this topic complet: e_SELF should be replaced by e_REQUEST_SELF e_BASE should be replaced by e_HTTP Example for breadcrumbs: Before:
for($i=0;$i<count($arr[$id]);$i  ){   
	$crumb .= "<a href='".e_PLUGIN."content/content.php?cat.".$arr[$id][$i]."'>".$arr[$id][$i 1]."</a> > ";
	$i  ;
Change to SEF-URL:
      $row['content_sef'] = eHelper::title2sef($arr[$id][$i+1],'dashl');
      $row['content_query'] = "?cat.".$arr[$id][$i];
      $url = e107::url("content", "content", $row, "full"); 
      $crumb .= "<a href='".$url."'>".$arr[$id][$i+1]."</a> > ";

e_url.php [part n.2] on 16 Jul 2018

building SEF-URL system for content plugin - 2. pa[...]

This part is about changes in old plugin and testing e_url.php built in 1. part

3. To solve how value of SEF-URL will be managed (generated, new field etc)

I decided to use generated field to avoid changing table structure. There is option to use custom field but I am not familiar with this part of content plugin, so the easiest way is probably the best.

To get sef-url: (I used the field 'content_sef' in e_url.php, so this determine key name)

$row['content_sef'] = eHelper::title2sef($row['content_heading'],'dashl');

Where to use it? Most of code is generated in old shortcodes, so I just add it to shortcodes that uses $row as global variable and return url in any format. If there are other places, I will find them during replacing url creation new way.

This way data are prepared for using SEF-URL.

4. To solve problem of double content (in case that both version are working together)

I am not able to replace all urls at once, so there will be old urls together with new ones. To avoid problem with double content I decided to use old urls as canonical.

Simple solution:
if(defined("e_URL_LEGACY")) {

   if (strpos(e_URL_LEGACY, 'content.php') !== false)     {
    define("e_PAGE", 'content.php');
   elseif (strpos(e_URL_LEGACY, 'content_manager.php') !== false)     {
     define("e_PAGE", 'content_manager.php');
	 if (substr(e_PAGE, 0, 7) == 'content')  {
	   $contentcanonicalurl = SITEURL.e_URL_LEGACY;
	   $debugtext = "Canonical URL from content plugin:  " . $contentcanonicalurl . "<br>";


I use JM Canonical plugin, so I can use it's debug mode:


But what if I want to use SEF-URL as canonical or use custom urls in future with JM Canonical plugin?

this works only with JM Canonical plugin:

Good question: Let this be managed by JM Canonical plugin or let JMC to ignore everything on content pages?

At least for manual canonical urls:

if (substr(e_PAGE, 0, 7) == 'content')  {
	   $canonicalurl = '';
	   $request_url = $tp->toDB(e_REQUEST_URL);
	   if($sql->retrieve('canonical_request_urls', 'canonical_id', "WHERE canru_url = '" . $request_url . "' LIMIT 1", true, true)) {
			// do nothing, JM Canonical plugin does rest
		 else { 
	   		$canonicalurl = SITEURL.e_URL_LEGACY;
	   $debugtext = "Canonical URL from content plugin:  " . $canonicalurl . "<br>";

Related urls will use legacy urls for now.

e_url.php [part n.1] on 15 Jul 2018

How I try to use e_url.php on maybe most complicat[...]

How to create search friendly urls for content plugin.
Why? It's easier this way to understa[...]

Official documentation:

It provides a simple way to add mod-rewrite redirects to your plugin's page, without having to edit the .htaccess file. To create search-engine-friendly URLs which utilize this add-on, please see the e107::url() method.

class myplugin_url  
	function config() 
		$config = array();
		$config[] = array(
			'regex'			=> '^myplugref-(.*)/?$',
			'redirect'		=> 'e107_plugins/myplugin/ref.php?ref=$1',
		return $config;

Using: e107::url('other',$row);
where $row is array of values needed to generate correct SEF-URL. If they are missing, SEF-URL is not used.

Content plugin

Why I use content plugin? Because it is written old way where everything is set by urls parameters.

What simple rewriting means with old plugin?
1. To set correct rewrite rules in meaning that if you use them manually, correct content will be displayed
2. To fix problems before actual changing used urls (changing related path to absolute)
3. To solve how value of SEF-URL will be managed (generated, new field etc)
4. To solve problem of double content (in case that both version are working together)
5. Replace old ulrs with e107::url();

1. To set correct rewrite rules

It means to analyze how legacy urls work. In fact old urls were created with more logic and they had more understandable rules than new plugins have now.

e_PAGE is filled
e_QUERY is filled
as soon as you add e_url.php, e_LEGACY _URL is filled too
: now if you use SEF-URL, e_PAGE is not defined. There is no rule for this.

e_LEGACY_URL is in fact value you have set in 'redirect' field.

Now, what values can e_PAGE to have in content plugin? Only content.php and content_manager.php

All others urls are set by e_QUERY (categories, authors, comments etc), so everything can be done by simple settings:

After you know (or you still quess) how it should work, create content_url class in e_url.php file
(you need to run Plugin scan after adding it)

class content_url
	function config()
		$config = array();
    $config['content_manager'] = array(
		'regex'    => '^content_manager/(.*)',
		'sef'      => 'content_manager/{content_query}',
		'redirect' => 'e107_plugins/content/content_manager.php$1'
    $config['content'] = array(
    'alias'         => '{alias}',
		'regex'    => '^{alias}/(.*)/(.*)',
		'sef'      => '{alias}/{content_sef}/{content_query}',
		'redirect' => 'e107_plugins/content/content.php$2'
    $config['content-temp'] = array(
    'alias'         => '{alias}',
		'regex'    => '^{alias}/(.*)',
		'sef'      => '{alias}/{content_query}',
		'redirect' => 'e107_plugins/content/content.php$1'
    $config['index'] = array(
    'alias'         => '{alias}',
		'regex'    => '^{alias}\/?$',
		'sef'      => '{alias}',
		'redirect' => 'e107_plugins/content/content.php'
  return $config;

- in fact you don't need pretty urls for content manager, because it's accessible only for manager classes. But it's easier this way (to do everything, not just part of content)
- because the same reason content manager uses simplier version - no alias, no sef version
- content-temp version is temporalily solution before adding SEF-URL field
- {alias} is used for posibility to used different word than content in url root (f.e. knowledge_base). On multilang site it can be different for each language.

Where to set aliases:

2. To fix problems before actual changing used urls

* replace

* replace e_PLUGIN with e_PLUGIN_ABS for all images and inserted urls. Do this one by one, where you notice wrong url. Replace in bulk could cause more issues that fix.

<a href='".e_PLUGIN  -  to <a href='".e_PLUGIN_ABS

* replace e_SELF with e_HTTP

* check all using of e_PAGE - with SEF-URL is not filled anymore.

This could be fixed very easy in e_meta.php and now e_PAGE is filled as should be:

if(defined("e_URL_LEGACY")) { 
   if (strpos(e_URL_LEGACY, 'content.php') !== false)     {
    define("e_PAGE", 'content.php');
   elseif (strpos(e_URL_LEGACY, 'content_manager.php') !== false)     {
     define("e_PAGE", 'content_manager.php');

you can now manually check your future urls:


So in this point rewriting works, now it's needed to solve the rest.

e_bb.php Adding BB codes to a Plugin on 13 Jul 2018

How to add custom bbcode to your e107 plugin

This is copy of old e107 wiki article with little updates for new version (paths and so).
Real examp[...] Adding bbcode to your e107 plugin is as simple as including a .bb file in your plugin folder. eg. mycode.bb (See e107_core/bbcodesfor sample files). If you want to include a single tag bb code (ie [hr]) then you need to add a _ before the bbcode name (ie _hr.bb).

Any bbcodes added in a plugin are available system-wide.

There are two parameters passed to a bbcode:

$parm is any text appearing after the '=' within the opening tag.
$code_text is the text appearing between the opening and closing bbcode tags.
The bbcode must return the HTML required to execute the task - this may take anything from a line or two up to tens or even hundreds of lines of code.

All the normal coding features, such as global variables, including files and the like, are available in the normal way.

To add a bbcode button to your textarea you need to create an e_bb.php file in your plugin folder. Here is an example of such a file:


$bb['name']: unique name. (if a .bb file is used it should match.)
$bb['onclick']: defaults to the 'addhelp' function. leave blank for simple text insertion or use 'expandit' for popups.
$bb['onclick_var']: var sent to onclick function. eg. you could send the container ID of the div to expand if expandit is used for the $bb['onclick'] parameter.
$bb['icon']: path to the button.
$bb['helptext']: the help text to display on mouseover.
$bb['function']: optional function to be called at time of loading.
$bb['function_var']: optional vars to be sent to the function. eg. for the example above the following would be executed: myFunction($myfunction_vars);

Note: To be sure that your bbcode is registered in e107, check the Preference Viewer in admin -> database and look for your file in the pref bbcode_list.

If it is not shown, run the Plugin Scan & View in admin -> database.


e_bb.php extension is not listed in supported extension for version 2 - reason for red checkbox

New 13.7.2018 :
e_bb.php is now supported addon in scan plugin directory

e_frontpage.php on 30 Nov 1999

add your plugin to Frontpage settings

To add your plugin page to Frontpage options:


You should know already what is Frontpage and how to use it.


Create file e_frontpage.php in your plugin folder (see _blank plugin for example).

Bellow is real example from content plugin:

class name = plugin name "_frontpage";

Note: with new plugin you should use new way how to load language strings.

if (!defined('e107_INIT')) { exit; }


class content_frontpage // include plugin-folder in the name.
	// simple
	function config()
	  $frontPage = array();
		$frontPage['title'] = CONT_FP_3;
		$frontPage['page'] = 'e107_plugins/content/content.php';		
		return $frontPage;

This is easy and you can find examples in other plugins too. Just look for e_frontpage.php file.


But content plugin separates content to sections and you maybe want to have possibility to set different sections for different userclasses.

class content_frontpage
	function config()
		$frontPage = array();
		$frontPage['title'] = CONT_FP_3;
		$frontPage['page'][0] = array(
			'page' => 'e107_plugins/content/content.php',
			'title' => CONT_FP_2
		if ($maincat = e107::getDb()->retrieve("pcontent", "content_id, content_heading", 
		" WHERE content_parent='0'", true))
			$i = 1;
			foreach($maincat as $row)
				$row['url_content_id'] = $row['content_id'];
				$frontPage['page'][$i] = array(
					'page' => $PLUGINS_DIRECTORY . 'content/content.php?recent.' . $row['content_id'],
					'title' => CONT_FP_1 . ': ' . $row['content_heading']
				if ($subpages = e107::getDb()->retrieve("pcontent", "content_id, content_heading", 
				" WHERE LEFT(content_parent,1) = '" . $row['content_id'] . "' ORDER BY content_heading", TRUE))
					foreach($subpages as $row2)
						$frontPage['page'][$i] = array(
							'page' => 'e107_plugins/content/content.php?content.' . $row2['content_id'],
							'title' =>  ' - ' . $row['content_heading'] . ' - ' . $row2['content_heading']

		return $frontPage;


Known issues with Frontpage:

Fatal error: require_once(): Failed opening required '../../class2.php'


Need to be changed to:


Comparing with version 1.0.4:

- old ways with arrays is not supported, you need to rewrite this file to new standards
- there is change in behaviour in version 2 - one plugin can have just one line in Frontpage . This is not possible now (or yet):



* For layout / look is FRONTPAGE layout applied (if it's used), not defined layout for original URL.
* you can set different frontpage for any userclass,
* you can set after login page this way too different for userclasses
* you can extend frontpage of core plugins this way too - just create your own plugin and create options with core tables (for example download categories)

Other links

Follow us