domenica 24 febbraio 2008

Joomla 1.5: campo data con controllo calendario

Una risposta veloce ad un quesito ricevuto da un lettore (qualcuno usa il modulo per le domande / suggerimenti e, quando sono in grado, mi fa piacere rispondere).

Sembra proprio che la creazione di componenti per Joomla 1.5 sia un argomento 'caldo', la domanda in questo caso è come utilizzare il controllo standard calendario per gestire un campo data in un proprio componente.

Visto che si è già creato un componente per la gestione di un modulo di immissione dati, mi sembra inutile crere un altro esempio solo per questo problema.

Il punto di partenza sarà quindi l'ultima versione del componente MyForm (myform5.zip, scaricabile dal sito). Ecco la procedura passo passo per aggiungere al modulo un campo data (data di nascita) e consentire l'input all'utente tramite il calendario standard di Joomla (per intendersi quello con cui si imposta, ad esempio, la data di pubblicazione degli articoli).

Per brevità eviterò di riportare tutti i file per intero. Nel codice la parte da inserire o modificare è in blu, mentre sono in nero le parti preesistenti giusto per capire il punto esatto dove è stata fatta la modifica.

Inserimento del campo nel database

Il nuovo campo data deve essere inserito nel database, quindi bisogna modificare lo script sql di installazione.

File: install.sql
[...]/administrator/components/com_myform/

CREATE TABLE `#__myform` (
  ...
  `note` text NULL,
  `data_nasc` date NULL,
  `data` datetime NULL,
   PRIMARY KEY  (`id`)
) DEFAULT CHARSET=utf8;

Se avete una versione già installata del componente potete semplicemente aggiornare la tabella lanciando da phpmyadmin questa query

ALTER TABLE `jos_myform` ADD `data_nasc` DATE NULL;

Se avete un prefisso tabelle diverso da jos_ il nome della tabella va modificato opportunamente.

Aggiungere il campo alla classe Table

La classe Table deve essere modificata per riflettere la modifica fatta alla tabella del database

File: myform.php
[...]/administrator/components/com_myform/tables

class TableMyForm extends JTable {
  ...
  var $data_nasc = null;
  ...
  function check() {
    ...
    if (trim($this->data_nasc) == '') {
      $this->setError(JText::_('Inserire la Data di nascita.'));
      return false;
    }
    $d = explode('-', $this->data_nasc);
    if(count($d) != 3 || checkdate($d[1], $d[0], $d[2]) === false) {
      $this->setError(JText::_('Data di nascita non valida!'));
      return false;
    }
    $this->data_nasc = date('Y-m-d',mktime(0,0,0,$d[1],$d[0],$d[2]));
    return true;

  } //Fine check

Acquisiamo la data nel formato giorno-mese-anno più familiare all'utente e, se è valida, prima di uscire dalla funzione la convertiamo nel formato che si aspetta MySql (anno-mese-giorno).

Aggiungere il campo nella struttura del modulo

La struttura del modulo è definita nella classe Model. Aggiungiamo all'array fields la definizione per il nuovo campo data.

File: myform.php
[...]/components/com_myform/models/

class MyFormModelMyForm extends JModel {
var $form = array(
  'name' => 'myform',
  'id' => 'myform',
  'fields' => array (
     ...
     array('label'=>'Indirizzo','name'=>'myform[indirizzo]',
'id'=>'indirizzo', 'size'=>40),
     array('label'=>'Data Nascita', 'name'=>'myform[data_nasc]',
'id'=>'data_nasc', 'size'=>'9','type'=>'date'),
     ...
   )
);
...

Modifica funzione visualizzazione modulo

Dobbiamo gestire la visualizzazione del nuovo tipo di campo (date).

File: myform.php
[...]/administrator/components/com_myform/helpers/

...
switch($type) {
...
case 'date':
  if($fv && $ts=strtotime($fv)) {
    $fv = strftime('%d-%m-%Y', $ts);
  }
  $html .= JHTML::_('calendar', $fv, $field['name'], $field['id'], 
  '%d-%m-%Y', array('size'=>$field['size'])) .'<br />';
  break;
}
...

La classe JHTML contiene diverse funzioni per la generazione dell'html. Quella che abbiamo visto serve a creare un campo input con a fianco un'icona che attiva il calendario per l'inserimento della data. Gli argomenti sono

  • 'calendar' costante
  • data da inserire nel campo
  • attributo name del tag input per il campo data
  • attributo id del tag input per il campo data
  • formato data. Stesso formato della istruzione strftime poco sopra
  • array con attributi addizionali del tag input per il campo data

Modifica funzione visualizzazione elenco

Aggiungiamo anche una colonna all'elenco per la visualizzazione dei dati inseriti.

File: default.php
[...]/administrator/components/com_myform/views/myform/tmpl

...
$trh = '<thead><tr>
<th width="20">
    <input type="checkbox" name="toggle" value="" 
 onclick="checkAll(' . count($this->items) . ');" />
</th>
<th width="15%%">%s</th><th width="15%%">%s</th>
<th width="10%%">%s</th><th width="20%%">%s</th>
<th width="15%%">%s</th>
<th width="25%%">%s</th></tr></thead>';
$tr = '<tr>' . str_repeat('<td>%s</td>', 7) . '</tr>';
...
$html .= '<tfoot><tr><td colspan="7">' 
. $this->pagination->getListFooter()
. '</td></tr></tfoot>';
$html .= sprintf($trh,JText::_('Nome'),JText::_('Cognome'), 
JText::_('Telefono'),JText::_('Indirizzo'),JText::_('Data Nascita'), 
JText::_('Note'));
$i = 0;
foreach($this->items as $item) {
  $checked = JHTML::_('grid.id', $i, $item->id); 
  $dn = '';
  if($item->data_nasc) {
    $dn = strftime('%d %B %Y', strtotime($item->data_nasc));
  }
  $html .= sprintf($tr, $checked, $item->nome, $item->cognome, 
  $item->telefono, $item->indirizzo, $dn, $item->note);
  $i++;
}
...
Un'ultima cosa: l'icona del calendario viene visualizzata con un bordo che a me personalmente non piace granché. Se siete della stessa opinione e volete toglierlo il file da modificare è [...]/media/system/css/calendar-jos.css

eliminate la riga 10

 border: 1px solid #cccccc;
Abbiamo finito. Il campo data di nascita sarà visibile nel frontend e nel backend del componente.

mercoledì 20 febbraio 2008

Joomla 1.5: Guida Sviluppo Componenti

Riscontro un certo interesse riguardo allo sviluppo di componenti per Joomla 1.5. Si è già avuto modo di parlare dell'argomento in diverse occasioni, ma, come giustamente qualche lettore mi ha fatto notare, sarebbe utile avere un riferimento in un formato più 'compatto' di una serie di articoli sparsi sul blog.

Per cui ho pensato di fare cosa gradita (e se non fosse gradita ormai sarebbe troppo tardi per tornare indietro) realizzando una breve guida sull'argomento.

Nasce così la "Guida allo Sviluppo di Componenti per Joomla 1.5". L'idea era di fare un riassunto di quanto scritto finora sul blog relativamente a questo argomento, ma mi sono fatto prendere la mano e, rispetto agli articoli che potete trovare qui, alcuni aspetti sono stati trattati in modo molto più approfondito.

Se questo sia un bene o no è difficile dirlo. Certo sarebbe stato più facile creare uno 'scheletro' di componente e dire: "Un componente per Joomla 1.5 è fatto così: partite da questa struttura e personalizzate il tutto secondo le vostre esigenze". Però penso che spesso torni utile sapere non solo come si fa una cosa, ma anche perché si fa in un certo modo.

Non aspettatevi a questo punto un trattato sulla materia, l'impostazione della guida resta molto pratica: ho creato un componente di esempio cercando di spiegare passo passo la struttura dei diversi file che ne fanno parte.

Il componente di esempio è diverso da quello utilizzato negli articoli, per cui chi ha seguito l'argomento sul blog può leggere comunque la guida e viceversa.

La guida in formato pdf più il pacchetto di installazione del componente di esempio sono disponibili sul sito per il download.

Scarica la guida

Spero vi sia utile. Lasciate un commento se ci sono dubbi, domande o se trovate qualche inesattezza.

venerdì 8 febbraio 2008

Joomla 1.5: Altre Funzioni per il Backend del Componente MyForm

Ho trascurato un po' lo sviluppo del componente di esempio per Joomla 1.5 (MyForm). Preferisco scrivere delle cose di cui mi occupo al momento e capita di affaccendarsi in diverse faccende.

Comunque con l'uscita di Joomla 1.5 stabile noto un crescente interesse riguardo allo sviluppo di componenti per la nuova versione per cui credo sia il caso di riprendere il filo ed aggiungere qualche (ultima) funzionalità al backend del componente.

Allo stadio attuale dello sviluppo, dal backend è possibile solamente consultare i dati inseriti dagli utenti tramite il modulo pubblicato nel frontend. Aggiungeremo le funzioni per modificare e cancellare questi dati con la possibilità di cancellazione di record multipli selezionati mediante caselle di selezione (checkboxes).

Come al solito il risultato finale è disponibile sul sito (myform5.zip).

Gestione della selezione dei record

La selezione multipla di record da un elenco è una funzionalità standard che viene implementata nei componenti con apposite funzioni del framework di Joomla.

Il file da modificare è default.php in .../administrator/components/com_myform/views/myform/tmpl

Aggiungiamo la casella per la selezione di tutti i record nell'intestazione dell'elenco

<th width="20">
 <input type="checkbox" name="toggle" value=""
   onclick="checkAll(' . count($this->items) . ');" />
</th>

Portiamo a 6 le colonne dell'elenco per fare spazio alla casella di selezione a fianco di ogni record.

$tr = '<tr>' . str_repeat('<td>%s</td>', 6) . '</tr>';

Il ciclo che genera le righe dell'elenco diventa

$i = 0;
foreach($this->items as $item) {
 $checked = JHTML::_('grid.id', $i, $item->id);
 $html .= sprintf($tr, $checked, $item->nome, $item->cognome,
 $item->telefono, $item->indirizzo, $item->note);
 $i++;
}

Da notare che il codice HTML per la casella di selezione è generato da una funzione del framework ( JHTML::_('grid.id', $i, $item->id) ) a cui si devono passare come argomenti il numero della riga dell'elenco ( $i ) e il valore del campo ID del record nel database ( $item->id ).

Infine va inserito al form adminForm un campo nascosto

<input type="hidden" name="boxchecked" value="0" />

che serve al passaggio dei valori dei campi selezionati.

Basta ricordarsi questi pochi passaggi e il resto sarà fatto da Joomla in modo standard. Maggiori dettagli (almeno a me, almeno per ora) non interessano.

Aggiunta pulsanti Cancella e Modifica

Aggiungiamo i pulsanti standard per la gestione delle operazioni di cancellazione e modifica.

Il file da modificare è view.html.php in .../administrator/components/com_myform/views/myform

JToolBarHelper::title('MyForm', 'generic.png');
JToolBarHelper::deleteList();
JToolBarHelper::editListX();

Anche in questo caso si utilizzano funzioni del framework. Non abbiamo passato alcun argomento a deleteList() e editListX() per cui tutte le impostazioni saranno quelle predefinite inclusi i valori dei task che vengono generati dalla pressione dei pulsanti, remove per la cancellazione, edit per la modifica.

Ricordo che perché il tutto possa funzionare il form adminForm che abbiamo visto sopra deve contenere un campo nascosto

<input type="hidden" name="task" value="" />

che serve alla trasmissione del task.

Controller di backend

Si è detto che ad ogni pulsante della barra degli strumenti corrisponde un task. Implementiamo nel Controller di backend i metodi per processare questi task.

File controller.php in .../administrator/components/com_myform/

function edit() {
 $this->addModelPath(JPATH_COMPONENT_SITE.DS.'models');
 $model = $this->getModel('myform');

Per la funzione di modifica abbiamo bisogno di visualizzare il modulo di immissione dati la cui struttura si trova nell'oggetto Model del frontend. Però stiamo scrivendo il backend del componente per cui con addModelPath indichiamo al Controller di creare l'oggetto Model utilizzando la classe definita nel frontend del componente (JPATH_COMPONENT_SITE).

 $array = JRequest::getVar('cid',  0, '', 'array');
 $id = (int)$array[0];

L'array contiene i valori del campo ID nel database di tutti i record selezionati nell'elenco. Sulla fiducia o, se non vi fidate, controllate il sorgente HTML della pagina che visualizza l'elenco. In una operazione di modifica anche in caso di selezione multipla ci interessa solo l'ID del primo record.

 $view =& $this->getView('form', 'html');
 $view->setModel($model);

Viene creato un nuovo oggetto View form. La classe relativa deve essere ancora creata, lo faremo tra poco.

 if($data = $model->getData($id)) {
   $view->assignRef('data', $data);
 }
 $view->display();
} // fine function edit()

I dati corrispondenti al record selezionato vengono letti dal database e passati all'oggetto View per la visualizzazione. Anche il metodo getData() di Model sarà creato in seguito.

Implementiamo il metodo per il task remove.

function remove() {
 $model = $this->getModel('myform');
 if(!$model->delete()) {
   $msg = JText::_('Errore: Uno o più record
   non sono stati cancellati');
 } else {
   $msg = JText::_('Record cancellato/i');
 }
 $this->setRedirect('index.php?option=com_myform', $msg);
}

Niente di particolare. Tutto il lavoro significativo viene fatto dal metodo delete() dell'oggetto Model (di backend) che dobbiamo ancora scrivere.

View per il modulo modifica dati nel backend

La classe utilizzata per crare l'oggetto View che si occupa della visualizzazione del modulo per la modifica dei dati nel backend è tutta da scrivere.

Creiamo un nuovo file view.html.php in .../administrator/components/com_myform/views/form
defined('_JEXEC') or die('Restricted access');

jimport('joomla.application.component.view');

class MyFormViewForm extends JView {
  
 function display($tpl = null) {
   JToolBarHelper::title(JText::_('MyForm Edit'), 'generic.png');
   JToolBarHelper::save('submit');
   JToolBarHelper::cancel();

Si crea un pulsante Salva, che genera un task submit, e un pulsante Annulla che genera il task predefinito cancel.

   
   $model =& $this->getModel('myform');
   $form = $model->getForm();
   //nel backend nome e id sono standard
   $form['name'] = 'adminForm';
   $form['id'] = 'adminForm';
   $this->assignRef('form', $form);
   parent::display($tpl);
 } // fine function display()
} //fine class MyFormViewForm

La definizione del form viene chiesta all'oggetto Model e passata al template per la visualizzazione. Tutte cose già viste negli articoli precedenti.

Anche il template associato alla View va creato da zero.

File default.php in .../administrator/components/com_myform/views/form/tmpl

defined('_JEXEC') or die('Restricted access');
require JPATH_COMPONENT_ADMINISTRATOR.DS.'helpers'
. DS . 'myform.php';
MyFormHelper::displayForm($this->form, $this->data);

Il codice per la visualizzazione del modulo lo abbiamo già scritto per il frontend del componente, sarebbe assurdo duplicarlo. Scriviamo quindi una classe MyFormHelper con un metodo displayForm() che sarà utilizzato nel frontend e nel backend.

La classe MyFormHelper è definita nel file myform.php in .../administrator/components/com_myform/helpers

Non commento il codice perché si tratta di cose già viste, potete controllare i sorgenti allegati.

Il file default.php del frontend in ...components/com_myform/views/myform/tmpl

è stato modificato per utilizzare lo stesso metodo displayForm() e anche in questo caso chi è interessato ai dettagli può esaminare il sorgente.

Controller di backend: task submit e cancel

Bisogna tornare al Controller di backend per l'implementazione dei metodi submit() e cancel() che processano i task generati dai pulsanti Salva e Annulla nella schermata di modifica record.

File controller.php in .../administrator/components/com_myform/

function submit() {
 $data = JRequest::getVar('myform', array(), 'post', 'array');
 $this->addModelPath(JPATH_COMPONENT_SITE.DS.'models');
 $model = $this->getModel('myform');
 if($model->store($data)) {
   $msg = JText::_('Record Salvato');
   $this->setRedirect('index.php?option=com_myform', $msg);
 } else {
   $view =& $this->getView('form', 'html');
   $view->setModel($model);
   $view->assignRef('data', $data);
   $view->display();
 }
}

Per salvare le modifiche si chiama il metodo store() dell'oggetto Model del frontend che già esiste perché è utilizzato per il salvataggio dei dati inseriti dai visitatori. Notate che solo in caso di successo si fa un setRedirect per reindirizzare alla pagina principale (quella con l'elenco dei record), in caso di errore i dati ricevuti da $_POST vengono restituiti alla View in modo che il modulo sia visualizzato di nuovo e l'utente possa fare le necessarie correzioni senza perdere i dati già inseriti.

Il codice è praticamente identico a quello già scritto negli articoli precedenti per il frontend.

Manca il metodo per il task cancel.

function cancel() {
 $msg = JText::_('Operazione annullata');
 $this->setRedirect('index.php?option=com_myform', $msg);
}

Più facile di così!

Model di backend

La cancellazione dei dati avviene solo dal backend per cui la relativa funzione va inserita nella classe Model del backend.

File myform.php in .../administrator/components/com_myform/models

function delete() {
 $cids = JRequest::getVar('cid', array(0), 'post', 'array');
 $row =& $this->getTable();

 foreach($cids as $cid) {
   if (!$row->delete($cid)) {
     $this->setError($row->getErrorMsg());
     return false;
   }
 }
 return true;
}

Ricordo che questo metodo viene invocato dal metodo remove() del Controller di backend.

$cids contiene un array dei valori del campo ID di tutti i record selezionati nell'elenco. Il resto è banale (o forse no?): scansione dell'array e uso del metodo delete() dell'oggetto Table (di cui già si è parlato negli articoli precedenti) per cancellare i record.

Come al solito niente istruzioni SQL nel nostro codice, tutto il lavoro lo fa il framework.

Model di frontend

Resta da implementare il metodo getData() (richiamato da edit() del Controller di backend) nella classe Model del frontend.

File myform.php in .../components/com_myform/models

function getData($id) {
 $sql = 'SELECT * FROM #__myform WHERE id = '. $id;
 $this->_db->setQuery($sql);
 return $this->_db->loadAssoc();
}

Si estrae dal database il record corrispondente ad un determinato ID e si ritorna come array associativo ( loadAssoc() ).

Per concludere

Abbiamo finito. Il sorgente aggiornato è scaricabile dal sito (myform5.zip).

Sviluppare ulteriormente MyForm non avrebbe molto senso. Si tratta di un componente di esempio anche se nato con l'ambizione di essere (anche solo appena un po') più 'reale' del tradizionale componente dimostrativo.

Lo sviluppo di componenti (nonché di moduli e plugin) per Joomla è comunque un argomento di cui si avrà modo di parlare ancora.

Se c'è qualcosa che non funziona, qualche dettaglio che non capite o semplicemente se vi va di farlo lasciate un commento.

martedì 5 febbraio 2008

Joomla 1.5: SEF Integrato e Duplicazione Contenuti

Finalmente è uscita la versione stabile di Joomla 1.5. Di sicuro questo già lo sanno tutti coloro che sono in qualche modo interessati a Joomla perché la notizia è stata ampiamente pubblicizzata, come d'altra parte è giusto visto l'interesse che ruota intorno a questo cms.

La mia intenzione non è però quella di dare un annuncio in ritardo, ma piuttosto iniziare a fare qualche riflessione sulla nuova versione.

Leggendo i commenti e le prime impressioni in giro per i vari forum dedicati all'argomento, mi pare di capire che una delle novità che è stata accolta più favorevolmente sia il supporto integrato per le url pulite (senza parametri) ottimizzate per i motori di ricerca (clean urls, SEF urls chiamiamole un po' come si vuole).

Parliamone iniziando da un esempio concreto. Supponiamo di voler creare un sito strutturato in sezioni e categorie nel modo mostrato dalla figura

Per prima cosa creiamo le sezioni e le categorie da Contenuti -> Gestione Sezioni e Contenuti -> Gestione Categorie nell'area di amministrazione di Joomla.

Faccio notare che sia le sezioni che le categorie oltre al Titolo hanno un proprio campo Alias. Lo possiamo lasciare vuoto, ma è bene sapere che esiste, si vedrà alla fine perché.

Poi pensiamo ai menu. Proprio per mantenere l'esempio il più semplice possibile creeremo un menu standard (Articoli) a due livelli: le voci di menu del primo livello saranno del tipo Aspetto sezione, quelle del secondo livello saranno del tipo Aspetto categoria.

Creiamo ovviamente una voce di menu per ogni sezione e ogni categoria. Prima si creano le voci menu Aspetto sezione, lasciando il campo Elemento impostato su Principale.

Poi si creano le voci di menu Aspetto categoria, selezionando per il campo Elemento il valore corrispondente alla rispettiva sezione.

Nel campo Titolo possiamo mettere il nome della sezione o categoria e il campo Alias (notare che esiste un campo Alias anche per la voce del menu) possiamo lasciarlo vuoto.

La struttura del menu Articoli deve apparire come in figura

Il menu può essere pubblicato su tutte le pagine in posizione left. La visualizzazione di un menu strutturato in questo modo è gestita automaticamente da Joomla: quando si clicca su una voce relativa ad una sezione il menu si espande a mostrare i link a tutte le categorie sottostanti.

L'effetto nel template Beez è questo

Niente di nuovo. Anche con la vecchia versione le cose funzionavano così. Proviamo però a vedere cosa succede quando si attivano le SEF url.

Andiamo a Sito -> Configurazione e nel box Configurazione SEO impostiamo a tutte e tre le opzioni Friendly URL per i motori di ricerca, Utilizza mod_rewrite, Aggiungi il suffisso agli URL.

Se non lo si è già fatto occorre rinominare il file htaccess.txt in .htaccess nella cartella dove abbiamo installato Joomla.

Partendo dalla prima pagina del nostro sito di esempio navighiamo uno dei link del menu Articoli che abbiamo creato. Poiché tutti i link di primo livello sono di tipo Aspetto sezione, arriviamo ad una pagina contenente la lista di tutte le categorie contenute nella sezione. Controllando la barra degli indirizzi del nostro browser vedremo una url del tipo

.../alias_voce_menu_aspetto_sezione.html

Fino a qui tutto è a posto, la url è pulita, senza parametri. Va solo notato che per la creazione della url viene utilizzato il campo Alias della voce del menu non quello della sezione. Nel nostro caso abbiamo utilizzato il nome della sezione come titolo del menu e quindi i due alias sono identici, in quanto quando il campo Alias è lasciato vuoto viene automaticamente valorizzato utilizzando il campo Titolo corrispondente.

Se la spiegazione non è chiara (il che, devo ammetterlo, è piuttosto probabile) provate a costruire un sito di prova con una struttura simile al nostro sito di esempio e fate qualche esperimento cambiando i valori dei campi Alias delle voci di menu e delle sezioni e categorie e verificando come cambiano le url.

Ma il punto più importante non è questo.

Siamo arrivati ad una pagina che mostra l'elenco delle categorie contenute in una sezione. Diamo un'occhiata ai link su questa pagina: nel corpo della pagina abbiamo i link che conducono alle liste degli articoli di ogni categoria e strutturati in questo modo

.../alias_voce_aspetto_sezione/x-alias_categoria.html

Dove x è l'ID della categoria.

Il menu laterale si è espanso e mostra le voci di tipo Aspetto categoria con link strutturati in queso modo

.../alias_voce_aspetto_sezione/alias_voce_aspetto_categoria.html

Ora è facile capire che i link nel menu e quelli nel corpo della pagina conducono alle stesse pagine (l'elenco degli articoli della categoria). Il fatto che in una situazione come questa Joomla utilizzi il campo Alias della voce del menu per i link nel menu e il campo Alias della categoria per i link nella pagina, porta ad un problema di duplicazione di contenuto: una stessa pagina è raggiungibile, e quindi indicizzabile dai motori di ricerca, sotto due url diverse.

Non voglio affrontare l'argomento se la duplicazione di contenuto possa portare a vere e proprie penalizzazioni di un sito, oppure i motori di ricerca (Google in particolare) si limitino a filtrare ed escludere dall'indice i doppioni senza altre conseguenze. Da quello che leggo in giro le opinioni sul punto non sono sempre concordi.

In ogni caso, motori di ricerca a parte, questa situazione crea una struttura del sito poco lineare ed ordinata.

Quello che abbiamo visto è solo un esempio, ma ci sono altre situazioni in cui si genera contenuto duplicato: per esempio se si inserisce una voce Aspetto articolo in un menu, il link all'articolo avrà una struttura diversa da quello presente sulla pagina con l'elenco degli articoli della categoria. Quindi anche in questo caso avremo più url per uno stesso contenuto.

Va detto per precisione che nelle stesse situazioni anche le url standard (con i parametri) generano contenuto duplicato. Ne ho parlato in relazione alle url SEF solo perché, essendo queste più semplici, la cosa è resa molto più evidente e comprensibile.

Questa è la situazione. Soluzioni personalmente non ne ho trovate, almeno non per Joomla in configurazione base. Resta da vedere se il problema sarà risolto da componenti SEF di terze parti. Qualcosa comincia a vedersi anche per Joomla 1.5, ma ne parlerò dopo aver fatto qualche test.