J1.5

Difference between revisions of "Creating a content plugin"

From Joomla! Documentation

m (→‎Quick tips: removing categories, shutting down namespace)
 
(28 intermediate revisions by 16 users not shown)
Line 1: Line 1:
{{review}}
+
{{version|1.5}}
[[Category:Development]]
 
[[Category:Plugins]]
 
 
==Description==
 
==Description==
 
There are lots of abilities of the use of a Content Plugin. They all have to do with the display of your content and so your articles. You will need at least two files for this Plugin. An XML file and a PHP file. Because there are so many differences between two Content Plugins in the PHP file, two examples of them will be explained in this document. Also a part about internationalization (with INI files) is added. And last but not least: the Joomla! Core Content Plugin coding examples and the quick tips.
 
There are lots of abilities of the use of a Content Plugin. They all have to do with the display of your content and so your articles. You will need at least two files for this Plugin. An XML file and a PHP file. Because there are so many differences between two Content Plugins in the PHP file, two examples of them will be explained in this document. Also a part about internationalization (with INI files) is added. And last but not least: the Joomla! Core Content Plugin coding examples and the quick tips.
Line 9: Line 7:
 
Always start off with the XML tag and define that it is written in a UTF-8 format.
 
Always start off with the XML tag and define that it is written in a UTF-8 format.
 
<source lang="xml"><?xml version="1.0" encoding="utf-8"?>
 
<source lang="xml"><?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE install PUBLIC
+
<!DOCTYPE install
   "-//Joomla! 1.5//DTD plugin 1.0//EN" "http://dev.joomla.org/xml/1.5/plugin-install.dtd"></source>
+
   PUBLIC "-//Joomla! 1.5//DTD plugin 1.0//EN" "http://www.joomla.org/xml/dtd/1.5/plugin-install.dtd">
 +
</source>
 +
 
 
To define that the plugin has to be a content plugin, add this line:
 
To define that the plugin has to be a content plugin, add this line:
 
<source lang="xml"><install version="1.5" type="plugin" group="content"></source>
 
<source lang="xml"><install version="1.5" type="plugin" group="content"></source>
Line 29: Line 29:
 
And now include your PHP file to the Content Plugin. The name of this file should be the same as the name of this XML file. Put this name also behind the plugin="" part.  
 
And now include your PHP file to the Content Plugin. The name of this file should be the same as the name of this XML file. Put this name also behind the plugin="" part.  
  
You could also add more files for your plugin, for example an image. Just add another row between <files> and </file>, and then place the file between <filename> tags.
+
You could also add more files for your plugin, for example an image. Just add another row between <files> and </files>, and then place the file between <filename> tags.
 
<source lang="xml">
 
<source lang="xml">
 
<files>
 
<files>
Line 35: Line 35:
 
</files></source>
 
</files></source>
  
For the internationalization, we will use language files. This is not required, but people from other countries will love it they can easily translate your plugin to their own language. Plugin language files are always installed in administrator/languages/xx-XX/ where xx-XX is the code for a language already installed in Joomla.
+
Some files, like .js or .css, are not recognized and will cause an error when you try to install the plugin. For these, simply create a new folder in the plugin directory, then add the files to the folder. Then add a line for the folder in the <files> tags. Of course, .js and .css files might be better managed better as part of the template, but if these are plugin specific then they could go here.
 +
 
 +
<source lang="xml">
 +
<files>
 +
  <folder>scripts</folder>
 +
  <folder>css</folder>
 +
</files></source>
 +
 
 +
For the internationalization, we will use language files. This is not required, but people from other countries will love it if they can easily translate your plugin to their own language. Plugin language files are always installed in administrator/languages/xx-XX/ where xx-XX is the code for a language already installed in Joomla.
 
The language tags can be found here: [http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes] (use the ISO 639-1 column) and here: [http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements]
 
The language tags can be found here: [http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes] (use the ISO 639-1 column) and here: [http://en.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements]
 
<source lang="xml">
 
<source lang="xml">
 
<languages>
 
<languages>
   <language tag="en-GB">en-GB.plg_content_nameofplugin.INI</language>
+
   <language tag="en-GB">en-GB.plg_content_nameofplugin.ini</language>
 
</languages></source>
 
</languages></source>
 
Optionally, you could add some parameters to the Plugin. These will look like this:
 
Optionally, you could add some parameters to the Plugin. These will look like this:
Line 47: Line 55:
 
</params></source>
 
</params></source>
 
*'''Param name:''' The name of the parameter. You will need this when creating the PHP file.
 
*'''Param name:''' The name of the parameter. You will need this when creating the PHP file.
*'''Param type:''' You could choose between several types of parameters. Look at this document to learn something about the different types: [http://docs.joomla.org/Using_the_core_parameter_types]  
+
*'''Param type:''' You could choose between several types of parameters. Look at this document to learn something about the different types: [[Using the core parameter types]]
 
*'''Param default:''' The default setting for this parameter.
 
*'''Param default:''' The default setting for this parameter.
 
*'''Param label:''' The name of this parameter displayed in the edit screen of this Plugin in the Plugin Manager.
 
*'''Param label:''' The name of this parameter displayed in the edit screen of this Plugin in the Plugin Manager.
Line 57: Line 65:
 
<source lang="xml"></install></source>
 
<source lang="xml"></install></source>
  
==PHP file - Example 1==
+
==PHP file==
Example 1 is about the Content Plugin vote. The PHP file will be displayed here, with comments what every function or part does.
+
Start your PHP file with the general licensing and author information about your content plugin.
<source lang="PHP">
 
<?php
 
  
//First start with some information about the Content Plugin, its author and probably some other information
+
<source lang="PHP"><?php
 
/**
 
/**
* @version $Id: vote.php 9764 2007-12-30 07:48:11Z ircmaxell $
+
* @version $Id: nameofplugin.php revision date lasteditedby $
* @package Joomla
+
* @package Joomla
* @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
+
* @subpackage Content
* @license GNU/GPL, see LICENSE.php
+
* @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
* Joomla! is free software. This version may have been modified pursuant
+
* @license GNU/GPL, see LICENSE.php
* to the GNU General Public License, and as distributed it includes or
+
* Joomla! is free software. This version may have been modified pursuant
* is derivative of works licensed under the GNU General Public License or
+
* to the GNU General Public License, and as distributed it includes or
* other free or open source software licenses.
+
* is derivative of works licensed under the GNU General Public License or
* See COPYRIGHT.php for copyright notices and details.
+
* other free or open source software licenses.
*/
+
* See COPYRIGHT.php for copyright notices and details.
 
+
*/ </source>
//You can not directly access the file when you put this code at the beginning:
+
 +
Next, always put the following code in any PHP file:
 +
<source lang="PHP">
 
// no direct access
 
// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );
+
defined( '_JEXEC' ) or die( 'Restricted access' );</source>
 
+
This prevents people from directly accessing this PHP file.
//Now set the registerEvent. The action will start before the content is opened.
 
//In plgContentVote you should replace Vote by the name of your own Plugin.
 
$mainframe->registerEvent( 'onBeforeDisplayContent', 'plgContentVote' );
 
 
 
//Here the real function starts.
 
function plgContentVote( &$row, &$params, $page=0 )
 
{
 
  
//Set the JURI
+
After that, you should import the general plugin file of Joomla!'s library
$uri = & JFactory::getURI();
+
<source lang="PHP">jimport( 'joomla.plugin.plugin' );</source>
  
$id = $row->id;
+
To indicate that you're writing a Content plugin, add the following code.
 +
<source lang="PHP">class plgContentNameofplugin extends JPlugin {</source>
 +
Please note the use of capital letters. You should replace Nameofplugin by the name of your own plugin.
  
//$html is made empty
+
Now, it's time to construct the plugin:
$html = '';
+
<source lang="PHP">/**
 
+
* Constructor
//Get the rating_count and the parameters from the XML file
+
*
if (isset($row->rating_count) && $params->get( 'show_vote' ) && !$params->get( 'popup' ))
+
* For php4 compatability we must not use the __constructor as a constructor for plugins
 +
* because func_get_args ( void ) returns a copy of all passed arguments NOT references.
 +
* This causes problems with cross-referencing necessary for the observer design pattern.
 +
*
 +
* @param object $subject The object to observe
 +
* @param object $params  The object that holds the plugin parameters
 +
* @since 1.5
 +
*/
 +
function plgContentNameofplugin( &$subject, $params )
 
{
 
{
 +
parent::__construct( $subject, $params );
 +
}</source>
  
//Load the language file
+
You should choose now at which moment the plugin should be rendered. You can choose from the following:
JPlugin::loadLanguage( 'plg_content_vote' );
 
  
//Add the general HTML output
+
* onBeforeContentSave : This is an event that is called right before the content is saved into the database.
$html .= '<form method="post" action="' . $uri->toString( ) . '">';
+
* onAfterContentSave : This is an event that is called after the content is saved into the database.
$img = '';
+
* onPrepareContent : This is the first stage in preparing content for output and is the most common point for content orientated plugins to do their work.
 +
* onAfterDisplayTitle : This is a request for information that should be placed between the content title and the content body.
 +
* onBeforeDisplayContent : This is a request for information that should be placed immediately before the generated content.
 +
* onAfterDisplayContent : This is a request for information that should be placed immediately after the generated content.
  
//Look for images in template if available
+
More information on which type you should use for your plugin, including several examples, can be found here: [[Plugin events/Content]]
$starImageOn = JHTML::_('image.site', 'rating_star.png', '/images/M_images/' );
 
$starImageOff = JHTML::_('image.site',  'rating_star_blank.png', '/images/M_images/' );
 
  
//Show the 'full' star images when the rate number is higher then 0
+
===onBeforeContentSave===
for ($i=0; $i < $row->rating; $i++) {
+
Use the following code:
$img .= $starImageOn;
+
<source lang="PHP"> function onBeforeContentSave( &$article, $isNew )
}
+
{
 +
global $mainframe;
 +
//add your plugin codes here
 +
return true;
 +
}</source>
 +
The parameters article and isNew should contain the following:
 +
* article : A reference to the JTableContent object that is being saved which holds the article data.
 +
* isNew : A boolean which is set to true if the content is about to be created.
  
//Show the the 'empty' star images when the rate number is less then 5
+
===onAfterContentSave===
for ($i=$row->rating; $i < 5; $i++) {
+
Use the following code:
$img .= $starImageOff;
+
<source lang="PHP"> function onAfterContentSave( &$article, $isNew )
}
+
{
 +
global $mainframe;
 +
//add your plugin codes here
 +
return true;
 +
}</source>
 +
The parameters article and isNew should contain the following:
 +
* article : A reference to the JTableContent object that was saved which holds the article data.
 +
* isNew : A boolean which is set to true if the content was created.
  
//HTML output
+
===onPrepareContent===
$html .= '<span class="content_rating">';
+
Use the following code:
$html .= JText::_( 'User Rating' ) .':'. $img .'&nbsp;/&nbsp;';
+
<source lang="PHP"> function onPrepareContent( &$article, &$params, $limitstart )
$html .= intval( $row->rating_count );
+
{
$html .= "</span>\n<br />\n";
+
global $mainframe;
 +
//add your plugin codes here
 +
//no return value
 +
}</source>
 +
The parameters article, params and limitstart should contain the following:
 +
* article : A reference to the article that is being rendered by the view.
 +
* params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
 +
* limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.
  
//Get params
+
===onAfterDisplayTitle===
if (!$params->get( 'intro_only' ))
+
Use the following code:
{
+
<source lang="PHP"> function onAfterDisplayTitle( &$article, &$params, $limitstart )
 +
{
 +
global $mainframe;
 +
//add your plugin codes here
 +
return '';
 +
//return a string value. Returned value from this event will be displayed in a placeholder.
 +
                // Most templates display this placeholder after the article separator.
 +
}</source>
 +
The parameters article, params and limitstart should contain the following:
 +
* article : A reference to the article that is being rendered by the view.
 +
* params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
 +
* limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.
 +
 +
===onBeforeDisplayContent===
 +
Use the following code:
 +
<source lang="PHP"> function onBeforeDisplayContent( &$article, &$params, $limitstart )
 +
{
 +
global $mainframe;
 +
//add your plugin codes here
 +
return '';
 +
//return a string value. Returned value from this event will be displayed in a placeholder.
 +
                // Most templates display this placeholder after the article separator.
 +
}</source>
 +
 +
The parameters article, params and limitstart should contain the following:
 +
* article : A reference to the article that is being rendered by the view.
 +
* params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
 +
* limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.
  
//HTML output; set the display of the images
+
===onAfterDisplayContent===
$html .= '<span class="content_vote">';
+
Use the following code:
$html .= JText::_( 'Poor' );
+
<source lang="PHP"> function onAfterDisplayContent( &$article, &$params, $limitstart )
$html .= '<input type="radio" alt="vote 1 star" name="user_rating" value="1" />';
+
{
$html .= '<input type="radio" alt="vote 2 star" name="user_rating" value="2" />';
+
global $mainframe;
$html .= '<input type="radio" alt="vote 3 star" name="user_rating" value="3" />';
+
//add your plugin codes here
$html .= '<input type="radio" alt="vote 4 star" name="user_rating" value="4" />';
+
return '';
$html .= '<input type="radio" alt="vote 5 star" name="user_rating" value="5" checked="checked" />';
+
//return a string value. Returned value from this event will be displayed in a placeholder.  
$html .= JText::_( 'Best' );
+
                // Most templates display this placeholder after the article separator.
$html .= '&nbsp;<input class="button" type="submit" name="submit_vote" value="'. JText::_( 'Rate' ) .'" />';
+
}</source>
$html .= '<input type="hidden" name="task" value="vote" />';
+
$html .= '<input type="hidden" name="option" value="com_content" />';
+
The parameters article, params and limitstart should contain the following:
$html .= '<input type="hidden" name="cid" value="'. $id .'" />';
+
* article : A reference to the article that is being rendered by the view.
$html .= '<input type="hidden" name="url" value="'.  $uri->toString( ) .'" />';
+
* params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
$html .= '</span>';
+
* limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.
}
 
//HTML output; close the <form> tag
 
$html .= '</form>';
 
}
 
//Return HTML output
 
return $html;
 
}</source>
 
  
==PHP file - Example 2==
+
==PHP file - Example==
Example 2 is about the Content Plugin load module. It is a plugin made for displaying modules within the articles. The PHP file will be displayed here, with comments what every function or part does.  
+
This example PHP file is about the Content Plugin load module. It is a plugin made for displaying modules within the articles.  
 +
The commented PHP file used in this example is the file which will be included in Joomla! 1.6. This has been done because the content plugin files in Joomla! 1.5 are not refactored yet to the new standards.  
 
<source lang="PHP">
 
<source lang="PHP">
 
<?php
 
<?php
//First start with some information about the Content Plugin, its author and probably some other information
+
// The general information at the top of each file
 
/**
 
/**
* @version $Id: loadmodule.php 9764 2007-12-30 07:48:11Z ircmaxell $
+
* @version $Id$
 
* @package Joomla
 
* @package Joomla
* @copyright Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
+
* @copyright Copyright (C) 2005 - 2009 Open Source Matters, Inc. All rights reserved.
* @license GNU/GPL, see LICENSE.php
+
* @license GNU General Public License, see LICENSE.php
* Joomla! is free software. This version may have been modified pursuant
 
* to the GNU General Public License, and as distributed it includes or
 
* is derivative of works licensed under the GNU General Public License or
 
* other free or open source software licenses.
 
* See COPYRIGHT.php for copyright notices and details.
 
 
*/
 
*/
//You can not directly access the file when you put this code at the beginning:
+
 
// no direct access
+
// No direct access allowed to this file
 
defined( '_JEXEC' ) or die( 'Restricted access' );
 
defined( '_JEXEC' ) or die( 'Restricted access' );
  
//Now set the registerEvent. The action will start before the content is opened.
+
// Import Joomla! Plugin library file
//In plgContentVote you should replace Vote by the name of your own Plugin.
+
jimport('joomla.plugin.plugin');
$mainframe->registerEvent( 'onPrepareContent', 'plgContentLoadModule' );
 
  
//The real function starts here
+
//The Content plugin Loadmodule
function plgContentLoadModule( &$row, &$params, $page=0 )
+
class plgContentLoadmodule extends JPlugin
 
{
 
{
//Access the database
+
/**
$db =& JFactory::getDBO();
+
* Plugin that loads module positions within content
//Check whether the bot should process or not
+
*/
if ( JString::strpos( $row->text, 'loadposition' ) === false ) {
+
// onPrepareContent, meaning the plugin is rendered at the first stage in preparing content for output
return true;
+
public function onPrepareContent( &$row, &$params, $page=0 )
}
+
{
 +
                // A database connection is created
 +
$db = JFactory::getDBO();
 +
// simple performance check to determine whether bot should process further
 +
if ( JString::strpos( $row->text, 'loadposition' ) === false ) {
 +
return true;
 +
}
 +
 
 +
// expression to search for
 +
$regex = '/{loadposition\s*.*?}/i';
  
//Get plugin info
+
// check whether plugin has been unpublished
$plugin =& JPluginHelper::getPlugin('content', 'loadmodule');
+
if ( !$this->params->get( 'enabled', 1 ) ) {
 +
$row->text = preg_replace( $regex, '', $row->text );
 +
return true;
 +
}
  
//Search for this tag in the content
+
// find all instances of plugin and put in $matches
$regex = '/{loadposition\s*.*?}/i';
+
preg_match_all( $regex, $row->text, $matches );
  
//Access the parameters
+
// Number of plugins
$pluginParams = new JParameter( $plugin->params );
+
$count = count( $matches[0] );
  
//Check whether plugin has been unpublished
+
// plugin only processes if there are any instances of the plugin in the text
if ( !$pluginParams->get( 'enabled', 1 ) ) {
+
if ( $count ) {
$row->text = preg_replace( $regex, '', $row->text );
+
// Get plugin parameters
return true;
+
$style = $this->params->def( 'style', -2 );
 +
$this->_process( $row, $matches, $count, $regex, $style );
 +
}
 +
// No return value
 
}
 
}
 +
// The proccessing function
 +
protected function _process( &$row, &$matches, $count, $regex, $style )
 +
{
 +
for ( $i=0; $i < $count; $i++ )
 +
{
 +
$load = str_replace( 'loadposition', '', $matches[0][$i] );
 +
$load = str_replace( '{', '', $load );
 +
$load = str_replace( '}', '', $load );
 +
$load = trim( $load );
  
//Find all instances of plugin and put in $matches
+
$modules = $this->_load( $load, $style );
preg_match_all( $regex, $row->text, $matches );
+
$row->text = preg_replace( '{'. $matches[0][$i] .'}', $modules, $row->text );
 +
}
  
//Number of plugins
+
  // removes tags without matching module positions
$count = count( $matches[0] );
+
$row->text = preg_replace( $regex, '', $row->text );
 
 
//Plugin only processes if there are any instances of the plugin in the text
 
if ( $count ) {
 
//Get plugin parameters
 
$style = $pluginParams->def( 'style', -2 );
 
 
 
plgContentProcessPositions( $row, $matches, $count, $regex, $style );
 
 
}
 
}
}
+
// The function who takes care for the 'completing' of the plugins' actions : loading the module(s)
//Function to process the posistions in the content
+
protected function _load( $position, $style=-2 )
function plgContentProcessPositions ( &$row, &$matches, $count, $regex, $style )
 
{
 
for ( $i=0; $i < $count; $i++ )
 
 
{
 
{
 +
$document = &JFactory::getDocument();
 +
$renderer = $document->loadRenderer('module');
 +
$params = array('style'=>$style);
  
//Get the correct output for $load
+
$contents = '';
$load = str_replace( 'loadposition', '', $matches[0][$i] );
+
foreach (JModuleHelper::getModules($position) as $mod)  {
$load = str_replace( '{', '', $load );
+
$contents .= $renderer->render($mod, $params);
$load = str_replace( '}', '', $load );
+
}
$load = trim( $load );
+
return $contents;
 
 
//Load position
 
$modules = plgContentLoadPosition( $load, $style );
 
$row->text = preg_replace( '{'. $matches[0][$i] .'}', $modules, $row->text );
 
}
 
 
 
//Remove tags without matching module positions
 
$row->text = preg_replace( $regex, '', $row->text );
 
}
 
 
 
//Function to load the module in the content
 
function plgContentLoadPosition( $position, $style=-2 )
 
{
 
 
 
//Get document
 
$document = &JFactory::getDocument();
 
 
 
//Load module
 
$renderer = $document->loadRenderer('module');
 
 
 
//Load the parameter
 
$params = array('style'=>$style);
 
 
 
$contents = '';
 
 
 
foreach (JModuleHelper::getModules($position) as $mod)  {
 
$contents .= $renderer->render($mod, $params);
 
 
}
 
}
 
//Return content with loaded modules
 
return $contents;
 
 
}
 
}
 
</source>
 
</source>
  
 
==INI file(s)==
 
==INI file(s)==
For internationalization it is good to use the INI files. You can add to the language file everyting which outputs text to the user, in this order:  
+
For internationalization it is good to use the INI files. You can add to the language file everything which outputs text to the user, in this order:  
 
*XML description tag  
 
*XML description tag  
 
*XML label and description attributes from parameters  
 
*XML label and description attributes from parameters  
*JText::_( 'string' ) used by the plugin  
+
*JText::_( 'string' ) used by the plugin
 +
 
 +
You should create two files: One for the backend and one for the front end. The naming should match the path of the extension. For example, if we were creating a content plugin named 'example' and it is installed at plugins/content/example, then our files should be named:
 +
*en-US.plg_content_example.ini (Frontend)
 +
*en-US.plg_content_example.sys.ini (Backend)
 +
 
 +
 
Start your INI file with something like this:  
 
Start your INI file with something like this:  
 
<source lang="INI"># $Id: en-GB.plg_content_nameofplugin.ini
 
<source lang="INI"># $Id: en-GB.plg_content_nameofplugin.ini
Line 274: Line 317:
 
Of course, you could also add other information, like the author.  
 
Of course, you could also add other information, like the author.  
  
For example, this parameter:  
+
Joomla 1.6+ uses the ; at the start of the line, rather than the #.
 +
 
 +
Backend Example:  
 
<source lang="XML">
 
<source lang="XML">
<param name="mode" type="list" default="1" label="Mode" description="Select how the emails will be displayed">
+
<param name="mode" type="list" default="1" label="PLG_CONTENT_EXAMPLE_MODE" description="PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED">
   <option value="0">Nonlinkable Text</option>
+
   <option value="0">PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT</option>
   <option value="1">As linkable mailto address</option>
+
   <option value="1">PLG_CONTENT_EXAMPLE_LINKABLE_TEXT</option>
 
</param></source>
 
</param></source>
Will cause the following in the INI file:  
+
 
 +
The localized strings are translated in the ini file:
 +
<source lang="INI">
 +
PLG_CONTENT_EXAMPLE_MODE=Mode
 +
PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED=Select how the e-mails will be displayed
 +
PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT=Nonlinkable text
 +
PLG_CONTENT_EXAMPLE_LINKABLE_TEXT=As linkable mailto address
 +
</source>
 +
 
 +
Best practice dictates that LOCALIZED_TAGS are all upper case, no spaces, and begin with the same name as the extension - to avoid interfering with other strings.
 +
 
 +
The localized tags can then be translated into multiple languages.When you want to make your Content Plugin available in more languages, first add them to the <languages> tag in the XML file. Then create the same INI file, and change the part after the =, for example the dutch version would be:  
 
<source lang="INI">
 
<source lang="INI">
MODE=Mode
+
PLG_CONTENT_EXAMPLE_MODE=Modus
SELECT HOW THE EMAILS WILL BE DISPLAYED=Select how the e-mails will be displayed
+
PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED=Selecteer hoe de e-mails worden weergegeven
NONLINKABLE TEXT=Nonlinkable text
+
PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT=Niet-linkbare tekst
AS LINKABLE MAILTO ADDRESS=As linkable mailto address
+
PLG_CONTENT_EXAMPLE_LINKABLE_TEXT=Als een linkbaar mailto adres
 
</source>
 
</source>
The file looks repetitive, but will be very useful for translaters.
 
  
When you want to make your Content Plugin available in more languages, first add them to the <languages> tag in the XML file. Then create the same INI file, and change the part after the =, for example the dutch version would be:  
+
Frontend Example:
 +
On Joomla 1.6+ you must create a separate file for the front end - as described above. For example:
 +
 
 
<source lang="INI">
 
<source lang="INI">
MODE=Modus
+
PLG_CONTENT_EXAMPLE_LINKNAME="The Name of the Link Goes Here!"
SELECT HOW THE EMAILS WILL BE DISPLAYED=Selecteer hoe de e-mails worden weergegeven
+
</source>
NONLINKABLE TEXT=Niet-linkbare tekst
+
 
AS LINKABLE MAILTO ADDRESS=Als een linkbaar mailto adres
+
In the plugin's php file, you must load the language file:
 +
<source lang="PHP">
 +
// Load user_profile plugin language
 +
$lang = JFactory::getLanguage();
 +
$lang->load('plg_content_simpleattachment', JPATH_ADMINISTRATOR);
 +
echo JText::_('PLG_CONTENT_EXAMPLE_LINKNAME');
 +
</source>
 +
 
 +
You could also use another component or plugin's language file.  This is useful for maintaining consistent strings between a component, module, and plugin, that are part of the same package.
 +
 
 +
To load another component or plugin's language files specify it's name in the load statement and specify whether to use the site or administrator language.  For example:
 +
 
 +
<source lang="PHP">
 +
$lang->load('com_someothercomponent',JPATH_ADMINISTRATOR);
 
</source>
 
</source>
  
 
==Coding examples==
 
==Coding examples==
There are seven Joomla! Core Content Plugins. To look at them, you can learn a lot. You can see them 'working' when you go to the Back-end of your Joomla! 1.5 installation, then go to the menu 'Extensions' and select the 'Plugin Manager'. Click on the name of the Plugin to edit it; and see it working. Also watch the content and see what happens when you insert a pagebreak for example.
+
There are seven Joomla! Core Content Plugins. These are all not yet refactored to the new standards. For learning how to write good plugins, its better to look at the (refactored) files of Joomla! 1.6.
*Plugin Content - Emailcloak
+
You can see them 'working' when you go to the Back-end of your Joomla! 1.5 installation, then go to the menu 'Extensions' and select the 'Plugin Manager'. Click on the name of the Plugin to edit it; and see it working. Also watch the content and see what happens when you insert a pagebreak for example.
**\plugins\content\emailcloak.XML
 
**\plugins\congent\emailcloak.PHP
 
*Plugin Content - Example
 
**\plugins\content\example.XML
 
**\plugins\congent\example.PHP
 
*Plugin Content - Geshi
 
**\plugins\content\geshi.XML
 
**\plugins\congent\geshi.PHP
 
*Plugin Content - Load Module
 
**\plugins\content\loadmodule.XML
 
**\plugins\congent\loadmodule.PHP
 
*Plugin Content - Pagebreak
 
**\plugins\content\pagebreak.XML
 
**\plugins\congent\pagebreak.PHP
 
*Plugin Content - Page navigation
 
**\plugins\content\pagenavigation.XML
 
**\plugins\congent\pagenavigation.PHP
 
*Plugin Content - Vote
 
**\plugins\content\vote.XML
 
**\plugins\congent\vote.PHP
 
**\language\en-GB\en-GB.plg_content_vote.INI
 
  
 
==Quick tips==
 
==Quick tips==
Line 326: Line 375:
 
*Take care of the fact that the parameters in the XML file are closed correctly. When you add options for example, you need to close it with </param>.  
 
*Take care of the fact that the parameters in the XML file are closed correctly. When you add options for example, you need to close it with </param>.  
 
*It is easy to test on a localhost when you are still busy with editing your Plugin.  
 
*It is easy to test on a localhost when you are still busy with editing your Plugin.  
*When making a zip-file to test it, do not forget to make the directories for the language files. A typical zip will contain the following:  
+
*A typical zip will contain the following:  
 
**nameofplugin.XML  
 
**nameofplugin.XML  
 
**nameofplugin.PHP  
 
**nameofplugin.PHP  
**language\en-GB\en-GB.plg_content_nameofplugin.INI
+
**en-GB.plg_content_nameofplugin.ini
 +
 
 +
 
 +
 
  
== Headline text ==
+
[[Category:Archived version Joomla! 1.5|{{PAGENAME}}]]

Latest revision as of 09:20, 29 April 2013

The "J1.5" namespace is an archived namespace. This page contains information for a Joomla! version which is no longer supported. It exists only as a historical reference, it will not be improved and its content may be incomplete and/or contain broken links.

Description[edit]

There are lots of abilities of the use of a Content Plugin. They all have to do with the display of your content and so your articles. You will need at least two files for this Plugin. An XML file and a PHP file. Because there are so many differences between two Content Plugins in the PHP file, two examples of them will be explained in this document. Also a part about internationalization (with INI files) is added. And last but not least: the Joomla! Core Content Plugin coding examples and the quick tips.

XML file[edit]

The XML file is named the same as the PHP file, and is one of the two required files. Always start off with the XML tag and define that it is written in a UTF-8 format.

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE install
  PUBLIC "-//Joomla! 1.5//DTD plugin 1.0//EN" "http://www.joomla.org/xml/dtd/1.5/plugin-install.dtd">

To define that the plugin has to be a content plugin, add this line:

<install version="1.5" type="plugin" group="content">

The type will define it is a Plugin, the group defines the Plugin is in the group of Content Plugins.

After that, add some information about yourself and the Plugin, like this:

<name>Name of your Content Plugin</name>
<creationDate>Created Date</creationDate>
<author>Your name</author>
<authorEmail>Your e-mail address</authorEmail>
<authorUrl>Your website</authorUrl>
<copyright>Copyright</copyright>
<license>License, for example GNU/GPL</license>
<version>Version of the plugin</version>
<description>Description of the Plugin; showed with installation and when editing 
the Plugin in the Plugin Manager</description>

And now include your PHP file to the Content Plugin. The name of this file should be the same as the name of this XML file. Put this name also behind the plugin="" part.

You could also add more files for your plugin, for example an image. Just add another row between <files> and </files>, and then place the file between <filename> tags.

<files>
   <filename plugin="nameofplugin">nameofplugin.php</filename>
</files>

Some files, like .js or .css, are not recognized and will cause an error when you try to install the plugin. For these, simply create a new folder in the plugin directory, then add the files to the folder. Then add a line for the folder in the <files> tags. Of course, .js and .css files might be better managed better as part of the template, but if these are plugin specific then they could go here.

<files>
   <folder>scripts</folder>
   <folder>css</folder>
</files>

For the internationalization, we will use language files. This is not required, but people from other countries will love it if they can easily translate your plugin to their own language. Plugin language files are always installed in administrator/languages/xx-XX/ where xx-XX is the code for a language already installed in Joomla. The language tags can be found here: [1] (use the ISO 639-1 column) and here: [2]

<languages>
   <language tag="en-GB">en-GB.plg_content_nameofplugin.ini</language>
</languages>

Optionally, you could add some parameters to the Plugin. These will look like this:

<params>
   <param name="paramname" type="typeofparameter" default="defaultsetting" label="title" description="description"/>
</params>
  • Param name: The name of the parameter. You will need this when creating the PHP file.
  • Param type: You could choose between several types of parameters. Look at this document to learn something about the different types: Using the core parameter types
  • Param default: The default setting for this parameter.
  • Param label: The name of this parameter displayed in the edit screen of this Plugin in the Plugin Manager.
  • Param description: The text which appears as a tool tip for this parameter.

When you do not want to use parameters, add the following tag:

<params/>

And do not forget to end your XML file with the following tag:

</install>

PHP file[edit]

Start your PHP file with the general licensing and author information about your content plugin.

<?php
/**
 * @version		$Id: nameofplugin.php revision date lasteditedby $
 * @package		Joomla
 * @subpackage	Content
 * @copyright	Copyright (C) 2005 - 2008 Open Source Matters. All rights reserved.
 * @license		GNU/GPL, see LICENSE.php
 * Joomla! is free software. This version may have been modified pursuant
 * to the GNU General Public License, and as distributed it includes or
 * is derivative of works licensed under the GNU General Public License or
 * other free or open source software licenses.
 * See COPYRIGHT.php for copyright notices and details.
 */

Next, always put the following code in any PHP file:

// no direct access
defined( '_JEXEC' ) or die( 'Restricted access' );

This prevents people from directly accessing this PHP file.

After that, you should import the general plugin file of Joomla!'s library

jimport( 'joomla.plugin.plugin' );

To indicate that you're writing a Content plugin, add the following code.

class plgContentNameofplugin extends JPlugin {

Please note the use of capital letters. You should replace Nameofplugin by the name of your own plugin.

Now, it's time to construct the plugin:

/**
 * Constructor
 *
 * For php4 compatability we must not use the __constructor as a constructor for plugins
 * because func_get_args ( void ) returns a copy of all passed arguments NOT references.
 * This causes problems with cross-referencing necessary for the observer design pattern.
 *
 * @param object $subject The object to observe
 * @param object $params  The object that holds the plugin parameters
 * @since 1.5
 */
	function plgContentNameofplugin( &$subject, $params )
	{
		parent::__construct( $subject, $params );
	}

You should choose now at which moment the plugin should be rendered. You can choose from the following:

  • onBeforeContentSave : This is an event that is called right before the content is saved into the database.
  • onAfterContentSave : This is an event that is called after the content is saved into the database.
  • onPrepareContent : This is the first stage in preparing content for output and is the most common point for content orientated plugins to do their work.
  • onAfterDisplayTitle : This is a request for information that should be placed between the content title and the content body.
  • onBeforeDisplayContent : This is a request for information that should be placed immediately before the generated content.
  • onAfterDisplayContent : This is a request for information that should be placed immediately after the generated content.

More information on which type you should use for your plugin, including several examples, can be found here: Plugin events/Content

onBeforeContentSave[edit]

Use the following code:

	function onBeforeContentSave( &$article, $isNew )
	{
		global $mainframe;
		//add your plugin codes here
		return true;
	}

The parameters article and isNew should contain the following:

  • article : A reference to the JTableContent object that is being saved which holds the article data.
  • isNew : A boolean which is set to true if the content is about to be created.

onAfterContentSave[edit]

Use the following code:

	function onAfterContentSave( &$article, $isNew )
	{
		global $mainframe;
		//add your plugin codes here
		return true;
	}

The parameters article and isNew should contain the following:

  • article : A reference to the JTableContent object that was saved which holds the article data.
  • isNew : A boolean which is set to true if the content was created.

onPrepareContent[edit]

Use the following code:

	function onPrepareContent( &$article, &$params, $limitstart )
	{
		global $mainframe;
		//add your plugin codes here
		//no return value
	}

The parameters article, params and limitstart should contain the following:

  • article : A reference to the article that is being rendered by the view.
  • params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
  • limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.

onAfterDisplayTitle[edit]

Use the following code:

	function onAfterDisplayTitle( &$article, &$params, $limitstart )
	{
		global $mainframe;
		//add your plugin codes here
		return '';
		//return a string value. Returned value from this event will be displayed in a placeholder. 
                // Most templates display this placeholder after the article separator.
	}

The parameters article, params and limitstart should contain the following:

  • article : A reference to the article that is being rendered by the view.
  • params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
  • limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.

onBeforeDisplayContent[edit]

Use the following code:

	function onBeforeDisplayContent( &$article, &$params, $limitstart )
	{
		global $mainframe;
		//add your plugin codes here
		return '';
		//return a string value. Returned value from this event will be displayed in a placeholder. 
                // Most templates display this placeholder after the article separator. 
	}

The parameters article, params and limitstart should contain the following:

  • article : A reference to the article that is being rendered by the view.
  • params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
  • limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.

onAfterDisplayContent[edit]

Use the following code:

	function onAfterDisplayContent( &$article, &$params, $limitstart )
	{
		global $mainframe;
//add your plugin codes here
		return '';
		//return a string value. Returned value from this event will be displayed in a placeholder. 
                // Most templates display this placeholder after the article separator.
	}

The parameters article, params and limitstart should contain the following:

  • article : A reference to the article that is being rendered by the view.
  • params : A reference to an associative array of relevant parameters. The view determines what it considers to be relevant and passes that information along.
  • limitstart : An integer that determines the "page" of the content that is to be generated. Note that in the context of views that might not generate HTML output, a page is a reasonably abstract concept that depends on the context.

PHP file - Example[edit]

This example PHP file is about the Content Plugin load module. It is a plugin made for displaying modules within the articles. The commented PHP file used in this example is the file which will be included in Joomla! 1.6. This has been done because the content plugin files in Joomla! 1.5 are not refactored yet to the new standards.

<?php
// The general information at the top of each file
/**
* @version		$Id$
* @package		Joomla
* @copyright	Copyright (C) 2005 - 2009 Open Source Matters, Inc. All rights reserved.
* @license		GNU General Public License, see LICENSE.php
*/

// No direct access allowed to this file
defined( '_JEXEC' ) or die( 'Restricted access' );

// Import Joomla! Plugin library file
jimport('joomla.plugin.plugin');

//The Content plugin Loadmodule
class plgContentLoadmodule extends JPlugin
{
	/**
	* Plugin that loads module positions within content
	*/
// onPrepareContent, meaning the plugin is rendered at the first stage in preparing content for output
	public function onPrepareContent( &$row, &$params, $page=0 )
	{
                // A database connection is created
		$db = JFactory::getDBO();
		// simple performance check to determine whether bot should process further
		if ( JString::strpos( $row->text, 'loadposition' ) === false ) {
			return true;
		}

	 	// expression to search for
	 	$regex = '/{loadposition\s*.*?}/i';

		// check whether plugin has been unpublished
		if ( !$this->params->get( 'enabled', 1 ) ) {
			$row->text = preg_replace( $regex, '', $row->text );
			return true;
		}

	 	// find all instances of plugin and put in $matches
		preg_match_all( $regex, $row->text, $matches );

		// Number of plugins
	 	$count = count( $matches[0] );

	 	// plugin only processes if there are any instances of the plugin in the text
	 	if ( $count ) {
			// Get plugin parameters
		 	$style	= $this->params->def( 'style', -2 );
	 		$this->_process( $row, $matches, $count, $regex, $style );
		}
		// No return value
	}
// The proccessing function
	protected function _process( &$row, &$matches, $count, $regex, $style )
	{
	 	for ( $i=0; $i < $count; $i++ )
		{
	 		$load = str_replace( 'loadposition', '', $matches[0][$i] );
	 		$load = str_replace( '{', '', $load );
	 		$load = str_replace( '}', '', $load );
 			$load = trim( $load );

			$modules	= $this->_load( $load, $style );
			$row->text 	= preg_replace( '{'. $matches[0][$i] .'}', $modules, $row->text );
	 	}

	  	// removes tags without matching module positions
		$row->text = preg_replace( $regex, '', $row->text );
	}
// The function who takes care for the 'completing' of the plugins' actions : loading the module(s)
	protected function _load( $position, $style=-2 )
	{
		$document	= &JFactory::getDocument();
		$renderer	= $document->loadRenderer('module');
		$params		= array('style'=>$style);

		$contents = '';
		foreach (JModuleHelper::getModules($position) as $mod)  {
			$contents .= $renderer->render($mod, $params);
		}
		return $contents;
	}
}

INI file(s)[edit]

For internationalization it is good to use the INI files. You can add to the language file everything which outputs text to the user, in this order:

  • XML description tag
  • XML label and description attributes from parameters
  • JText::_( 'string' ) used by the plugin

You should create two files: One for the backend and one for the front end. The naming should match the path of the extension. For example, if we were creating a content plugin named 'example' and it is installed at plugins/content/example, then our files should be named:

  • en-US.plg_content_example.ini (Frontend)
  • en-US.plg_content_example.sys.ini (Backend)


Start your INI file with something like this:

# $Id: en-GB.plg_content_nameofplugin.ini
# Joomla! Project
# Copyright (C) 2005 - 2007 Open Source Matters. All rights reserved.
# License http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL, see LICENSE.php
# Note : All ini files need to be saved as UTF-8 - No BOM

Of course, you could also add other information, like the author.

Joomla 1.6+ uses the ; at the start of the line, rather than the #.

Backend Example:

<param name="mode" type="list" default="1" label="PLG_CONTENT_EXAMPLE_MODE" description="PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED">
   <option value="0">PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT</option>
   <option value="1">PLG_CONTENT_EXAMPLE_LINKABLE_TEXT</option>
</param>

The localized strings are translated in the ini file:

PLG_CONTENT_EXAMPLE_MODE=Mode
PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED=Select how the e-mails will be displayed
PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT=Nonlinkable text
PLG_CONTENT_EXAMPLE_LINKABLE_TEXT=As linkable mailto address

Best practice dictates that LOCALIZED_TAGS are all upper case, no spaces, and begin with the same name as the extension - to avoid interfering with other strings.

The localized tags can then be translated into multiple languages.When you want to make your Content Plugin available in more languages, first add them to the <languages> tag in the XML file. Then create the same INI file, and change the part after the =, for example the dutch version would be:

PLG_CONTENT_EXAMPLE_MODE=Modus
PLG_CONTENT_EXAMPLE_EMAILS_DISPLAYED=Selecteer hoe de e-mails worden weergegeven
PLG_CONTENT_EXAMPLE_NONLINKABLE_TEXT=Niet-linkbare tekst
PLG_CONTENT_EXAMPLE_LINKABLE_TEXT=Als een linkbaar mailto adres

Frontend Example: On Joomla 1.6+ you must create a separate file for the front end - as described above. For example:

PLG_CONTENT_EXAMPLE_LINKNAME="The Name of the Link Goes Here!"

In the plugin's php file, you must load the language file:

// Load user_profile plugin language
$lang = JFactory::getLanguage();
$lang->load('plg_content_simpleattachment', JPATH_ADMINISTRATOR);
echo JText::_('PLG_CONTENT_EXAMPLE_LINKNAME');

You could also use another component or plugin's language file. This is useful for maintaining consistent strings between a component, module, and plugin, that are part of the same package.

To load another component or plugin's language files specify it's name in the load statement and specify whether to use the site or administrator language. For example:

$lang->load('com_someothercomponent',JPATH_ADMINISTRATOR);

Coding examples[edit]

There are seven Joomla! Core Content Plugins. These are all not yet refactored to the new standards. For learning how to write good plugins, its better to look at the (refactored) files of Joomla! 1.6. You can see them 'working' when you go to the Back-end of your Joomla! 1.5 installation, then go to the menu 'Extensions' and select the 'Plugin Manager'. Click on the name of the Plugin to edit it; and see it working. Also watch the content and see what happens when you insert a pagebreak for example.

Quick tips[edit]

  • In the PHP file you often forget to place an semicolon (;) at the end of a row, which causes errors. Check this before you test your Plugin and you will eliminate many errors.
  • Take care of the fact that the parameters in the XML file are closed correctly. When you add options for example, you need to close it with </param>.
  • It is easy to test on a localhost when you are still busy with editing your Plugin.
  • A typical zip will contain the following:
    • nameofplugin.XML
    • nameofplugin.PHP
    • en-GB.plg_content_nameofplugin.ini