Skip to content

Move your article’s data header to footer

After very busy work time I can write some other articles that I hope you find interesting.
I am involved in a large project for a news portal http://www.arezzonotizie.it/.
For this project I made some patches and writed some code personalization.
The first plugin I want to present is a mambot to move data from header to footer.
The standard joomla article's header show some elements in the header of the article:

  • pdf icon
  • print icon
  • e-mail icon
  • date created
  • author name

The mambot I have developed move all of this elements in the footer of the article.
As a bonus if the author have a linked contact, shows hyperlink to the correspondig author contact page.

PHP:
  1. /**
  2. * Authors Link Bot
  3. * @version 1.0
  4. * @package None
  5. * @copyright (C) Copyright 2007-2007 by Marco Sbragi
  6. * @license http://www.gnu.org/copyleft/gpl.html GNU/GPL
  7. */
  8.  
  9. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  10. $_MAMBOTS->registerFunction( 'onPrepareContent', 'botMosAuthorLink' );
  11.  
  12. function botMosAuthorLink( $published, &$row, &$params, $page=0  ) {
  13.     global $mosConfig_absolute_path, $database;
  14.  
  15.     $showbottom = true;
  16.  
  17.     // $row->created_by       -> Id dell'autore
  18.     // $row->created_by_alias -> Alias autore
  19.     // $row->Author           -> Nome Autore
  20.    
  21.     if($_REQUEST['task'] != 'view') { return true; }
  22.     if(! $published)                { return true; }
  23.     if($params->get( 'popup' ) )    { return true; }
  24.  
  25.    
  26.     if((@$row->created_by) && (! $my->id)) {
  27.         if((!$row->created_by_alias) || (strtolower(($row->created_by_alias) == strtolower($row->author)))) {
  28.             // Check If declared on Contacts
  29.             $database->setQuery( "SELECT id FROM #__menu WHERE link = 'index.php?option=com_contact' AND published=1" );
  30.             $Itemid = (int) $database->loadResult();
  31.  
  32.             $query = "SELECT id"
  33.                 . "\n FROM #__contact_details"
  34.                 . "\n WHERE user_id = {$row->created_by}"
  35.                 . "\n AND published = 1"
  36.                 . "\n LIMIT 1";
  37.  
  38.             $database->setQuery( $query );
  39.             $Id = (int) $database->loadResult();
  40.             if($Id) {
  41.                 $author_link = sefRelToAbs("index.php?option=com_contact&task=view&contact_id={$Id}&Itemid={$Itemid}");
  42.                 $row->created_by_alias = "<a href='" . $author_link . "'>" . $row->author . "</a>";
  43.             } else {
  44.                 $row->created_by_alias = $row->author;
  45.             }
  46.         }
  47.  
  48.         // Use standard jOOmla format
  49.         if(! $showbottom) {
  50.             return true;
  51.         }
  52.  
  53.         $showEmail = $params->get('email');
  54.         $showPrint = $params->get('print');
  55.         $showPdf   = $params->get('pdf');
  56.  
  57.         $params->set('author',0);
  58.         $params->set('createdate',0);
  59.         $params->set('print',0);
  60.         $params->set('email',0);
  61.         $params->set('pdf',0);
  62.  
  63.         $print_link = $mosConfig_live_site. '/index2.php?option=com_content&amp;task=view&amp;id=' . $row->id .'&amp;pop=1&amp;page='. $page . $row->Itemid_link;
  64.  
  65.         $str_html  = '<table style="clear: both;" width="100%" class="botAuthor" cellspacing="0" cellpadding="0">';
  66.         $str_html .= '<tr>';
  67.         $str_html .= '<td align="left">' . strtoupper(mosFormatDate($row->created)) . ' - ' . $row->created_by_alias . '</td>';
  68.         // $showPdf   && $str_html .= botMosAuthor_PdfIcon($row, $params );
  69.         $showPrint && $str_html .= botMosAuthor_PrintIcon($row, $params, $print_link );
  70.         $showEmail && $str_html .= botMosAuthor_EmailIcon($row, $params);
  71.         $str_html .= '</tr>';
  72.         $str_html .= '</table>';
  73.         $row->text .= $str_html;
  74.     }
  75.  
  76.     return true;
  77. }
  78.  
  79. function botMosAuthor_PdfIcon( &$row, &$params ) {
  80.     global $mosConfig_live_site, $Itemid, $task;
  81.        
  82.     if ( $params->get( 'popup' ) ) {
  83.         return '';
  84.     }
  85.  
  86.     $status = 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no';
  87.     $link = $mosConfig_live_site. '/index2.php?option=com_content&amp;do_pdf=1&amp;id='. $row->id;
  88.        
  89.     if ( $params->get( 'icons' ) ) {
  90.         $image = mosAdminMenus::ImageCheck( 'pdf_button.png', '/images/M_images/', NULL, NULL, _CMN_PDF, _CMN_PDF );
  91.     } else {
  92.         $image = '&nbsp;'. _CMN_PDF;
  93.     }
  94.     $str_html  = '<td align="right" width="16" class="buttonheading">';
  95.     $str_html .= '<a href="' . $link .'" target="_blank" onclick="window.open(\'' . $link .'\',\'win2\',\'' . $status. '\'); return false;" title="' . _CMN_PDF .'">' . $image . '</a>';
  96.     $str_html .= '</td>';
  97.     return $str_html;
  98. }
  99.  
  100. function botMosAuthor_EmailIcon( &$row, &$params ) {
  101.     global $mosConfig_live_site, $Itemid, $task;
  102.        
  103.     if ( $params->get( 'popup' ) ) {
  104.         return '';
  105.     }
  106.  
  107.     $status = 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=400,height=250,directories=no,location=no';
  108.        
  109.     $_Itemid = '&amp;itemid='. $Itemid;
  110.        
  111.     $link   = $mosConfig_live_site .'/index2.php?option=com_content&amp;task=emailform&amp;id='. $row->id . $_Itemid;
  112.        
  113.     if ( $params->get( 'icons' ) ) {
  114.         $image = mosAdminMenus::ImageCheck( 'emailButton.png', '/images/M_images/', NULL, NULL, _CMN_EMAIL, _CMN_EMAIL );
  115.     } else {
  116.         $image = '&nbsp;'. _CMN_EMAIL;
  117.     }
  118.     $str_html  = '<td align="right" width="16" class="buttonheading">';
  119.     $str_html .= '<a href="' . $link .'" target="_blank" onclick="window.open(\'' . $link .'\',\'win2\',\'' . $status. '\'); return false;" title="' . _CMN_EMAIL .'">' . $image . '</a>';
  120.     $str_html .= '</td>';
  121.     return $str_html;
  122. }
  123.  
  124. function botMosAuthor_PrintIcon( &$row, &$params, $link ) {
  125.     global $mosConfig_live_site, $Itemid, $task;
  126.        
  127.     $status = 'status=no,toolbar=no,scrollbars=yes,titlebar=no,menubar=no,resizable=yes,width=640,height=480,directories=no,location=no';
  128.        
  129.     $_Itemid = '&amp;itemid='. $Itemid;
  130.        
  131.     if ( $params->get( 'icons' ) ) {
  132.         $image = mosAdminMenus::ImageCheck( 'printButton.png', '/images/M_images/', NULL, NULL, _CMN_PRINT, _CMN_PRINT );
  133.     } else {
  134.         $image = _ICON_SEP .'&nbsp;'. _CMN_PRINT. '&nbsp;'. _ICON_SEP;
  135.     }
  136.  
  137.     $str_html  = '<td align="right" width="16" class="buttonheading">';
  138.     if ( $params->get( 'popup' ) ) {
  139.         $str_html .= '<a href="#" onclick="javascript:window.print(); return false;" title="' . _CMN_PRINT . '">' . $image . '</a>';
  140.     } else {
  141.         $str_html .= '<a href="' . $link .'" target="_blank" onclick="window.open(\'' . $link .'\',\'win2\',\'' . $status. '\'); return false;" title="' . _CMN_PRINT .'">' . $image . '</a>';
  142.     }
  143.     $str_html .= '</td>';
  144.     return $str_html;
  145. }

For anyone of you interested in how to write mambot for jOOmla read this article on jOOmla help site http://help.joomla.org/content/category/12/113/125

Download mambot

If you wish to use the mambot as a simple author to contact link and want to leave the standard jOOmla layout you must change the declaration at line 15 from

PHP:
  1. // $showbottom = true;
  2. // To
  3. $showbottom = false;

Want a free layout for your cake?

If you want a layout for your new cake app and don't want to waste your time you can benefit of thousands of templates made for jOOmla.
The translation from joomla templates to cake layout is a very very simple job.

Let me explain from start:
A jOOmla template is composed of this main files and dirs

index.php - main template file
css/template_css.css - stylesheet file
images/* - all the images needed from stylesheet and main file

this can vary but this is the minimum requirements.

The first thing to do is to move the css/* files in your webroot/css
then move the images dir in your webroot.

webroot
|----css
|       template_css.css
|       cake.generic.css
|
|----img/*
|
|----images/*

If you wish to have only one dir for all your images then you must change all reference to images/ with img/ in your index.php and template_css.css

Now move your index.php file to your cakeroot/views/layout and rename it to default.thtml

Ok this is the 50% of job :).

Now we must modify the default.thtml file to meet cake requirements.

This a simple joomla template 2 (columns i used for one of my clients)
You can view how it renders here

CODE:
  1. <?php
  2. defined( '_VALID_MOS' ) or die( 'Direct Access to this location is not allowed.' );
  3. ob_start("accSub_ob_callback");
  4. // needed to seperate the ISO number from the language file constant _ISO
  5. $iso = split( '=', _ISO );
  6. // Master paths:
  7. $path     = $mosConfig_live_site .'/templates/dara';
  8. $path_images    = $path .'/images';
  9. ?>
  10. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  11. <html xmlns="http://www.w3.org/1999/xhtml">
  12. <head>
  13. <?php
  14. if ( $my->id ) {
  15.     initEditor();
  16. }
  17. ?>
  18. <meta http-equiv="Content-Type" content="text/html; _ISO" />
  19. <?php mosShowHead(); ?>
  20. <link rel="shortcut icon" href="/images/favicon.ico" />
  21. </link><link rel="stylesheet" type="text/css" href="/css/template_css.css" />
  22. <!--[if lt IE 7]>
  23.     </link><link rel="stylesheet" type="text/css" href="/css/template_css_ie.css" />
  24. <![endif]-->
  25. </link></meta></head>
  26. <body  id="home">
  27.  
  28. <div id="site">
  29.     <div id="shadow">
  30.         <div id="wrapper">
  31.             <div id="masthead">
  32.                 <h1><?php echo $mosConfig_sitename; ?></h1>
  33.                 <!--<a href="#" title="Click here to sign up now." id="signUpNow">Sign up now!-->
  34.             </div>
  35.  
  36.             <div id="mainMenu">
  37.                 <?php mosLoadModules ( 'header', -2 ); ?>
  38.                 <br class="clearing" />
  39.             </div>
  40.  
  41.             <div id="content">
  42.                 <?php if($option == 'com_frontpage' || $option == '') { ?>
  43.                 <div id="homead">
  44.                     <?php mosLoadModules ( 'banner', -2 ); ?>
  45.                 </div>
  46.                 <?php } ?>
  47.                 <div id="subMenu"><?php mosLoadModules ( 'left', -2 ); ?></div>
  48.                 <div id="main"><?php mosMainBody(); ?></div>
  49.                 <br class="clearing" />
  50.             </div>
  51.  
  52.             <div id="footer">
  53.               <a taget="_blank" href="http://www.joomla.org/">jOOmla cms</a>
  54.               &nbsp;|&nbsp;Powered by <a taget="_blank" href="http://www.nospace.net/">nospace</a>
  55.               &nbsp;|&nbsp;&copy; italplan 2006
  56.             </div>
  57.         </div>
  58.     </div>
  59. </div>
  60. <map name="HomeMap">
  61. <area href="index.php?lang=it" shape="polygon" coords="138, 76, 324, 76, 361, 38, 183, 37">
  62. </area><area href="index.php?lang=en" shape="polygon" coords="142, 130, 327, 129, 359, 93, 186, 93">
  63. </area><area href="index.php?lang=pt" shape="polygon" coords="141, 184, 330, 184, 364, 148, 187, 147">
  64. <!--
  65. <area href="index.php?lang=es" shape="polygon" coords="142, 239, 328, 239, 365, 202, 186, 202">
  66. -->
  67. </area></map>
  68. </body>
  69. </html>
  70. <?php ob_end_flush(); ?>

The translation is very simple:
Replace mosMainBody(); jOOmla functions with echo content_for_layout;
And if needed replace the mosLoadModules() functions with renderElements()

Here the revised template for cake:

CODE:
  1. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  2. <html xmlns="http://www.w3.org/1999/xhtml">
  3. <head>
  4. <!-- cakePHP header Begin -->
  5. <title>CakePHP(tm) : <?php echo $title_for_layout;?></title>
  6. <link rel="icon" href="favicon.ico" type="image/x-icon" />
  7. </link><link rel="shortcut icon" href="favicon.ico" type="image/x-icon" />
  8. <?php
  9.   echo $html->css('template_css');
  10.   echo $html->css('cake.generic');
  11.   if(isset($javascript)) {
  12.     echo $javascript->link('jquery-latest.js') . "\n";
  13.   }
  14.   echo isset($head) ? $head->registered() : '';
  15.   echo "\n";
  16. ?>
  17. <!-- cakePHP header End -->
  18. </link></head>
  19. <body id="home">
  20. <div id="site">
  21.     <div id="shadow">
  22.         <div id="wrapper">
  23.             <div id="masthead">
  24.             </div>
  25.             <div id="mainMenu">
  26.                 <!-- cakePHP Top Menu -->
  27.                 <?php echo $this->renderElement('menus/topMenu'); ?>
  28.                 <br class="clearing" />
  29.             </div>
  30.             <div id="content">
  31.                 <div id="homead">
  32.                     <?php echo $this->renderElement('banner'); ?>
  33.                 </div>
  34.                 <div id="subMenu">
  35.                     <!-- cakePHP left Menu -->
  36.                     <?php echo $this->renderElement('menus/leftMenu'); ?>
  37.                 </div>
  38.                 <div id="main">
  39.                     <!-- cakePHP contents -->
  40.                     <?php $session->flash(); ?>
  41.                     <?php echo $content_for_layout; ?>
  42.                 </div>
  43.                 <br class="clearing" />
  44.             </div>
  45.             <div id="footer">
  46.               <a taget="_blank" href="http://www.joomla.org/">jOOmla cms</a>
  47.                | Powered by <a taget="_blank" href="http://www.nospace.net/">nospace</a>
  48.                | and <a taget="_blank" href="http://www.cakephp.org/">cakephp</a>
  49.             </div>
  50.         </div>
  51.     </div>
  52. </div>
  53. </body>
  54. </html>

if you want tons of free templates go to jOOmla forum it is a very good resource also for making templates that render the same on different browser

Bypass jOOmla acl for automatic publishing

You knows that with jOOmla only publishers can publish there are situations with small groups I had requests for lowering the acl and permits to publish their articles also for authors. This is a very simple trick to do.

Locate these lines near the top of components/com_content/content.php

PHP:
  1. // Editor usertype check
  2. $access = new stdClass();
  3. $access->canEdit    = $acl->acl_check( 'action', 'edit', 'users', $my->usertype, 'content', 'all' );
  4. $access->canEditOwn = $acl->acl_check( 'action', 'edit', 'users', $my->usertype, 'content', 'own' );
  5. $access->canPublish = $acl->acl_check( 'action', 'publish', 'users', $my->usertype, 'content', 'all' );

And replace with:

PHP:
  1. // Editor usertype check
  2. $access = new stdClass();
  3. // ---------------------------------------------------------------------------
  4. // Marco 05.12.2005
  5. // Show publish in frontend even for authors
  6. // http://blog.nospace.net/
  7. // ---------------------------------------------------------------------------
  8. $acl->_mos_add_acl( 'action', 'publish', 'users', 'editor', 'content', 'all' );
  9. $acl->_mos_add_acl( 'action', 'publish', 'users', 'author', 'content', 'all' );
  10. // ---------------------------------------------------------------------------
  11. $access->canEdit    = $acl->acl_check( 'action', 'edit', 'users', $my->usertype, 'content', 'all' );
  12. $access->canEditOwn = $acl->acl_check( 'action', 'edit', 'users', $my->usertype, 'content', 'own' );
  13. $access->canPublish = $acl->acl_check( 'action', 'publish', 'users', $my->usertype, 'content', 'all' );

And then locate this lines:

PHP:
  1. } else {
  2.         $row->sectionid = $sectionid;
  3.         $row->version = 0;
  4.         $row->state = 0; // <<<<----------- replace 0 with 1 if you wish publish checkbox auto checked
  5.         $row->ordering = 0;
  6.         $row->images = array();
  7.         $row->publish_up = date( 'Y-m-d', time() );
  8.         $row->publish_down = 'Mai';
  9.         $row->creator = 0;
  10.         $row->modifier = 0;
  11.         $row->frontpage = 0;
  12.     }

that's all.

When model::getLastInsertId() is not enough.

There are situation where the very useful model::getLastInsertId() function is not enough.
For example if you are editing a records of an hasMany parts and you want to return to the list of records that belongsTo its parent.

Let me explain better:

PHP:
  1. /*
  2. ** Post model
  3. ** File: models/post.php
  4. */