Joomla! 1.0 component tutorial - part 1: front-end
A tutorial explaining how simple component for Joomla! CMS 1.0 works, and how to create a component. One may wonder why to write about version 1.0 of Joomla!, when version 1.5 is almost ready (as of January 2007). I think version 1.0 is still a very good framework: one can get to know how Joomla! works, extend the PHP knowledge, and prepare for Joomla! 1.5, which is a lot different and more advanced. And since there rather will not be upgrade possible from 1.0 to 1.5, just migration (hopefully a fast and easy one, thanks to great developers), there may be still a lot of existing web sites working on Joomla! 1.0 for quite some time.

Official Joomla! web site contains a lot of useful information:

help.joomla.org > Developer > Components

Joomla! Development Wiki

There are of course tutorials of Joseph LeBlanc , and let's not forget about the most important part - security:

Guide to more secure components


1. What is a component ?


Component is mini-application working in Joomla! enviroment. There are a few component included with Joomla! installation: com_banners, com_contact, com_content, com_weblinks and others. These core components cannot be uninstalled, of course.
Components show information in frontend and backend, as Joomla! does.

2. Simplest component

The very simplest component has only two files:
very_simple.php
very_simple.xml

Download zip file and install this sample component as usual in Joomla! Then create menu position pointing to the component. If there were no errors during installation the component should work now - it should display either "you are not logged in" or "welcome back" if you are logged in from frontend.

Joomla! installer creates two folders for the component (com_simplest), and will put these files there:
administrator/components/com_simplest/simplest.xml
components/com_simplest/simplest.php

The xml file is the "definition" file for the component - it contains details about it, list of files, SQL queries to perform during installation and after uninstalling it.
The php file is the actual frontend of a component.


3. Typical component files

The discussed component - JPortfSimple - has the following files:

  1. admin.jportfsimple.php
  2. admin.jportfsimple.html.php
  3. toolbar.jportfsimple.php
  4. toolbar.jportfsimple.html.php
  5. install.jportfsimple.php
  6. uninstall.jportfsimple.php
  7. jportfsimple.xml
  8. jportfsimple.class.php
  9. jportfsimple.php
  10. jportfsimple.html.php
  11. CSS / jp.css
  12. HELP / english.html
  13. IMAGES
  14. LANG / english.php
During component installation there are two folders created within Joomla!:
in administrator/components/com_jportfsimple - files 1 to 7 are copied here, this is so called backend
and
in components/com_jportfsimple - files 8, 9, 10 are copied here, this is frontend.

Location of remaining folders with files (11 to 14) depends on a developer. Location of all the above files and folders is defined in XML file, which is read during installation.


4. XML file

 

jportfsimple.xml
  1. <?xml version="1.0" ?>
  2. <mosinstall type="component">
  3. <name>jportfsimple</name>
  4. <creationDate>2007/01/01</creationDate>
  5. <author>Konrad Gretkiewicz</author>
  6. <copyright>This component in released under the GNU/GPL License</copyright>
  7. <authorEmail> This e-mail address is being protected from spam bots, you need JavaScript enabled to view it </authorEmail>
  8. <authorUrl>www.anetus.com</authorUrl>
  9. <version>0.2</version>
  10. <files>
  11. <filename>index.html</filename>
  12. <filename>jportfsimple.php</filename>
  13. <filename>jportfsimple.html.php</filename>
  14. <filename>jportfsimple.class.php</filename>
  15. <filename>license.txt</filename>
  16. <filename>_readme.txt</filename>
  17. <filename>css/index.html</filename>
  18. <filename>css/jp.css</filename>
  19. <filename>images/index.html</filename>
  20. <filename>images/no_image.jpg</filename>
  21. <filename>lang/index.html</filename>
  22. <filename>lang/english.php</filename>
  23. </files>
  24. <install>
  25. <queries>
  26. <query>
  27.   CREATE TABLE IF NOT EXISTS `#__jportfsimple_conf` (
  28. `id` INT NOT NULL AUTO_INCREMENT,
  29. `version` VARCHAR(20) NOT NULL,
  30. `base_path` VARCHAR(50) NOT NULL,
  31. `title` VARCHAR(100) NOT NULL,
  32. `description` TEXT NOT NULL,
  33. `css_file` VARCHAR(50) NOT NULL,
  34.   PRIMARY KEY (`id`)
  35.   ) TYPE=MyISAM
  36. </query>
  37. <query>
  38.   CREATE TABLE IF NOT EXISTS `#__jportfsimple_categories` (
  39. `id` INT NOT NULL AUTO_INCREMENT,
  40. `cat_name` TEXT NOT NULL,
  41. `cat_info` TEXT NOT NULL,
  42. `cat_path` TEXT NOT NULL,
  43. `meta_desc` TEXT NOT NULL,
  44. `meta_keywords` TEXT NOT NULL,
  45. `cat_image` TEXT NOT NULL,
  46. `cat_grp` int(11) NOT NULL default '0',
  47. `ordering` int(11) NOT NULL default '0',
  48. `access` TINYINT(1) NOT NULL default '0',
  49. `published` TINYINT(1) NOT NULL,
  50.   PRIMARY KEY (`id`)
  51.   ) TYPE=MyISAM
  52. </query>
  53. <query>
  54.   CREATE TABLE IF NOT EXISTS `#__jportfsimple_projects` (
  55. `id` INT NOT NULL AUTO_INCREMENT,
  56. `catid` TEXT NOT NULL,
  57. `name` TEXT NOT NULL,
  58. `description` TEXT NOT NULL,
  59. `meta_desc` TEXT NOT NULL,
  60. `meta_keywords` TEXT NOT NULL,
  61. `proj_image` TEXT NOT NULL,
  62. `proj_images_path` TEXT NOT NULL,
  63. `userid` int(11) NOT NULL default '0',
  64. `date` datetime NOT NULL,
  65. `ordering` int(11) NOT NULL default '0',
  66. `access` TINYINT(1) NOT NULL default '0',
  67. `published` TINYINT(1) NOT NULL,
  68.   PRIMARY KEY (`id`)
  69.   ) TYPE=MyISAM
  70. </query>
  71. <query>
  72. INSERT INTO `#__jportfsimple_conf` VALUES (1,'0.2','images/stories/','JPortSimple','Sample description.','jp.css');
  73. </query>
  74. </queries>
  75. </install>
  76. <uninstall>
  77. <queries>
  78. <query>
  79.   DROP TABLE IF EXISTS `#__jportfsimple_conf`;
  80. </query>
  81. <query>
  82.   DROP TABLE IF EXISTS `#__jportfsimple_categories`;
  83. </query>
  84. <query>
  85.   DROP TABLE IF EXISTS `#__jportfsimple_projects`;
  86. </query>
  87. </queries>
  88. </uninstall>
  89. <installfile>
  90.   <filename>install.jportfsimple.php</filename>
  91. </installfile>
  92. <uninstallfile>
  93.   <filename>uninstall.jportfsimple.php</filename>
  94. </uninstallfile>
  95. <administration>
  96.   <menu>jportfsimple</menu>
  97.   <submenu>
  98.     <menu act="categories">Categories</menu>
  99.     <menu act="projects">Projects</menu>
  100.     <menu act="configure">Configuration</menu>
  101.     <menu act="info">About</menu>
  102.   </submenu>
  103. <files>
  104.   <filename>index.html</filename>
  105.   <filename>admin.jportfsimple.php</filename>
  106.   <filename>admin.jportfsimple.html.php</filename>
  107.   <filename>toolbar.jportfsimple.php</filename>
  108.   <filename>toolbar.jportfsimple.html.php</filename>
  109.   <filename>logo.gif</filename>
  110.   <filename>help/index.html</filename>
  111.   <filename>help/english.html</filename>
  112. </files>
  113. </administration>
  114. <params>
  115.   <param name="back_button" type="list" default="" label="Back Button" description="Show/Hide a Back Button, that returns you to the previous page">
  116.     <option value="">Use Global</option>
  117.     <option value="0">Hide</option>
  118.     <option value="1">Show</option>
  119.   </param>
  120.   <param name="item_navigation" type="list" default="" label="Navigation Bar" description="Show/Hide the Navigation bar">
  121.     <option value="">Use Global</option>
  122.     <option value="0">Hide</option>
  123.     <option value="1">Show</option>
  124.   </param>
  125.   <param name="display_num" type="list" default="50" label="Display Number" description="Number of items to be displayed by default">
  126.     <option value="6">6</option>
  127.     <option value="10">10</option>
  128.     <option value="16">16</option>
  129.     <option value="20">20</option>
  130.     <option value="25">25</option>
  131.     <option value="30">30</option>
  132.     <option value="50">50</option>
  133.   </param>
  134. </params>
  135. </mosinstall>

lines 1 to 9 - basic component's information: name, author, version

10 to 23 - frontend files

24 to 75 - SQL queries creating new tables (CREATE) with necessary structure in database. Here 3 tables are created: jos_jportfsimple_conf (few configuration values), jos_jportfsimple_categories (for categories) and jos_jportfsimple_projects (for projects). #_ is replaced during installation with table prefix defined for your site (usually jos_). Last query (line 81) loads sample configuration values.

76 to 88 - SQL queries run during uninstalling the component, removing old tables (DROP)

89 to 94 - defines files to run after installing and uninstalling component

96 to 102 - created backend menu, in Components

103 to 112 - backend files

114 to 134 - defines parameter which can be modified in menu position for given component


5. Frontend

Class file defines classes used in the component.

jportfsimple.class.php
  1. // no direct access
  2. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  3.  
  4.  
  5. class jportfsimpleConf extends mosDBTable {
  6.   var $id = null;
  7.   var $version = null;
  8.   var $base_path = null;
  9.   var $title = null;
  10.   var $description = null;
  11.   var $css_file = null;   
  12.    
  13.   function jportfsimpleConf(&$db){
  14.     $this->mosDBTable('#__jportfsimple_conf', 'id', $db);
  15.   }
  16. }
  17.  
  18. class jportfsimpleCategories extends mosDBTable {
  19.     var $id = null;
  20.     var $cat_name = null;
  21.     var $cat_info = null;
  22.     var $cat_path = null;
  23.     var $meta_desc = null;
  24.     var $meta_keywords = null;
  25.     var $cat_image = null;
  26.     var $cat_grp = null;
  27.     var $ordering = null;
  28.     var $access = null;
  29.     var $published = null;
  30.    
  31.   function jportfsimpleCategories(&$db){
  32.     $this->mosDBTable('#__jportfsimple_categories', 'id', $db);
  33.   }
  34. }
  35.  
  36. class jportfsimpleProjects extends mosDBTable {
  37.   var $id = null;
  38.   var $catid = null;
  39.   var $name = null;
  40.   var $description = null;
  41.   var $meta_desc = null;
  42.   var $meta_keywords = null;
  43.   var $proj_image = null;
  44.   var $proj_images_path = null;
  45.   var $userid = null;
  46.   var $date  = null;
  47.   var $ordering = null;
  48.   var $access = null;
  49.   var $published = null;
  50.  
  51.   function jportfsimpleProjects(&$db){
  52.     $this->mosDBTable('#__jportfsimple_projects', 'id', $db);
  53.   }
  54. }

There are 3 classess defined, extending Joomla's class mosDBTable, each pointing to it's database table. Of course names of all fields here and in xml file (and database) must be the same.

Main frontend file - jportfsimple.php - contains all logic for the component. It should not contain any output instructions, output should be done via .html.php file.

jportfsimple.php
  1. // no direct access
  2. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  3.  
  4. global $mosConfig_live_site, $mosConfig_absolute_path, $mosConfig_lang, $database;
  5.  
  6. // load .class.php and .html.php files for the component
  7. require_once( $mainframe->getPath( 'class' ) );
  8. require_once( $mainframe->getPath( 'front_html' ) );
  9.  
  10. // load language file
  11. if (file_exists( $mosConfig_absolute_path.'/components/com_jportfsimple/lang/'.$mosConfig_lang.'.php'))
  12.       include_once( $mosConfig_absolute_path.'/components/com_jportfsimple/lang/'.$mosConfig_lang.'.php');
  13.    else
  14.    if (file_exists( $mosConfig_absolute_path.'/components/com_jportfsimple/lang/english.php'))
  15.          include_once( $mosConfig_absolute_path.'/components/com_jportfsimple/lang/english.php');
  16.  
  17. // load configuration from database
  18. $database->setQuery('SELECT * FROM #__jportfsimple_conf'  );
  19. $conf_rows = $database -> loadObjectList();
  20. if ($database -> getErrorNum()) {
  21.   echo $database -> stderr();
  22.   return false;
  23. }
  24. $jpConf=$conf_rows[0];
  25.  
  26. // add CSS file for the component
  27. $mainframe->addCustomHeadTag( '<link href="'.$mosConfig_live_site.'/components/com_jportfsimple/css/'.$jpConf->css_file.'" rel="stylesheet" type="text/css" />' );
  28.  
  29. // get option and category
  30. $option = trim( mosGetParam( $_REQUEST, 'option' ));
  31. $cat  = (int) ( mosGetParam( $_REQUEST, 'cat' ));
  32.  
  33. if (!$cat)
  34. {
  35.   // if category not defined display all
  36.     JP_categories();
  37. }
  38. else
  39. {
  40.   //display one category or one project
  41.  
  42.   $project = (int) ( mosGetParam( $_REQUEST, 'project' ));
  43.  
  44.   if ($project)
  45.   {
  46.     // display one project
  47.     JP_project( $cat, $project);
  48.   }
  49.   else
  50.   {
  51.     // no project so display all in category
  52.     JP_one_cat( $cat );
  53.   }
  54. }

First part of frontend file does the following:

line 15, 16 - loads the required class and frontend html (jportfsimple.html.php) files

19 to 23 - loads language file, default is english.php in com_jportfsimple/lang folder. The name of the file must be the same as the language file name for your Joomla! site

26 to 32 - reads data from database table containing configuration parameters. They are stored in $jpConf object.

line 35 - using Joomla function addCustomHeadTag the component loads the CSS file, what allows to style component display without changing whole site's CSS.

38 to 39 - function mosGetParam should be always used to get any input from user, with trim or (int) as additional security

41 to 62 - main frontend "logic": if category ($cat) is not defined, then display all categories, else try to read project number, and if it is defined, display one project, else display all projects in given category. That's it! Of course in case of more complicated component, here you would have case statement, with more variables.


Next, let's look at each function.


jportfsimple.php
  1. /**
  2. * Function displaying all categories
  3. */
  4. function JP_categories()
  5. {
  6.   global $database, $option, $mainframe, $jpConf;
  7.   // get categories
  8.   $database->setQuery('SELECT * FROM #__jportfsimple_categories ORDER BY ordering'  );
  9.   $rows = $database -> loadObjectList();
  10.   if ($database -> getErrorNum()) {
  11.     echo $database -> stderr();
  12.     return false;
  13.   }
  14.   // set page title
  15.   $mainframe->setPageTitle( $jpConf->title );
  16.  
  17.   display_categories( $option, $rows );
  18. }

First function loads all categories from database table (lines 71 to 77), then sets component title as web page title, and calls display function.


jportfsimple.php
  1. /**
  2. * Function displaying one category
  3. */
  4. function JP_one_cat( $cat )
  5. {
  6.   global $database, $mainframe, $option, $Itemid, $mosConfig_absolute_path, $jpConf;
  7.  
  8.   // get parameters associated with menu
  9.   $params = new stdClass();
  10.   if ( $Itemid ) {
  11.     $menu = new mosMenu( $database );
  12.     $menu->load( $Itemid );
  13.     $params = new mosParameters( $menu->params );
  14.   } else {
  15.     $menu = '';
  16.     $params = new mosParameters( '' );
  17.   }
  18.   // define parameters, if not set already
  19.   $params->def('back_button', $mainframe->getCfg( 'back_button' ) );
  20.   $params->def('item_navigation', $mainframe->getCfg( 'item_navigation' ));
  21.   $params->def('display_num', 50);
  22.  
  23.   // get category
  24.   $database->setQuery('SELECT * FROM #__jportfsimple_categories WHERE id = '.$cat );
  25.   $categ = $database -> loadObjectList();
  26.   if ($database -> getErrorNum()) {
  27.     echo $database -> stderr();
  28.     return false;
  29.   }
  30.  
  31.   if ($categ)
  32.   {
  33.     if ($categ[0]->published)
  34.     {
  35.     // get projects in the category
  36.     $database->setQuery('SELECT * FROM #__jportfsimple_projects WHERE catid='.$cat.' AND published=1 ORDER BY ordering '  );
  37.     $rows = $database -> loadObjectList();
  38.     if ($database -> getErrorNum()) {
  39.       echo $database -> stderr();
  40.       return false;
  41.       }
  42.     // get limit values (needed for pagination)
  43.     $limit     = intval( mosGetParam( $_REQUEST, 'limit', '' ) );
  44.     $limitstart = intval( mosGetParam( $_REQUEST, 'limitstart', 0 ) );
  45.  
  46.     $total = count($rows)
  47.     $limit = $limit ? $limit : $params->get( 'display_num' ) ;
  48.     if ( $total <= $limit )
  49.     {
  50.       $limitstart = 0;
  51.       $limit = $total;
  52.     }
  53.     //load pagination class
  54.     require_once( $mosConfig_absolute_path . '/includes/pageNavigation.php' );
  55.     $pageNav = new mosPageNav( $total, $limitstart, $limit );
  56.  
  57.     $pp=$categ[0]->cat_name;
  58.     // add category name to pathway
  59.     $mainframe->appendPathWay($pp);
  60.     // set page title
  61.     $mainframe->setPageTitle( $jpConf->title.' - '.$categ[0]->cat_name );
  62.     // set meta tags 
  63.     $mainframe->appendMetaTag( 'description', $categ[0]->meta_desc );
  64.     $mainframe->appendMetaTag( 'keywords', $categ[0]->meta_keywords );
  65.    
  66.     display_one_cat($categ[0]->id, $categ[0]->cat_name, $categ[0]->cat_info, $categ[0]->cat_path, $rows, $params, $pageNav );
  67.     }
  68.     else echo _COM_JP_ALB_NOT_PUBLISHED;
  69.   }
  70.   else echo _COM_JP_ALB_NOT_PUBLISHED;
  71. }

Lines 91 to 104 - reads parameters associated with component's menu position. These are the parameters defined at the end of xml file.

106 to 112 - reads category data from db.

114 to 117 - checks if there is a category with given id, and if it's published

118 to 124 - reads projects in given category

126 to 138 - gets pagination parameters (limit, limitstart), loads required class and created $pageNav object needed later

140 to 142 - adds category name to pathway

line 144 - adds component title and category name to web site title bar

146 to 147 - adds meta tags (keywords and description)

line 149 - all logic done, call display function



jportfsimple.php
  1. /**
  2. * Function displaying one project
  3. */
  4. function JP_project( $cat, $project )
  5. {
  6.   global $database, $mainframe, $option, $Itemid, $jpConf;
  7.  
  8.   // get parameters associated with menu
  9.   $params = new stdClass();
  10.   if ( $Itemid ) {
  11.     $menu = new mosMenu( $database );
  12.     $menu->load( $Itemid );
  13.     $params = new mosParameters( $menu->params );
  14.   } else {
  15.     $menu = '';
  16.     $params = new mosParameters( '' );
  17.   }
  18.   // define parameters, if not set already
  19.   $params->def('back_button', $mainframe->getCfg( 'back_button' ) );
  20.   $params->def('item_navigation', $mainframe->getCfg( 'item_navigation' ));
  21.  
  22.   // get category
  23.   $database->setQuery('SELECT * FROM #__jportfsimple_categories WHERE id = '.$cat );
  24.   $categ = $database -> loadObjectList();
  25.   if ($database -> getErrorNum()) {
  26.     echo $database -> stderr();
  27.     return false;
  28.   }
  29.  
  30.   // get project
  31.   $database->setQuery('SELECT * FROM #__jportfsimple_projects WHERE catid='.$cat.' AND id = '.$project.' AND published=1');
  32.   $proj = $database -> loadObjectList();
  33.   if ($database -> getErrorNum()) {
  34.     echo $database -> stderr();
  35.     return false;
  36.   }
  37.  
  38.   if ($proj) 
  39.       if ($proj[0]->published)
  40.     {
  41.    
  42.     // add category name to pathway 
  43.     $pp="<a href=\"?option=com_jportfsimple&cat=".$categ[0]->id."&Itemid=".$Itemid."\">"
  44. .$categ[0]->cat_name."</a>";
  45.     $mainframe->appendPathWay($pp);
  46.     // add project name to pathway
  47.     $pp=$proj[0]->name;
  48.     $mainframe->appendPathWay($pp)
  49.     // set page title
  50.     $mainframe->setPageTitle( $jpConf->title.' - '.$categ[0]->cat_name.' - '.$proj[0]->name );   
  51.     // set meta tags
  52.     $mainframe->appendMetaTag( 'description', $categ[0]->meta_desc );
  53.     $mainframe->appendMetaTag( 'keywords', $categ[0]->meta_keywords );
  54.  
  55.     display_project( $categ[0]->id, $categ[0]->cat_name, $categ[0]->cat_path, $proj, $params);
  56.    
  57.      }
  58.       else echo _COM_JP_ITEM_NOT_PUBLISHED;
  59.   else echo _COM_JP_ITEM_NOT_PUBLISHED;
  60.  
  61. }


Frontend view - jportfsimple.html.php - contains all output functions.
jportfsimple.html.php
  1. // no direct access
  2. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  3.  
  4. /**
  5. * Displaying all categories
  6. */
  7. function display_categories( $option, &$rows )
  8. {
  9.   global $jpConf, $Itemid, $mosConfig_live_site;
  10. ?> 
  11.  
  12. <div id="jp_front">
  13.   <div id="jp_fronttitle">
  14.     <?php echo $jpConf->title; ?>
  15.   </div>
  16.   <?php if ($jpConf->description) { ?>
  17.   <div id="jp_frontdesc">
  18.     <?php echo $jpConf->description; ?>
  19.   </div>
  20.   <?php  } ?>
  21.   <div id="jp_frontcategories">
  22.  
  23.   <?php
  24. // if no rows then display: No categories defined !
  25. if (!$rows) echo _COM_JP_NO_CAT;
  26. else
  27. foreach($rows as $row)
  28. {
  29.   if ($row->published) {
  30.     $link='<a href="'.sefRelToAbs( 'index.php?option='.$option.'&cat='.$row->id.'&Itemid='.$Itemid).'">';
  31.     echo '<div class="jp_frontcategory">';
  32.       echo '<div class="jp_frontcatname">';
  33.       echo $link.$row->cat_name.'</a><br />';
  34.       echo '</div>';
  35.       echo '<div class="jp_frontcatimage">';
  36.       if ($row->cat_image)
  37.       echo $link.'<img src="'.$mosConfig_live_site.'/'.$jpConf->base_path.$row->cat_image.'" border="0" alt="" /></a>';
  38.    
  39.       echo '</div>';
  40.       echo '<div class="jp_frontcatinfo">';
  41.       echo $row->cat_info;
  42.         echo '</div>';
  43.       echo '</div>';
  44.     }
  45. }
  46.   echo'</div>';
  47.   bottom();
  48. echo '</div>';
  49. }

Lines 20 to 28 - shows component title and description

line 33 - shows warning if there are no categories

35 to 54 - loop through categories and shows their name, description and image, if exists

in line 38 function sefRelToAbs is used so links work when SEF is enabled

As you can see, almost each displayed element is surrounded with <div> element, each with specific id or class. This way  component display is not based on tables, but uses CSS.


jportfsimple.html.php
  1. /**
  2. * Displaying all projects in one category
  3. */
  4. function display_one_cat( $catid, $catname, $catinfo, $catpath, &$rows, &$params, &$pageNav )
  5. {
  6. global $jpConf, $option, $Itemid, $mosConfig_absolute_path, $mosConfig_live_site;
  7.  
  8. echo '<div id="jp_front">';
  9.   echo '<div id="jp_cattitle">'._COM_JP_CAT_NAME.$catname.'</div>';
  10.   if ($catinfo)
  11.     echo '<div id="jp_catinfo">'.$catinfo.'</div>';
  12.  
  13.   echo '<div id="jp_onecat">';
  14.   // if no rows then display: No projects defined !
  15.     if (!$rows) echo _COM_JP_NO_PROJ;
  16.    
  17.     // go through all projects on given page
  18.     for($i=$pageNav->limitstart; $i < ($pageNav->limitstart+$pageNav->limit) && $i < $pageNav->total; $i++)
  19.     if ($rows[$i])
  20.   {
  21.   $src=$jpConf->base_path.$catpath.'/'.$rows[$i]->proj_image;
  22.   // if image defined exist, then show it, or show no_image.jpg
  23.   if (!file_exists($mosConfig_absolute_path.'/'.$src) | is_dir($mosConfig_absolute_path.'/'.$src))
  24.     {
  25.     $src=$mosConfig_live_site.'/components/com_jportfsimple/images/no_image.jpg';
  26.     }
  27.   $link2=sefRelToAbs( 'index.php?option='.$option.'&cat='.$catid.'&project='.$rows[$i]->id.'&Itemid='.$Itemid);
  28.   $prname=$rows[$i]->name;
  29.     echo '<div class="jp_onecat_proj">';
  30.       echo '<div class="jp_onecat_img"><div class="jp_onecat_img2"><a href="'.$link2.'"><img src="'.$src.'" border="0" alt="" /></a></div></div>';
  31.       echo '<div class="jp_onecat_name"><a href="'.$link2.'">'.$prname.'</a></div>';
  32.     echo '</div>';
  33.   }
  34.  
  35.   echo '</div>';
  36.  
  37.   // if item navigation enabled, then show page number
  38.   if ( $params->get( 'item_navigation' ) && !($pageNav->limit == $pageNav->total) )
  39.   {
  40.     echo '<div class="jp_pagination">';
  41.     $link='index.php?option='.$option.'&cat='.$catid.'&Itemid='.$Itemid;
  42.     echo $pageNav->writePagesLinks( $link );
  43.     echo '</div>';   
  44.   }
  45.  
  46.   // if back button enabled, show it
  47.   if ( $params->get( 'back_button' ))
  48.   {
  49.     echo '<div class="jp_back">';
  50.     mosHTML::BackButton ( $params );
  51.     echo '</div>';
  52.   }
  53.   bottom();
  54. echo '</div>';
  55. }

line 76 - uses limit and limitstart (from $pageNav) to loop through all projects on given page

95 to 102 - shows page numbers, if it should

104 to 110 - shows back button, if enabled



jportfsimple.html.php
  1. /**
  2. * Displaying one project
  3. */
  4. function display_project( $catid, $catname, $catpath, &$proj, &$params )
  5. {
  6. global $database, $option,$Itemid, $jpConf, $mosConfig_absolute_path, $mosConfig_live_site;
  7.  
  8. echo '<div id="jp_front">';
  9.   echo '<div id="jp_cattitle">'._COM_JP_CAT_NAME.$catname.'</div>';
  10.   echo '<div id="jp_projtop" >'._COM_JP_PROJ_NAME.$proj[0]->name.'</div>';
  11.  
  12.   echo '<div id="jp_projcont" >';
  13.     echo '<div id="jp_projimage" >';
  14.     $src=$jpConf->base_path.$catpath.'/'.$proj[0]->proj_image;
  15.   // if image defined exist, then show it, or show no_image.jpg
  16.   if (!file_exists($mosConfig_absolute_path.'/'.$src) | is_dir($mosConfig_absolute_path.'/'.$src))
  17.     {
  18.     $src=$mosConfig_live_site.'/components/com_jportfsimple/images/no_image.jpg';
  19.     }
  20.     echo '<img src="'.$src.'" border="0" alt="" />';
  21.     echo '</div>';
  22.     echo '<div id="jp_projdesc" >';
  23.     echo $proj[0]->description.'<br />';
  24.     echo '</div>';
  25.   echo '</div>';
  26.  
  27.   // if back button enabled, show it
  28.   if ( $params->get( 'back_button' ))
  29.   {
  30.     echo '<div class="jp_back">';
  31.     mosHTML::BackButton ( $params );
  32.     echo '</div>';
  33.   }
  34.  
  35.   bottom();
  36. echo '</div>';
  37.  
  38. }
  39.  
  40. /**
  41. * Displaying component footer
  42. */
  43. function bottom()
  44. {
  45. ?> 
  46.   <div align="right" style="float:right; width:60%; line-height:6px; padding:3px;">
  47.   <span class="small">
  48.   <br /><br /><br /> 
  49.   <a href="http://www.anetus.com/_r/jportfolio-component-for-joomla-cms" target="_blank" title="JPortfolio - component for Joomla! CMS">jp</a>
  50.   </span>
  51.   </div>
  52. <?php
  53. }
  54.  
  55.  
  56. ?>

Function display_project does exactly what the name suggests - it displays one project.

Last one: bottom() - this is the function showing component footer, something like link to component web page and/or copyright information. It is not necessary to have, of course ;)


6. Remaining frontend files

There are few more files in frontend folder: language file, CSS file, and images.
Language file - lang/english.php:
lang/english.php
  1. // no direct access
  2. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  3.  
  4. // main info
  5.  
  6. DEFINE('_COM_JP_VERSION','0.2');
  7. DEFINE('_COM_JP_DESC',' JPortfSimple - example of Joomla! component');

It's always good to provide language file, instead of using strings inside component, so the component can be translated easier.

CSS file - css/jp.css:

jp.css
  1. /* CSS for JPortSimple
  2. *
  3. * jp.css
  4. */
  5.  
  6. /*********************/
  7. /* frontpage */
  8.  
  9. #jp_front {
  10. position:relative;
  11. float:left;
  12. width:99.5%!important;
  13. width:99.7%;
  14. margin:0px;
  15. }
  16.  
  17. #jp_fronttitle, #jp_cattitle {
  18. position:relative;
  19. font-weight:bold
  20. font-size: 16px; 
  21. border-bottom: 2px solid #ccc;
  22. float:left;
  23. width:94%!important;
  24. width:97%;
  25. padding:10px;
  26. margin:1%;
  27. }
  28.  
  29. and so on
  30. ......

CSS file contains all classes used in divs in the component.

So far I haven't found a tool which would make checking language or css files easier. Now whatever change in the code is done - a text constant added or changed, or CSS class name changed - one has to remember to add/remove/change the respective one in the language or CSS file.